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:
Joseph Doherty
2026-10-22 18:21:46 -04:00
parent 01f7e3d62e
commit 0f1f8ad8fa
26 changed files with 411 additions and 102 deletions
@@ -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;
}
}