fix(adminui): lane D-b review r0 fixes (I1, M1, M2, M5-M9, N1-N3, N5, H3)
I1: /hosts eviction keyed off the AUTHORED DriverInstances, so a driver deleted in /raw but not yet deployed - still running, still publishing - vanished every tick. The stores' sweep is now EvictUnconfiguredStale(set, olderThanUtc): an entry goes only when unconfigured AND its PublishedUtc is older than 60 s. Tests cover unconfigured+fresh kept (positive control), unconfigured+stale evicted, configured+stale kept, and the deploy hand-off. M1: Test Connect falls back to the driver's documented ProbeTimeoutSeconds default (Galaxy 30, OpcUaClient 15, ...) when the key is absent. M2: the budget never undercuts the config's root timeoutMs (+1 s). M5: RawBrowseModal compares the open generation captured before the await, so a close-then-reopen mid-open closes the stale session. M6: /alarms-historian keeps a 30 s re-poll on 'not registered' (a driver node may still be starting) instead of stopping for good. M7: /scripts source fetch failure shows in the dialog, not the error boundary. M8: the export modal maps only its preview rows; the endpoint writes via Results.Text (no second byte[] copy). M9: /hosts config queries are ordered, so SequenceEqual change detection holds. N1 tooltip, N2 CRLF-safe regex, N3 throttled Warning for subscriber faults, N5 equipment-import help text now describes RFC 4180 quoting. H3: MonacoEditor documents that themes are page-global. Refs #745 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -89,7 +89,11 @@ else
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="CloseSource"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@if (src is null || (_sourceLoaded && _sourceCode is null))
|
||||
@if (_sourceError is not null)
|
||||
{
|
||||
<div class="panel notice notice-alert mb-0">@_sourceError</div>
|
||||
}
|
||||
else if (src is null || (_sourceLoaded && _sourceCode is null))
|
||||
{
|
||||
<p class="text-muted mb-0">This script is no longer loaded.</p>
|
||||
}
|
||||
@@ -123,6 +127,7 @@ else
|
||||
// operator opened another row, or closed the dialog, while the first one was in flight).
|
||||
private string? _sourceCode;
|
||||
private bool _sourceLoaded;
|
||||
private string? _sourceError;
|
||||
private int _sourceGeneration;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@@ -147,8 +152,22 @@ else
|
||||
_sourceCode = null;
|
||||
_sourceLoaded = false;
|
||||
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
var source = await ScriptListQueries.LoadSourceAsync(db, scriptId);
|
||||
_sourceError = null;
|
||||
string? source;
|
||||
try
|
||||
{
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
source = await ScriptListQueries.LoadSourceAsync(db, scriptId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// A ConfigDb hiccup must not escape the click handler into the page's error boundary (review r0 M7).
|
||||
if (generation != _sourceGeneration) return;
|
||||
_sourceError = $"The script source could not be loaded: {ex.Message}";
|
||||
_sourceLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (generation != _sourceGeneration) return;
|
||||
_sourceCode = source;
|
||||
_sourceLoaded = true;
|
||||
@@ -160,5 +179,6 @@ else
|
||||
_sourceScriptId = null;
|
||||
_sourceCode = null;
|
||||
_sourceLoaded = false;
|
||||
_sourceError = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user