8.4 KiB
AdminUI UI Sweeps Implementation Plan
Goal: Apply the ignitionoee router's UI-sweep taxonomy (2026-08-05, ~/Desktop/ignitionoee/docs/plans/2026-08-05-router-ui-sweeps.md) to the OtOpcUa AdminUI: button grouping/sizing, row-action normalization, instructional-prose removal (including five actively-wrong/stale claims), and the two AdminUI-specific foundation defects the discovery sweep found. Tree tables were evaluated and rejected — see Discovery below.
Architecture: One foundation task (site.css + App.razor + doc relocations) plus five per-batch passes over disjoint file sets, all parallelizable (foundation classes are referenced by name only — CSS class names are not compile-checked, so batches build independently and compose at merge). Orchestrator merges --no-ff (foundation first), runs the full build + AdminUI.Tests on the merged tree, then live-verifies on the docker-dev rig (http://localhost:9200, login disabled) — mandatory because the AdminUI has no bUnit and this change is almost entirely markup.
Tech stack: .NET 10 Blazor Server, Bootstrap 5.3.3 self-hosted, ZB.MOM.WW.Theme 0.3.1 (light-only), xUnit (AdminUI.Tests baseline ~1,499 — no markup coverage).
Discovery evidence (2026-08-10, four parallel read-only sweeps)
- The router's ghost-layout-class defect does NOT exist here — all 111 razor files use only classes that Theme 0.3.1/Bootstrap/site.css actually ship. But two same-class defects do:
- The scoped-CSS bundle is never linked.
ContextMenu.razor.cssbuilds and serves (_content/ZB.MOM.WW.OtOpcUa.AdminUI/ZB.MOM.WW.OtOpcUa.AdminUI.bundle.scp.cssreturns 200 on the rig) butApp.razorlinks only bootstrap → ThemeHead → site.css, so all 8.ctx-*rules no-op: context menus render in-flow (noposition:fixed), the backdrop has no viewport coverage. - Phantom tokens:
var(--alert)×13 (defined nowhere; the theme's red is--bad) — intended red error tints silently stay amber;var(--surface-2)(Scripts.razor:47) likewise dead.var(--surface-raised,#fff)(DriverStatusPanel:174) carries a fallback — harmless.
- The scoped-CSS bundle is never linked.
- Button sizing: no
.btnrule anywhere; 187 raw Bootstrap buttons (zero TechButton, zerobtn-groupin the whole app — the idiom isd-flex gap-2); 121 carrybtn-sm, 66 are full-size 1rem against the 0.9rem body (mostly modal feet +DriverFormShell). No adjacent same-group size mismatches — the convention is consistent, just unsized at the foundation. - Prose: 17 DELETE items (5 carrying stale/wrong claims:
Authentication:Ldapshould beSecurity:Ldapon Account + RoleGrants; ClusterRedundancy describes pre-Phase-6 redundancy and dead-links/docs/v2/Architecture-v2.md; ScriptLog says "F8/F9 pending" for shipped features; Certificates/ClusterAudit carry F-milestone labels), 2 RELOCATE items (driver-health per-instance-not-per-member keying →docs/Telemetry.md; audit EventId/CorrelationId dedup →docs/Configuration.md— its only current home is the historicaldocs/v2/AdminUI-rebuild-plan.md:93), and stale "arriving in v3 Batch 2/3" phrasing on the two namespace placeholder pages. - Tree tables: REJECTED. All 23 data tables are flat entity lists, time-ordered logs (a tree destroys ordering), or already grouped per parent (Hosts driver instances, Certificates per-store). Hierarchical data lives in four purpose-built lazy nav/picker trees (RawTree, AclScopeTree, UnsTree, DriverBrowseTree) that the flat-list TreeTable model cannot serve (lazy loading, no columns). Porting the router's TreeTable would create an orphan. The four trees' duplicated expander scaffolding is nav-tree duplication — left alone per AclScopeTree's documented no-bUnit separate-components decision.
Execution rules
- Six Opus subagents in isolated worktrees, one per task below; disjoint files; each builds the AdminUI project + runs
tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Testsgreen before committing on its own branch. - Orchestrator merges (foundation first), full-solution build, AdminUI.Tests on the merged tree (the parallel-worktrees-compose-only-at-full-build rule), then docker-dev live verification (rebuild BOTH central images —
:9200round-robins). - Confirm-step (arm → confirm) flows are restyle-only — behavior must be untouched: Certificates pending-action, ClusterRedundancy failover, DriverStatusPanel restart, RawBrowseModal rebirth, RawCsvImportModal all-or-nothing commit, GlobalUns delete modal.
- Genuine navigation stays links (ClusterOverview:75,104, ClusterAcls:134, Scripts:45, UnsTree ⚙/Open); DriverBrowseTree labels stay buttons (blazor.web.js interceptor comment).
Task F — foundation
Files: Components/App.razor, wwwroot/css/site.css, docs/Telemetry.md, docs/Configuration.md, Components/Shared/ContextMenu.razor.css (comment only).
- Link the scoped bundle in App.razor after site.css.
- site.css: the router's
--bs-btn-*sizing block (.btn.85rem/.35rem/.8rem,.btn-sm.78rem/.25rem/.6rem — variable overrides only, never box properties; header-comment as ZB.MOM.WW.Theme upstreaming candidates);.notice-alert(red tint from the theme's--bad*tokens, mirroring.chip-alert);.tree-twist { flex: 0 0 18px; width: 18px; }for the four trees' repeated inlinewidth:18px. - Relocate the two orphaned facts into
docs/Telemetry.md(driver-health channel) anddocs/Configuration.md(audit-log subsection) — must land before the page copies are deleted (Tasks 1–2). - Fix ContextMenu.razor.css's aspirational "light and dark" comment (theme is light-only).
Tasks 1–5 — per-batch passes (disjoint files, parallel)
Each applies to its files: (a) btn-group wrapping of adjacent related buttons (modal/form feet, confirm pairs, toolbar pairs, row-action runs ≥2); (b) action-styled btn-link → btn btn-sm btn-outline-secondary (destructive → btn-outline-danger); (c) its prose DELETE/stale-fix items; (d) inline var(--alert) tints → .notice-alert; (e) tree files adopt .tree-twist.
- Task 1 — Clusters pages: ClusterOverview, ClusterEdit, NodeEdit, NewCluster, AclEdit, ClusterAcls, ClusterRedundancy, ClustersList, ClusterAudit, ClusterNamespaces, NamespaceEdit. Includes the AclEdit
·-separated preset run → grouped small buttons; the ClusterAcls/AclEdit duplicated ~35-line ACL mode walkthrough deletion (keep theunresolved-chip decoder at ClusterAcls:66-71); the stale redundancy block + dead link; namespace placeholders → past tense. - Task 2 — Top-level ops pages: Alerts, ScriptLog, Hosts, Fleet, Deployments, Certificates, ApiKeys, RoleGrants, Scripts, ScriptEdit, Account, Reservations, AlarmsHistorian. Includes the Alerts ack/shelve cell (two
btn-group-sms split by the minutes input); RoleGrants Delete link → outline-danger; theSecurity:Ldapkey corrections; the Hosts/ClusterAudit deletions whose facts Task F relocated; ScriptLog F8/F9 + Certificates F13a stale fixes; Scripts:47--surface-2→ a shipped token. - Task 3 — UNS: GlobalUns, EquipmentPage, UnsTree, AreaModal, LineModal, VirtualTagModal, AddReferenceModal, ImportEquipmentModal, ScriptedAlarmModal (+ TagEditors noted no-op). UnsTree per-node action links → compact grouped buttons (Deletes danger; ⚙/Open stay links); GlobalUns Expand/Collapse pair; six modal feet; EquipmentPage row-action pairs.
- Task 4 — Shared/Raw: RawBrowseModal, RawCsvImportModal, RawCsvExportModal, RawManualTagEntryModal, RawTagModal, RawNameDialog, RawDriverTypeDialog, RawConfirmDialog, RawStubModal, RawTree. Seven modal feet + the mixed button/anchor export foot; browse-toolbar and rebirth-confirm pairs; drop the
py-0hack; RawTree adopts.tree-twist. - Task 5 — Shared/Drivers + Acls: DriverFormShell (the 13-form lever), CollectionEditor (foot + row actions), DriverConfigModal, DeviceModal, DriverTagPicker, DriverStatusPanel, AclScopePickerModal, AclScopeTree, DriverBrowseTree, six address-picker browse toolbars (Galaxy/FOCAS/AbCip/TwinCAT/OpcUaClient/Sql), MqttDriverForm/MTConnectDriverForm/MqttDeviceForm (tint swaps). MonacoEditor btn-link toolbar left as-is.
Task 6 — integration (orchestrator)
Merge F then 1–5 --no-ff; full build zero errors; AdminUI.Tests green; review the merged diff for KEEP-prose accidentally deleted / broken handlers / groups around non-adjacent elements; docker-dev live pass (context menu now positioned, red notice tint, button sizing, grouped feet, confirm flows still two-step); memory update. No push without an explicit request.