fix(adminui): stale-open guards, validation summaries, key-delete confirm, error boundary (#604)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 06:55:23 -04:00
parent 3baa332d6b
commit d3bca7afd4
12 changed files with 504 additions and 13 deletions
@@ -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);
}
}