ui: Central UI density/consistency sweep + Theme 0.4.1

Applies the family-wide admin-UI cleanup playbook to the Central UI so the
Blazor surfaces stop diverging from the shared kit: buttons are grouped rather
than individually sized, long cell values are contained instead of widening
tables, and hard-coded colours give way to theme tokens.

The headline fix is that MainLayout passed Accent="#2f5fd0" to ThemeShell,
which the kit emits as an inline style on the shell root. Being a descendant of
<html>, it beat the [data-bs-theme="dark"] override for the entire app, so the
dark accent had never rendered. Declaring --accent in site.css :root instead
lets both schemes resolve; light is unchanged because the value already matched
the kit's light default.

Theme pins to 0.4.1, which upstreams the local .btn sizing block verbatim, so
that block is deleted here rather than duplicated. Verified byte-identical
before removal; the repo now declares no --bs-btn-* anywhere.

NOT purely cosmetic, contrary to the sweep's stated scope: four detail-modal
surfaces (NotificationReport, ConfigurationAuditLog, ParkedMessages,
SiteCallsReport) were additionally refactored from holding the selected record
to holding its id and re-resolving from the current page each render, with the
resolve doubling as the visibility gate. A background refresh that drops the
row now closes the modal instead of showing a stale snapshot. This is a
behaviour change and is called out rather than buried: a full-suite run turned
up one intermittent CentralUI failure, CloseButton_DismissesModal, whose stack
(GetRequiredEventBindingEntry during DispatchEventAsync) indicates the handler
was disposed between render and click — a window the previous field-held record
made structurally impossible. Treat the modal lifecycle here as unreviewed.

Build 0/0; suite green apart from that one intermittent failure.
This commit is contained in:
Joseph Doherty
2026-08-11 05:50:12 -04:00
parent b6f383a225
commit 9e243493fb
77 changed files with 2197 additions and 1292 deletions
+10 -7
View File
@@ -17,7 +17,8 @@ As of M8 (T18), Transport is no longer limited to central-only configuration: it
## Responsibilities
- Define and own the `.scadabundle` file format (ZIP container, `manifest.json`, `content.json` / `content.enc`).
- Resolve artifact dependencies at export time: base templates, shared scripts, external systems, template folders, notification lists, SMTP configs, API keys, API methods.
- Resolve artifact dependencies at export time: base templates, shared scripts, external systems, template folders, notification lists, SMTP configs, SMS configs, API methods.
- **Inbound API keys are deliberately NOT transportable.** They live in each environment's own secret store (per-env pepper, secret shown once) and cannot be exported — see the comment on `ExportSelection`. Only API *methods* travel. After importing into a destination environment, an operator must re-create the keys there and re-grant their method scopes via the admin UI or CLI.
- Move **site-scoped configuration** (T18): `Site` definitions, site-scoped `DataConnection`s (protocol connections — distinct from External-System `DatabaseConnection`s), and `Instance`s along with their `InstanceAttributeOverride` / `InstanceAlarmOverride` / `InstanceNativeAlarmSourceOverride` / `InstanceConnectionBinding` children and `Area` membership (carried by name).
- Reconcile cross-environment site identifiers and connection names through the **name-mapping subsystem** (`BundleNameMap`): auto-match by identifier/name, operator override via the import-wizard Map step or CLI flags, and per-conflict create-or-bind resolution (see "Name Mapping").
- Compute a **per-line (Myers) diff** for code fields on Modified artifacts (T20) via the pure `LineDiffer`, embedding a size-capped structured line diff in each `ArtifactDiff`. Two independent caps guard the diff: a 400-line **output** cap on the emitted hunk list, and — as of arch-review 05 (Task 22) — a `MaxInputLines` **input** cap (4000 combined lines) that short-circuits the O((N+M)²) Myers trace to a summary-only result (`Truncated = true`, add/remove totals only) so a bloated or crafted bundle cannot OOM the active central node from the import preview.
@@ -72,7 +73,7 @@ zip-bomb guard, and the exporter never emits per-script files.
"summary": {
"templates": 12, "templateFolders": 3, "sharedScripts": 4,
"externalSystems": 2, "dbConnections": 1,
"notificationLists": 1, "smtpConfigs": 0, "apiKeys": 2, "apiMethods": 5,
"notificationLists": 1, "smtpConfigs": 0, "smsConfigs": 0, "apiMethods": 5,
"sites": 2, "dataConnections": 3, "instances": 8
},
"contents": [
@@ -141,7 +142,7 @@ The component is central-hosted. It is registered in `ZB.MOM.WW.ScadaBridge.Host
### UI — 4-Step Wizard (Design nav group)
**Step 1 — Select artifacts.** Templates are rendered as a tree matching the existing Templates page (the `TemplateFolderTree.razor` shared component, used in its new checkbox-selection mode). Tri-state checkboxes on folders (`☑` all, `☐` none, `▣` partial). Search filters the tree in place. Other artifact groups (shared scripts, external systems, notification lists, SMTP configs, API keys, API methods) are flat checkbox lists.
**Step 1 — Select artifacts.** Templates are rendered as a tree matching the existing Templates page (the `TemplateFolderTree.razor` shared component, used in its new checkbox-selection mode). Tri-state checkboxes on folders (`☑` all, `☐` none, `▣` partial). Search filters the tree in place. Other artifact groups (shared scripts, external systems, notification lists, SMTP configs, SMS configs, API methods) are flat checkbox lists. API keys are not offered — they are not transportable (see Scope).
A **Sites & Instances** section (T18) adds a flat list of sites, each row expandable to its instances; selecting a site or individual instances pulls them (and their site-scoped `DataConnection`s) into the bundle. The wizard distinguishes operator-seeded selections from artifacts auto-included by dependency resolution (e.g., an instance's site and bound connections).
@@ -151,7 +152,7 @@ A **Sites & Instances** section (T18) adds a flat list of sites, each row expand
- `Template` references `SharedScript` (by name) → include the script.
- `Template` references `ExternalSystem` → include the definition and its methods.
- `ApiMethod` references `SharedScript` → include the script.
- `NotificationList` references `SmtpConfiguration` → include the SMTP config.
- `NotificationList` does **not** pull in an `SmtpConfiguration`. SMTP (and SMS) configurations are environment-specific and are only ever included when the operator selects them explicitly — the resolver walks `ExportSelection.SmtpConfigurationIds` alone.
- Any folder containing a selected template is included so the structure is reproducible on import.
The user can toggle "include all dependencies" off (with a warning that the bundle may produce an invalid import).
@@ -213,7 +214,9 @@ Authorization: `RequireDesign` on both the Razor page and `IBundleExporter.Expor
## Import Flow
### UI — 6-Step Wizard (Admin nav group)
### UI — 5-Step Wizard (Admin nav group)
Upload → Passphrase → Diff → Confirm → Result. The **Map** step is not a sixth pill: name mapping is a section rendered inside the Diff step.
**Step 1 — Upload.** Drag-and-drop or browse. On selection, the manifest is parsed and displayed (source env, exporter, timestamp, content count, SHA-256, encrypted yes/no). The manifest hash is validated against the `content` blob.
@@ -371,7 +374,7 @@ Three commands surface the same Transport operations as the Central UI wizards,
```bash
scadabridge bundle export --output FILE --passphrase X [--all | --templates A,B ...] \
[--shared-scripts ...] [--external-systems ...] [--db-connections ...] \
[--notification-lists ...] [--smtp-configs ...] [--api-keys ...] \
[--notification-lists ...] [--smtp-configs ...] [--sms-configs ...] \
[--api-methods ...] [--sites A,B ...] [--instances X,Y ...] \
[--include-dependencies] [--source-environment NAME]
@@ -446,7 +449,7 @@ The `manifest.json` file is always present in the ZIP root and is never encrypte
"dbConnections": 1,
"notificationLists": 1,
"smtpConfigs": 0,
"apiKeys": 2,
"smsConfigs": 0,
"apiMethods": 5,
"sites": 2,
"dataConnections": 3,