docs(plan): AdminUI density sweep — §1d scan findings + 3-task execution plan

This commit is contained in:
Joseph Doherty
2026-08-10 17:56:27 -04:00
parent 34d60c4125
commit 9e337efa0a
@@ -0,0 +1,65 @@
# AdminUI density/layout sweep (§1d follow-through) — 2026-08-10
Follow-through of the `/hosts` density rework: the §1d scan (four parallel read-only agents,
62 files) applied to the rest of the AdminUI. Playbook: `../scadaproj/admin_ui_cleanup.md`
§1d + §2 "Density fixes". Prior context: `2026-08-10-adminui-ui-sweeps.md` (structure sweep)
and the `/hosts` rework commit `34d60c41`.
## Scan verdict
- **Zero unguarded `[..N]` slices** anywhere (all existing slices are length-guarded or Guid-fixed).
- Cluster pages: no A/B/D defects at all; 3 C items.
- The dominant class is **C — unbounded backend/free text** (~17 sites), concentrated on the
fault-triage surfaces (`/alerts`, `/fleet`, `/script-log`, alarms-historian, DriverStatusPanel).
- Two structural defects: `Scripts.razor` (inline `<details>` source dump + identity slam — the
/hosts shape) and `EquipmentPage.razor` (only authoring page with no panel idiom + bare RawPath
column).
- Deliberate designs kept: `RawManualTagEntryModal` colspan config sub-row (documented, inside
`modal-xl` — a fix means stacked modals), `VirtualTagModal` inline Monaco card (collapsed by
default, own card boundary).
- Style-only residual (not §1d, not in this sweep): `Deployments.razor` is off the panel idiom
(bare `<h1>` + Bootstrap table).
## Task 1 — mechanical truncation sweep (Abbreviate + title)
All `DisplayText.Abbreviate(value, N)` + full text on `title`; behavior byte-for-byte.
| File:line | Value | N |
|---|---|---|
| `Pages/Alerts.razor:84` | alarm `Message` | 80 |
| `Pages/Fleet.razor:92` | `FailureReason` | 80 |
| `Pages/ScriptLog.razor:71` | log `Message` (mono) | 120 |
| `Pages/AlarmsHistorian.razor:41` | drain `LastError` | 80 |
| `Shared/Drivers/DriverStatusPanel.razor` | op-result chip — truncate in `ShowOpResult` choke point, `title` on chip; also `:41` SignalR `_error` | 60 |
| `Pages/Certificates.razor:77-78` | Subject / Issuer DNs | 48 |
| `Pages/RoleGrants.razor:65,96,24` | LDAP group DNs, SearchBase | 48 |
| `Pages/Clusters/ClusterAcls.razor:88` | ACL `Notes` | 60 |
| `Pages/Clusters/ClusterOverview.razor:49,100,102` | cluster `Notes` (120), `Host` (30), `ApplicationUri` (40) | — |
| `Pages/Clusters/ClusterRedundancy.razor:128` | `ApplicationUri` | 40 |
| `Pages/Account.razor:63` | group-DN chips | 40 |
| `Pages/Clusters/ClusterAudit.razor:55-57` | add `title` to the already-ellipsized DetailsJson cell | — |
| `Shared/Drivers/Pickers/SqlAddressPickerBody.razor:208-211` | composed TagConfig JSON `<code>` | 64 |
| `Shared/Drivers/Pickers/SqlAddressPickerBody.razor:159-162` | `_openError` → adopt the sibling truncated-chip + `title` pattern | 60 |
| `Shared/Drivers/DriverTagPicker.razor:19-22` | footer `CurrentAddress` | 60 |
| Picker Result `<code>` lines (AbCip:75, TwinCAT:64, OpcUaClient:57, Galaxy:95, FOCAS:109) | browsed address | 64 |
## Task 2 — Scripts page: `<details>` expander → source dialog + two-line identity
`Pages/Scripts.razor`: replace the per-row inline `<details>`/`<pre>` source dump with the
Bootstrap modal pattern (`modal-backdrop fade show` + `modal fade show d-block`, `modal-lg`,
one at a time); list rows get the stacked identity (name first line, mono id + hash beneath,
chips with the name). Hold only the open row's `ScriptId`; re-resolve from current data every
render (self-closes if the script vanishes).
## Task 3 — EquipmentPage: adopt the panel idiom + bound the RawPath column
`Pages/Uns/EquipmentPage.razor`: wrap each tab body in `<section class="panel">` +
`panel-head` (Details tab: Identity and OPC 40010 as two panels, dropping the `<hr>`),
matching ScriptEdit's shells; `Abbreviate(r.RawPath, 48)` + `title` at :166. Behavior
byte-for-byte — tab switching, all bindings, buttons, modals unchanged.
## Verification
Merged-tree full build + AdminUI.Tests; live gate on docker-dev (both centrals rebuilt) with
at least one faulted/erroring row on screen (§1d realistic-data rule): /alerts, /fleet,
/scripts dialog open/close, equipment page tabs, Sql picker footer.