merge: AdminUI sweep — Shared/Drivers+Acls (DriverFormShell lever, CollectionEditor, tint swaps)
v2-ci / build (push) Successful in 4m56s
v2-ci / unit-tests (push) Failing after 15m23s

This commit is contained in:
Joseph Doherty
2026-08-10 16:33:24 -04:00
15 changed files with 125 additions and 103 deletions
@@ -92,9 +92,11 @@
}
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-secondary" @onclick="CancelAsync">Cancel</button>
<button type="button" class="btn btn-primary" @onclick="ConfirmAsync"
disabled="@(_selected is null)">Use this scope</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary" @onclick="CancelAsync">Cancel</button>
<button type="button" class="btn btn-primary" @onclick="ConfirmAsync"
disabled="@(_selected is null)">Use this scope</button>
</div>
</div>
</div>
</div>
@@ -36,14 +36,14 @@
<div @key="node.Key" class="d-flex align-items-center gap-1 py-1" style="@indent">
@if (hasExpander)
{
<button type="button" class="btn btn-sm btn-link p-0" style="width:18px"
<button type="button" class="btn btn-sm btn-link p-0 tree-twist"
@onclick="@(() => ToggleAsync(node))">
@(node.Expanded ? "▼" : "▶")
</button>
}
else
{
<span style="width:18px"></span>
<span class="tree-twist"></span>
}
@if (node.Selectable)
@@ -26,8 +26,10 @@
<tr @key="Items[idx]">
@RowTemplate(Items[idx])
<td class="text-end" style="white-space:nowrap">
<button type="button" class="btn btn-sm btn-link p-0 me-2" @onclick="() => Edit(idx)">Edit</button>
<button type="button" class="btn btn-sm btn-link p-0 text-danger" @onclick="() => Delete(idx)">Delete</button>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-secondary" @onclick="() => Edit(idx)">Edit</button>
<button type="button" class="btn btn-outline-danger" @onclick="() => Delete(idx)">Delete</button>
</div>
</td>
</tr>
}
@@ -55,8 +57,10 @@
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" @onclick="Cancel">Cancel</button>
<button type="button" class="btn btn-primary" @onclick="Commit">Save</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary" @onclick="Cancel">Cancel</button>
<button type="button" class="btn btn-primary" @onclick="Commit">Save</button>
</div>
</div>
</div>
</div>
@@ -20,7 +20,7 @@
@if (_model.LegacyConnectionKeys.Count > 0)
{
<section class="panel rise mt-3" style="animation-delay:.06s;border-color:var(--alert)">
<section class="panel rise notice-alert mt-3" style="animation-delay:.06s">
<div class="panel-head">Legacy connection keys on this device</div>
<div style="padding:1rem">
<p class="mb-2 small">
@@ -21,7 +21,7 @@
<div class="modal-body">
@if (_loadError is not null)
{
<div class="panel notice mb-3" style="border-color:var(--alert)">@_loadError</div>
<div class="panel notice notice-alert mb-3">@_loadError</div>
}
else
{
@@ -64,19 +64,21 @@
@if (_saveError is not null)
{
<div class="panel notice mt-3" style="border-color:var(--alert)">@_saveError</div>
<div class="panel notice notice-alert mt-3">@_saveError</div>
}
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" @onclick="CloseAsync" disabled="@_busy">Cancel</button>
@if (_loadError is null)
{
<button type="button" class="btn btn-primary" @onclick="SaveAsync" disabled="@_busy">
@if (_busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
@(_isNew ? "Create device" : "Save changes")
</button>
}
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary" @onclick="CloseAsync" disabled="@_busy">Cancel</button>
@if (_loadError is null)
{
<button type="button" class="btn btn-primary" @onclick="SaveAsync" disabled="@_busy">
@if (_busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
@(_isNew ? "Create device" : "Save changes")
</button>
}
</div>
</div>
</div>
</div>
@@ -132,14 +132,14 @@
<div class="d-flex align-items-center gap-1 py-1 @selectedCls" style="@indent">
@if (item.Node.Kind == BrowseNodeKind.Folder && item.Node.HasChildrenHint)
{
<button type="button" class="btn btn-sm btn-link p-0"
@onclick="@(() => ToggleAsync(item))" style="width:18px">
<button type="button" class="btn btn-sm btn-link p-0 tree-twist"
@onclick="@(() => ToggleAsync(item))">
@(item.Expanded ? "▼" : "▶")
</button>
}
else
{
<span style="width:18px"></span>
<span class="tree-twist"></span>
}
@* BUTTONS, NOT <a href="#">. This is a Blazor Web App: blazor.web.js installs a
document-level click interceptor for enhanced navigation, and it resolves a bare "#"
@@ -19,7 +19,7 @@
<div class="modal-body">
@if (_loadError is not null)
{
<div class="panel notice mb-3" style="border-color:var(--alert)">@_loadError</div>
<div class="panel notice notice-alert mb-3">@_loadError</div>
}
else
{
@@ -65,19 +65,21 @@
@if (_saveError is not null)
{
<div class="panel notice mt-3" style="border-color:var(--alert)">@_saveError</div>
<div class="panel notice notice-alert mt-3">@_saveError</div>
}
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" @onclick="CloseAsync" disabled="@_busy">Cancel</button>
@if (_loadError is null)
{
<button type="button" class="btn btn-primary" @onclick="SaveAsync" disabled="@_busy">
@if (_busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
@(_isNew ? "Create driver" : "Save changes")
</button>
}
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary" @onclick="CloseAsync" disabled="@_busy">Cancel</button>
@if (_loadError is null)
{
<button type="button" class="btn btn-primary" @onclick="SaveAsync" disabled="@_busy">
@if (_busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
@(_isNew ? "Create driver" : "Save changes")
</button>
}
</div>
</div>
</div>
</div>
@@ -6,15 +6,17 @@
@if (!string.IsNullOrWhiteSpace(Error))
{
<div class="panel notice mt-3" style="border-color:var(--alert)">@Error</div>
<div class="panel notice notice-alert mt-3">@Error</div>
}
<div class="mt-3 d-flex gap-2">
<button type="submit" class="btn btn-primary" disabled="@Busy">
@if (Busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
@(IsNew ? "Create" : "Save changes")
</button>
<a href="@CancelHref" class="btn btn-outline-secondary">Cancel</a>
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary" disabled="@Busy">
@if (Busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
@(IsNew ? "Create" : "Save changes")
</button>
<a href="@CancelHref" class="btn btn-outline-secondary">Cancel</a>
</div>
@if (OnDelete.HasValue)
{
<button type="button" class="btn btn-outline-danger ms-auto" @onclick="OnDelete.Value" disabled="@Busy">
@@ -130,37 +130,39 @@
@if (_canOperate && Enabled)
{
<div class="d-flex gap-2 align-items-center mt-3">
<button type="button"
class="btn btn-sm btn-outline-secondary"
disabled="@_busyReconnect"
@onclick="ReconnectAsync"
title="Re-establish driver transport without restarting the actor">
@if (_busyReconnect)
{
<span class="spinner-border spinner-border-sm me-1"></span>
<span>Reconnecting&hellip;</span>
}
else
{
<span>Reconnect</span>
}
</button>
<div class="btn-group btn-group-sm" role="group">
<button type="button"
class="btn btn-outline-secondary"
disabled="@_busyReconnect"
@onclick="ReconnectAsync"
title="Re-establish driver transport without restarting the actor">
@if (_busyReconnect)
{
<span class="spinner-border spinner-border-sm me-1"></span>
<span>Reconnecting&hellip;</span>
}
else
{
<span>Reconnect</span>
}
</button>
<button type="button"
class="btn btn-sm btn-outline-danger"
disabled="@_busyRestart"
@onclick="() => _showRestartConfirm = true"
title="Stop and respawn the driver actor — briefly interrupts active subscriptions">
@if (_busyRestart)
{
<span class="spinner-border spinner-border-sm me-1"></span>
<span>Restarting&hellip;</span>
}
else
{
<span>Restart</span>
}
</button>
<button type="button"
class="btn btn-outline-danger"
disabled="@_busyRestart"
@onclick="() => _showRestartConfirm = true"
title="Stop and respawn the driver actor — briefly interrupts active subscriptions">
@if (_busyRestart)
{
<span class="spinner-border spinner-border-sm me-1"></span>
<span>Restarting&hellip;</span>
}
else
{
<span>Restart</span>
}
</button>
</div>
@if (_opResultMessage is not null)
{
@@ -176,9 +178,9 @@
Restart driver <code>@DriverInstanceId</code>?<br />
<span style="color:var(--ink-soft)">This briefly interrupts active subscriptions and clears in-memory state.</span>
</p>
<div class="d-flex gap-2">
<button type="button" class="btn btn-sm btn-danger" @onclick="RestartConfirmedAsync">Confirm restart</button>
<button type="button" class="btn btn-sm btn-outline-secondary" @onclick="() => _showRestartConfirm = false">Cancel</button>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-danger" @onclick="RestartConfirmedAsync">Confirm restart</button>
<button type="button" class="btn btn-outline-secondary" @onclick="() => _showRestartConfirm = false">Cancel</button>
</div>
</div>
}
@@ -20,11 +20,13 @@
{
<code class="me-auto mono">@CurrentAddress</code>
}
<button type="button" class="btn btn-outline-secondary" @onclick="OnCloseAsync">Close</button>
<button type="button" class="btn btn-primary" disabled="@string.IsNullOrEmpty(CurrentAddress)"
@onclick="OnUseAsync">
Use this address
</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary" @onclick="OnCloseAsync">Close</button>
<button type="button" class="btn btn-primary" disabled="@string.IsNullOrEmpty(CurrentAddress)"
@onclick="OnUseAsync">
Use this address
</button>
</div>
</div>
</div>
</div>
@@ -141,7 +141,7 @@
@if (_form.Validate() is { } error)
{
<div class="panel notice mt-3" style="border-color:var(--alert)">@error</div>
<div class="panel notice notice-alert mt-3">@error</div>
}
<DriverResilienceSection ResilienceConfig="@ResilienceConfig" ResilienceConfigChanged="OnResilienceChanged" />
@@ -289,7 +289,7 @@
@if (_validationError is not null)
{
<div class="panel notice mt-3" style="border-color:var(--alert)">@_validationError</div>
<div class="panel notice notice-alert mt-3">@_validationError</div>
}
<DriverResilienceSection ResilienceConfig="@ResilienceConfig" ResilienceConfigChanged="OnResilienceChanged" />
@@ -46,14 +46,16 @@
else
{
<span class="chip chip-ok">Browser open</span>
<button type="button" class="btn btn-outline-secondary btn-sm"
disabled="@_opening" @onclick="RefreshBrowseAsync">
@if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
Refresh
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" @onclick="CloseBrowseAsync">
Close
</button>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-secondary"
disabled="@_opening" @onclick="RefreshBrowseAsync">
@if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
Refresh
</button>
<button type="button" class="btn btn-outline-secondary" @onclick="CloseBrowseAsync">
Close
</button>
</div>
}
@if (_openError is not null) { <span class="chip chip-bad" title="@_openError">@TruncatedError()</span> }
</div>
@@ -74,14 +74,16 @@
else
{
<span class="chip chip-ok">Browser open</span>
<button type="button" class="btn btn-outline-secondary btn-sm"
disabled="@_opening" @onclick="RefreshBrowseAsync">
@if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
Refresh
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" @onclick="CloseBrowseAsync">
Close
</button>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-secondary"
disabled="@_opening" @onclick="RefreshBrowseAsync">
@if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
Refresh
</button>
<button type="button" class="btn btn-outline-secondary" @onclick="CloseBrowseAsync">
Close
</button>
</div>
}
@if (_openError is not null) { <span class="chip chip-bad" title="@_openError">@TruncatedError()</span> }
</div>
@@ -35,14 +35,16 @@
else
{
<span class="chip chip-ok">Browser open</span>
<button type="button" class="btn btn-outline-secondary btn-sm"
disabled="@_opening" @onclick="RefreshBrowseAsync">
@if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
Refresh
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" @onclick="CloseBrowseAsync">
Close
</button>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-secondary"
disabled="@_opening" @onclick="RefreshBrowseAsync">
@if (_opening) { <span class="spinner-border spinner-border-sm me-1"></span> }
Refresh
</button>
<button type="button" class="btn btn-outline-secondary" @onclick="CloseBrowseAsync">
Close
</button>
</div>
}
@if (_openError is not null) { <span class="chip chip-bad" title="@_openError">@TruncatedError()</span> }
</div>