diff --git a/CLAUDE.md b/CLAUDE.md index 1086033..d9bf186 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -160,7 +160,7 @@ each project's **code-verified current state**, and the **gaps** between. See | Component | Status | Goal | Design | Implementation | |---|---|---|---|---| | Auth (login / identity / authz) | **2026-11-09: source at `0.4.4`, UNPUBLISHED** (0.4.2 typed `ApiKeyPepperUnavailableException`; 0.4.3 Sqlite 10.0.13; 0.4.4 user-bind proves the bound account = the entry whose groups it returns (#40), SQL Server key ids case-exact, `ApiKeyFailure.StoreUnavailable`) — live-verify vs real AD before publishing (scadaproj#51). Adopted. Feed carries **`0.4.1`** (2026-10-01; 0.4.0 the same day; opt-in user bind) — **all four apps pin `0.4.1` on their default branches since 2026-11-09** (scadaproj#5: OtOpcUa `1ecd01d3`, ScadaBridge `37fcd296`, mxgw `ace12f81`, HistorianGateway `0d06483`; `BindMode` left at `ServiceAccount`; NOT deployed — wonder boxes still run `0.3.0` builds). History below refers to the earlier `0.3.0` pins. **All four apps pin `0.3.0`** (2026-09-03, all on their default branch and pushed — and all four are DEPLOYED at those tips on DEV vd03 and QA vq03/vq04 since 2026-09-10: OtOpcUa `b8b4c18f`, mxgw `4f931e4`, HistorianGateway `d8d890c`; ScadaBridge already had it on `main` via the `inbound-api-key-shared-store` work, `e45c4af9`). **0.4.0 (2026-10-01) — opt-in LDAP user bind:** adds `LdapOptions.BindMode` (`ServiceAccount` default | `User`), `UserBindTemplate` and `AcceptDomainQualifiedNames`; in `User` mode `LdapAuthService` binds as the signing-in user and reads their own groups on the same connection, so no service account is needed. Bind failures map to `BadCredentials` (bad password, unusable name, or bind result 49) or `GroupLookupFailed` (zero/multiple entries or no groups after a good bind), other bind/connect/search errors fail over to the next endpoint, and `ServiceAccount` stays the default so no existing consumer needs to change. **0.4.1** fixes the review findings: `Username` is canonicalised from the entry's `UserNameAttribute`, empty passwords are refused in both bind modes (a `ServiceAccount`-mode behaviour change), and the docs prefer the down-level `EXAMPLE\{0}` template over UPN. First consumer: BTDB Manager; ScadaBridge/HistorianGateway/OtOpcUa/MxAccessGateway stay on `0.3.0` until they move to AD. `0.2.1` is a functional fix, not housekeeping — `0.1.5` cannot log in against an AD domain root at all. `FallbackServers` (0.2.0) live-gated on the redundant local GLAuth pair. Version narrative, consumer matrix, `tools/LdapProbe`: [`ZB.MOM.WW.Auth/CLAUDE.md`](ZB.MOM.WW.Auth/CLAUDE.md). | Shared `ZB.MOM.WW.Auth` lib | [`components/auth/`](components/auth/) | [`ZB.MOM.WW.Auth/`](ZB.MOM.WW.Auth/) | -| UI Theme (layout / tokens / components) | **2026-11-09: all five consumers pin `0.5.0` on their default branches (scadaproj#9; not deployed, no browser check yet); source at `0.5.2` unpublished (TechButton `disabled`, nav-state WeakSet, opt-in `ThemeShell ScrollNav`).** Adopted. Feed `0.2.0`–`0.4.1`; **five** consumers (the ignitionoee router joined), all on `0.4.1` and pushed (2026-08-11); Every deployed wonder box (DEV vd03 + QA vq03/vq04) runs its repo tip as of 2026-09-10, so the deployed Theme is 0.4.1 everywhere. **On bump, TRIM the local `.btn` block, don't delete it** — mxgw's carried more than sizing. Narrative: [`ZB.MOM.WW.Theme/CLAUDE.md`](ZB.MOM.WW.Theme/CLAUDE.md). | Shared `ZB.MOM.WW.Theme` RCL | [`components/ui-theme/`](components/ui-theme/) | [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) | +| UI Theme (layout / tokens / components) | **2026-11-09: all five consumers pin `0.5.0` on their default branches (scadaproj#9; not deployed, no browser check yet); source at `0.5.3` unpublished (TechButton `disabled`, nav-state WeakSet, opt-in `ThemeShell ScrollNav`; 0.5.3 shell `100dvh` fill, #10).** Adopted. Feed `0.2.0`–`0.4.1`; **five** consumers (the ignitionoee router joined), all on `0.4.1` and pushed (2026-08-11); Every deployed wonder box (DEV vd03 + QA vq03/vq04) runs its repo tip as of 2026-09-10, so the deployed Theme is 0.4.1 everywhere. **On bump, TRIM the local `.btn` block, don't delete it** — mxgw's carried more than sizing. Narrative: [`ZB.MOM.WW.Theme/CLAUDE.md`](ZB.MOM.WW.Theme/CLAUDE.md). | Shared `ZB.MOM.WW.Theme` RCL | [`components/ui-theme/`](components/ui-theme/) | [`ZB.MOM.WW.Theme/`](ZB.MOM.WW.Theme/) | | Health (readiness / liveness / active-node) | **Adopted** — lib `0.3.0`, all 4 apps reference it + wire `MapZbHealth`. `0.2.1`/`0.3.0` changed the active tier's behaviour (standby now answers **503**; active = oldest `Up` member via `ClusterActiveNode`, not `RoleLeader` — the two diverge after any restart), and both Akka apps' private copies were deleted in its favour (merged + pushed). Narrative: [`ZB.MOM.WW.Health/CLAUDE.md`](ZB.MOM.WW.Health/CLAUDE.md). | Shared `ZB.MOM.WW.Health` lib | [`components/health/`](components/health/) | [`ZB.MOM.WW.Health/`](ZB.MOM.WW.Health/) | | Observability (metrics / traces / logs) | **Adopted** (libs `0.1.0`, on the feed; **all 4 apps** call `AddZbTelemetry`; `AddZbSerilog` in all but ScadaBridge, which keeps its own factory by design) | Shared `ZB.MOM.WW.Telemetry` lib + `.Serilog` | [`components/observability/`](components/observability/) | [`ZB.MOM.WW.Telemetry/`](ZB.MOM.WW.Telemetry/) | | Config + validation (options / startup validation) | Adopted (lib `0.1.0`, on the feed; **all 4 apps**, pushed — the "local only / not yet pushed" caveat was stale) | Shared `ZB.MOM.WW.Configuration` lib | [`components/configuration/`](components/configuration/) | [`ZB.MOM.WW.Configuration/`](ZB.MOM.WW.Configuration/) | diff --git a/ZB.MOM.WW.Theme/CLAUDE.md b/ZB.MOM.WW.Theme/CLAUDE.md index 4b9ea57..00ac41c 100644 --- a/ZB.MOM.WW.Theme/CLAUDE.md +++ b/ZB.MOM.WW.Theme/CLAUDE.md @@ -2,7 +2,22 @@ Shared UI kit (Razor Class Library — Technical-Light tokens, IBM Plex, side-rail shell, widgets) for the **ZB.MOM.WW SCADA family**; five consumers. Build/test from this directory: `dotnet test`. Component spec + gaps: `../components/ui-theme/`. -**Backlog / open work:** lives in Gitea issues on `dohertj2/scadaproj` (`tea issues list --repo dohertj2/scadaproj`) — currently #9 (roll `0.5.0` to the other consumers), #10 (`layout.css` `calc(100vh - 3.3rem)` review). The history below is a record, not a status tracker; file new follow-ups as issues. +**Backlog / open work:** lives in Gitea issues on `dohertj2/scadaproj` (`tea issues list --repo dohertj2/scadaproj`) — currently #9 (roll `0.5.0` to the other consumers); #10 (`calc(100vh - 3.3rem)`) is fixed in 0.5.3 source. The history below is a record, not a status tracker; file new follow-ups as issues. + +## 0.5.3 (2026-11-09, UNPUBLISHED) + +Fixes scadaproj#10. `.app-shell` was `min-height: calc(100vh - 3.3rem)` — the 3.3rem is a donor-app top-bar +leftover (ThemeShell renders no top bar), so below lg a short page stopped 53 px short of the viewport, and plain +`100vh` overshoots on mobile browsers with collapsing toolbars. Now `min-height: 100vh; min-height: 100dvh;` +(100vh = fallback), and the lg+ sticky `#theme-rail` is `height: 100vh; height: 100dvh;`. The column layout's +`flex: 1` on the page was already supplied by `.app-shell .page`, so the page takes the height left under the +hamburger row. Static test `Shell_fills_the_dynamic_viewport_with_no_topbar_offset`; also fixed the CS8602 in +`NavStateScriptTests` (0 warnings). Browser check (Overview on local 0.5.2 vs 0.5.3 packages, iframe viewports): +390x844 short page — before shell 791 px tall with a 53 px gap under the page, after shell/page reach 844, +`scrollHeight == innerHeight` both times (no extra scroll); 1440x900 — rail sticky at 0–900 after scrolling a +1133 px page, short page fills 900, before and after. Consumers: mxgw's `body.dashboard-body { min-height: 100vh }` +and ScadaBridge's lg+ `#theme-rail > .side-rail { height: 100% }` don't conflict; neither app still has an inline +`min-height:100vh` shell wrapper on its default branch. Version bumped in `Directory.Build.props`, not packed or pushed. ## 0.5.2 (2026-11-09, UNPUBLISHED) diff --git a/ZB.MOM.WW.Theme/Directory.Build.props b/ZB.MOM.WW.Theme/Directory.Build.props index e13d9e1..a48aff4 100644 --- a/ZB.MOM.WW.Theme/Directory.Build.props +++ b/ZB.MOM.WW.Theme/Directory.Build.props @@ -4,7 +4,7 @@ enable enable latest - 0.5.2 + 0.5.3 true diff --git a/ZB.MOM.WW.Theme/README.md b/ZB.MOM.WW.Theme/README.md index 7e925b8..fa8703c 100644 --- a/ZB.MOM.WW.Theme/README.md +++ b/ZB.MOM.WW.Theme/README.md @@ -59,7 +59,7 @@ server-side** before redirecting (open-redirect risk): | Component | Parameters (key) | Notes | |---|---|---| | `ThemeHead` | — | Emits `` tags for `theme.css` and `layout.css`. Place in `` after Bootstrap. | -| `ThemeShell` | `Product`*, `Accent`, `Logo`, `Nav`, `RailFooter`, `ChildContent`, `ScrollNav` | Side-rail chassis. Not a layout — delegated to from `MainLayout`. `Accent` overrides `--accent` token. `ScrollNav` (opt-in, default false; 0.5.2) wraps `Nav` in a `.rail-scroll` pane and fills the rail height on lg+ so a long nav scrolls while `RailFooter` stays pinned. | +| `ThemeShell` | `Product`*, `Accent`, `Logo`, `Nav`, `RailFooter`, `ChildContent`, `ScrollNav` | Side-rail chassis. Not a layout — delegated to from `MainLayout`. The shell fills the viewport (`min-height: 100dvh`, `100vh` fallback; 0.5.3) and the lg+ sticky rail is `100dvh` tall, so no consumer needs its own `min-height: 100vh` wrapper. `Accent` overrides `--accent` token. `ScrollNav` (opt-in, default false; 0.5.2) wraps `Nav` in a `.rail-scroll` pane and fills the rail height on lg+ so a long nav scrolls while `RailFooter` stays pinned. | | `BrandBar` | `Product`*, `Logo` | Brand glyph + product name; rendered inside `ThemeShell`'s rail header. | | `NavRailItem` | `Href`*, `Text`*, `Icon`, `Match` | Wraps ``. | | `NavRailSection` | `Title`*, `Expanded` (default `true`), `ChildContent` | CSS-only collapsible `
` group; no JS, works in static SSR. | diff --git a/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/wwwroot/css/layout.css b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/wwwroot/css/layout.css index 8c184e1..09a4ef2 100644 --- a/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/wwwroot/css/layout.css +++ b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/wwwroot/css/layout.css @@ -60,9 +60,17 @@ direction is supplied by Bootstrap utilities on the wrapper (`d-flex flex-column flex-lg-row`) so the hamburger row stacks above the rail on