Files
lmxopcua/docs/plans/2026-08-10-adminui-density-sweep.md
T

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) 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.