Merge #604: AdminUI stale-open guards on 5 modals, ValidationSummary, API-key delete confirm, ErrorBoundary

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 06:55:40 -04:00
12 changed files with 504 additions and 13 deletions
@@ -123,20 +123,27 @@
private string? _saveError;
private bool _openHandled;
// Bumped on every open and close; LoadAsync re-checks it after each await so a superseded open can't
// install one target's fields under another target's displayed modal (RawBrowseModal idiom).
private int _openGeneration;
private bool IsStale(int generation) => generation != _openGeneration || !Visible;
protected override async Task OnParametersSetAsync()
{
if (Visible && !_openHandled)
{
_openHandled = true;
await LoadAsync();
await LoadAsync(++_openGeneration);
}
else if (!Visible)
{
_openHandled = false;
_openGeneration++;
}
}
private async Task LoadAsync()
private async Task LoadAsync(int generation)
{
_busy = false; _loadError = null; _saveError = null;
_isNew = string.IsNullOrEmpty(DeviceId);
@@ -153,6 +160,7 @@
else
{
var dto = await Svc.LoadDeviceForEditAsync(DeviceId!);
if (IsStale(generation)) { return; }
if (dto is null) { _loadError = $"Device '{DeviceId}' was not found."; return; }
_resolvedDriverInstanceId = dto.DriverInstanceId;
_driverType = dto.DriverType;
@@ -166,6 +174,7 @@
if (!string.IsNullOrEmpty(_resolvedDriverInstanceId))
{
var drv = await Svc.LoadDriverForEditAsync(_resolvedDriverInstanceId);
if (IsStale(generation)) { return; }
_parentDriverConfig = drv?.DriverConfig ?? "{}";
}
}
@@ -217,6 +226,7 @@
{
Visible = value;
_openHandled = value;
_openGeneration++;
await VisibleChanged.InvokeAsync(value);
}
}
@@ -129,20 +129,27 @@
private string? _saveError;
private bool _openHandled;
// Bumped on every open and close; LoadAsync re-checks it after each await so a superseded open can't
// install one target's fields under another target's displayed modal (RawBrowseModal idiom).
private int _openGeneration;
private bool IsStale(int generation) => generation != _openGeneration || !Visible;
protected override async Task OnParametersSetAsync()
{
if (Visible && !_openHandled)
{
_openHandled = true;
await LoadAsync();
await LoadAsync(++_openGeneration);
}
else if (!Visible)
{
_openHandled = false;
_openGeneration++;
}
}
private async Task LoadAsync()
private async Task LoadAsync(int generation)
{
_busy = false; _loadError = null; _saveError = null;
_isNew = string.IsNullOrEmpty(DriverInstanceId);
@@ -158,6 +165,7 @@
else
{
var dto = await Svc.LoadDriverForEditAsync(DriverInstanceId!);
if (IsStale(generation)) { return; }
if (dto is null) { _loadError = $"Driver '{DriverInstanceId}' was not found."; return; }
_driverType = dto.DriverType;
_name = dto.Name;
@@ -206,6 +214,7 @@
{
Visible = value;
_openHandled = value;
_openGeneration++;
await VisibleChanged.InvokeAsync(value);
}
}