4.0 KiB
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) andEquipmentPage.razor(only authoring page with no panel idiom + bare RawPath column). - Deliberate designs kept:
RawManualTagEntryModalcolspan config sub-row (documented, insidemodal-xl— a fix means stacked modals),VirtualTagModalinline Monaco card (collapsed by default, own card boundary). - Style-only residual (not §1d, not in this sweep):
Deployments.razoris 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.