docs: admin_ui_cleanup — add density/layout scan (1d) + fixes from the OtOpcUa /hosts rework

This commit is contained in:
Joseph Doherty
2026-08-10 17:41:36 -04:00
parent f0f607ea46
commit d131416673
+48 -2
View File
@@ -15,7 +15,7 @@ always a live browser pass.**
---
## 1. Discovery — four parallel read-only scans
## 1. Discovery — five read-only scans (1a–1d parallelize per file; 1d also needs a live walk)
Run these as parallel read-only agents (or by hand) and write the inventories down with `file:line`
before changing anything. The inventories become the per-batch fix briefs.
@@ -84,7 +84,27 @@ Inventory, with file:line:
code's `SectionName` said `Security:Ldap` — always verify cited key names against the options
class). Wrong facts outrank style: fix or delete them even if you skip everything else.
### 1d. Tree tables — check the data shape before porting the component
### 1d. Density / layout scan (found post-sweep, on OtOpcUa's `/hosts`)
The four scans above can all pass while a page is still unreadable — the sweep left `/hosts`
structurally correct and visually overloaded ("text slams together, the table is overloaded, no
separation between sections"). Walk each *page* (not each file) with realistic data and look for:
- **Sections running together.** One `panel` wrapping several groups, each with its own nested
`panel-head` — three headings stack flush with no card boundaries. Tell: `panel-head` appearing
more than once inside one `<section class="panel">`.
- **Identity slam.** A cell rendering name + id + status chips inline in one run
(`gate-modbus-renamedDRV-ce2fb5217f5d`). Two identifiers in one cell need two lines.
- **Unbounded free-text columns.** Any column bound to text the app doesn't control — error
messages, exception text, paths, config values — with no truncation. One long driver exception
widened the table until the actions column scrolled out of reach. Tell: `@d.SomeError`,
`@x.Message` etc. rendered bare in a `<td>`.
- **Inline full-width expander/detail rows** inside an already-dense table (a `colspan` row hosting
a whole panel). They destroy scannability exactly when the operator most needs it.
- **Realistic data matters.** On a healthy rig every error cell reads "—" and the defect is
invisible — the live gate below must be run with at least one faulted/erroring row on screen.
### 1e. Tree tables — check the data shape before porting the component
The router built a generic `TreeTable` + `TreeVisibility` (depth-ordered flat `ITreeRow` list,
forward-scan visibility — reference implementation in
@@ -154,6 +174,28 @@ foundation branch merges — all branches build independently and compose at mer
- Respect existing "buttons-not-anchors" comments (Blazor's `blazor.web.js` navigation interceptor
is why some tree labels are buttons) — never convert those to links.
### Density fixes (the `/hosts` rework, applicable anywhere 1d fires)
- **One panel per group.** Replace panel-wrapping-groups with one `section.panel` per group; hoist
the group's metadata (node/host chips, counts) into that panel's head so it stops being a
paragraph between heading and table.
- **Stack identities.** Primary name on the first line; the machine id on its own
`<div class="mono small text-muted">` beneath. Chips stay with the name line.
- **Truncate unbounded text with a safe helper, never a raw slice.** OtOpcUa's
`DisplayText.Abbreviate(value, 60)` + the full text on `title` — a raw `@x[..60]` 500s the whole
page when the value is shorter (OtOpcUa #504). Keep the full text reachable (tooltip + the
row's detail dialog).
- **Inline expander rows → a dialog.** Host the same detail component in a Bootstrap modal
(`modal-backdrop fade show` + `modal fade show d-block`, `modal-lg`), one at a time. Lifecycle
cautions that made the OtOpcUa version correct:
- Hold only the **id** of the open row on the page component; **re-resolve the row from current
data every render** — auto-refresh replaces row records, and a dialog caching one goes stale or
strands. A row that disappears ⇒ the dialog renders nothing (self-closes).
- Preserve any `@key` recycle discipline the inline version carried (OtOpcUa keys the panel on
`id + Enabled` so a config flip disposes and remounts it, keeping store subscriptions honest).
- Expect **source-scan guard tests** to pin the old markup (no bUnit ⇒ repos guard wiring by
grepping the `.razor` source); re-pin them to the dialog markup in the same commit.
### Execution pattern (what actually worked, twice)
- Discovery scans → plan doc with the full inventories → **one foundation agent + N page-batch
@@ -182,6 +224,10 @@ you the stale one otherwise), then walk:
write on shared rigs); verify disarm.
5. Anything the scoped bundle resurrected (context menus float at the cursor, backdrops cover).
6. Legends/hints/empty states from the KEEP list still render.
7. **Density, with realistic data**: at least one faulted/erroring row on screen (a healthy rig
renders "—" in every free-text cell and hides the unbounded-column defect entirely); sections
read as separate cards; no horizontal scroll; any detail dialog opens with live data and closes
cleanly.
Record PASS/FAIL per check in the plan or a recipe doc; CSS-only fixes may land in-session, anything
structural gets recorded instead.