AdminUI: DriverStatusPanel (Restart/Reconnect driver controls) is orphaned — referenced by no page #546

Closed
opened 2026-08-06 08:38:47 -04:00 by dohertj2 · 1 comment
Owner

Found during the ClusterClient→gRPC Phase 1A live gate (docs/plans/2026-08-06-clusterclient-to-grpc-live-gate.md): DriverStatusPanel.razor is the only component carrying the Restart/Reconnect driver buttons, and it is referenced by no page or component — verified repo-wide on both master and the 1A branch (0 usages; the only non-script-analysis POST the AdminUI makes is /api/deployments). So RestartDriver/ReconnectDriver have no reachable UI control; they work end-to-end when driven directly (proven over gRPC in the 1A gate). Pre-existing, transport-independent, out of the gRPC program's scope. Decide: wire the panel into /hosts (or wherever it was meant to live), or delete it.

Found during the ClusterClient→gRPC Phase 1A live gate (docs/plans/2026-08-06-clusterclient-to-grpc-live-gate.md): `DriverStatusPanel.razor` is the only component carrying the Restart/Reconnect driver buttons, and it is referenced by no page or component — verified repo-wide on both `master` and the 1A branch (0 usages; the only non-script-analysis POST the AdminUI makes is /api/deployments). So RestartDriver/ReconnectDriver have no reachable UI control; they work end-to-end when driven directly (proven over gRPC in the 1A gate). Pre-existing, transport-independent, out of the gRPC program's scope. Decide: wire the panel into /hosts (or wherever it was meant to live), or delete it.
Author
Owner

Fixed, merged to master @ 9420f8ef and pushed (branch fix/issue-546-panel, commits d33e4e20 + e669fb34).

Decision: wire it in — the commands were proven end-to-end over the gRPC mesh in the 1A gate; deleting working operator capability lost more than it saved. /hosts driver rows now carry a collapsed Controls expander rendering <DriverStatusPanel DriverInstanceId="@d.DriverInstanceId" ClusterId="@g.ClusterId" Enabled="@d.Enabled" /> in a full-width detail row. Expansion state is per instance-id and survives the page's 5 s rebuild; both rows are @key'd so a panel can never be diffed onto a different driver (it binds its id once in OnInitializedAsync); Enabled is projected from the real DriverInstance.Enabled (view-model records extended with a trailing optional param; an unmatched snapshot row defaults enabled deliberately — the row only exists because live health arrived).

Code review surfaced one Important: the panel's subscriptions/timer survived an Enabled true→false flip on an expanded row (pre-existing panel behavior, first made reachable here). Closed in e669fb34 by including Enabled in the detail row's @key — a flip disposes and remounts, and both directions were verified against the panel's actual OnInitializedAsync/DisposeAsync lifecycle.

Guard against re-orphaning: HostsPanelWiringTests source-scan pins that Hosts.razor references the panel AND that all three parameters are bound to row expressions, not literals. AdminUI.Tests 1113/0; full suite on the merged SHA exit 0, 9,333/0.

Live-verified on docker-dev (image from 9420f8ef): /hosts renders 11 Controls buttons (one per driver row), collapsed by default; expanding the SITEA-modbus row shows the panel; clicking Reconnect in the browser rendered "RECONNECT DISPATCHED" and both SITE-A nodes logged ForceReconnect requested by admin → reconnected ~10 s later — the full UI → AdminOps → mesh gRPC → driver path. Collapse removes the panel (disposing its subscriptions).

Fixed, merged to `master` @ `9420f8ef` and pushed (branch `fix/issue-546-panel`, commits `d33e4e20` + `e669fb34`). **Decision: wire it in** — the commands were proven end-to-end over the gRPC mesh in the 1A gate; deleting working operator capability lost more than it saved. `/hosts` driver rows now carry a collapsed **Controls** expander rendering `<DriverStatusPanel DriverInstanceId="@d.DriverInstanceId" ClusterId="@g.ClusterId" Enabled="@d.Enabled" />` in a full-width detail row. Expansion state is per instance-id and survives the page's 5 s rebuild; both rows are `@key`'d so a panel can never be diffed onto a different driver (it binds its id once in `OnInitializedAsync`); `Enabled` is projected from the real `DriverInstance.Enabled` (view-model records extended with a trailing optional param; an unmatched snapshot row defaults enabled deliberately — the row only exists because live health arrived). Code review surfaced one Important: the panel's subscriptions/timer survived an `Enabled` true→false flip on an expanded row (pre-existing panel behavior, first made reachable here). Closed in `e669fb34` by including `Enabled` in the detail row's `@key` — a flip disposes and remounts, and both directions were verified against the panel's actual `OnInitializedAsync`/`DisposeAsync` lifecycle. Guard against re-orphaning: `HostsPanelWiringTests` source-scan pins that `Hosts.razor` references the panel AND that all three parameters are bound to row expressions, not literals. AdminUI.Tests 1113/0; full suite on the merged SHA exit 0, 9,333/0. **Live-verified on docker-dev (image from `9420f8ef`):** `/hosts` renders 11 Controls buttons (one per driver row), collapsed by default; expanding the `SITEA-modbus` row shows the panel; clicking **Reconnect** in the browser rendered "RECONNECT DISPATCHED" and both SITE-A nodes logged `ForceReconnect requested by admin` → `reconnected` ~10 s later — the full UI → AdminOps → mesh gRPC → driver path. Collapse removes the panel (disposing its subscriptions).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#546