fix(ui): enforce idempotent AI data fetching and JSRuntime guards
This commit is contained in:
@@ -51,9 +51,13 @@
|
|||||||
private string _lastFetchedBlockId = string.Empty;
|
private string _lastFetchedBlockId = string.Empty;
|
||||||
private KnowledgePacket? _packet;
|
private KnowledgePacket? _packet;
|
||||||
private CancellationTokenSource? _streamCts;
|
private CancellationTokenSource? _streamCts;
|
||||||
|
private bool _isInteractive;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
|
if (!_isInteractive)
|
||||||
|
return;
|
||||||
|
|
||||||
// Only re-fetch when the block context actually changes
|
// Only re-fetch when the block context actually changes
|
||||||
if (string.IsNullOrEmpty(ContextBlockId) || ContextBlockId == _lastFetchedBlockId)
|
if (string.IsNullOrEmpty(ContextBlockId) || ContextBlockId == _lastFetchedBlockId)
|
||||||
return;
|
return;
|
||||||
@@ -62,6 +66,19 @@
|
|||||||
await FetchAndStreamAsync();
|
await FetchAndStreamAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
_isInteractive = true;
|
||||||
|
if (!string.IsNullOrEmpty(ContextBlockId))
|
||||||
|
{
|
||||||
|
_lastFetchedBlockId = ContextBlockId;
|
||||||
|
await FetchAndStreamAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task FetchAndStreamAsync()
|
private async Task FetchAndStreamAsync()
|
||||||
{
|
{
|
||||||
// Cancel any in-progress stream
|
// Cancel any in-progress stream
|
||||||
|
|||||||
@@ -26,15 +26,40 @@
|
|||||||
|
|
||||||
private GroundednessResult? _result;
|
private GroundednessResult? _result;
|
||||||
private bool _isChecking;
|
private bool _isChecking;
|
||||||
|
private bool _isInteractive;
|
||||||
|
private string _previousAnswer = string.Empty;
|
||||||
|
private string _previousContext = string.Empty;
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
if (Answer != _previousAnswer || Context != _previousContext)
|
||||||
|
{
|
||||||
|
_result = null;
|
||||||
|
_previousAnswer = Answer;
|
||||||
|
_previousContext = Context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(Answer) && !string.IsNullOrEmpty(Context) && _result == null)
|
if (_isInteractive && !string.IsNullOrEmpty(Answer) && !string.IsNullOrEmpty(Context) && _result == null)
|
||||||
{
|
{
|
||||||
await RunCheck();
|
await RunCheck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
_isInteractive = true;
|
||||||
|
if (!string.IsNullOrEmpty(Answer) && !string.IsNullOrEmpty(Context) && _result == null)
|
||||||
|
{
|
||||||
|
await RunCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task RunCheck()
|
private async Task RunCheck()
|
||||||
{
|
{
|
||||||
_isChecking = true;
|
_isChecking = true;
|
||||||
|
|||||||
@@ -27,11 +27,10 @@
|
|||||||
private IJSObjectReference? _keydownHandler;
|
private IJSObjectReference? _keydownHandler;
|
||||||
private DotNetObjectReference<Home>? _dotNetRef;
|
private DotNetObjectReference<Home>? _dotNetRef;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
QuizState.OnQuizRequested += HandleQuizRequestedAsync;
|
QuizState.OnQuizRequested += HandleQuizRequestedAsync;
|
||||||
FocusMode.OnFocusModeChanged += HandleUpdate;
|
FocusMode.OnFocusModeChanged += HandleUpdate;
|
||||||
await FocusMode.InitializeAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
@@ -65,11 +64,13 @@
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
|
await FocusMode.InitializeAsync();
|
||||||
try {
|
try {
|
||||||
_interopModule = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/NexusReader.UI.Shared/js/focusInterop.js");
|
_interopModule = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/NexusReader.UI.Shared/js/focusInterop.js");
|
||||||
_dotNetRef = DotNetObjectReference.Create(this);
|
_dotNetRef = DotNetObjectReference.Create(this);
|
||||||
_keydownHandler = await _interopModule.InvokeAsync<IJSObjectReference>("attachKeyboardListener", _dotNetRef);
|
_keydownHandler = await _interopModule.InvokeAsync<IJSObjectReference>("attachKeyboardListener", _dotNetRef);
|
||||||
} catch { } /* ignored dynamically */
|
} catch { } /* ignored dynamically */
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user