Phase 3 PR 29 — Account/session page with roles + capabilities #28

Merged
dohertj2 merged 1 commits from phase-3-pr29-account-page into v2 2026-04-18 14:46:46 -04:00
Owner

Expands the minimal sidebar role display into a dedicated /account route.

What's shown

  • Identity — username (from ClaimTypes.NameIdentifier) + display name (from ClaimTypes.Name).
  • Admin roles — the set of Admin roles as badges (from ClaimTypes.Role, populated from LDAP group mapping at sign-in).
  • LDAP groups — raw LDAP groups that produced those roles (from the ldap_group claim that Login.razor already adds).
  • Capability table — each Admin capability, its required role, and a Yes/No badge for whether this session has it. Mirrors Program.cs's AddAuthorizationBuilder policies + each page's [Authorize] attribute so operators can self-service check access without trial-and-error navigation.

Capabilities covered:

Capability Required role
View clusters + fleet status any admin role
Edit configuration drafts (CanEdit) ConfigEditor or FleetAdmin
Publish generations (CanPublish) FleetAdmin
Manage certificate trust FleetAdmin (PR 28 gate)
Manage external-ID reservations ConfigEditor or FleetAdmin

Sidebar change

The 'Signed in as' line in MainLayout.razor now wraps the display name in a link to /account. Sign-out stays where it is for muscle memory.

Design notes

  • Page is [Authorize] (any authenticated user) — the capability table deliberately works for every signed-in session so operators can see what they don't have access to. Helps them file the right ticket with their LDAP admin instead of getting blank Access Denied after navigating blindly.
  • Capability list is a private record list in the page, not a service. It's a UI-presentation mirror; the runtime policy is Program.cs + each page's [Authorize], and pulling it behind a service would just be indirection. A comment on the list reminds future-me to extend it when a new policy or [Authorize] page lands.

Tests

No new tests — the page is pure display over claims; its only logic (Any-overlap between session roles and required roles) is what [Authorize(Roles=...)] does in-framework, and mirroring that in a unit test would test ASP.NET rather than our code. Admin.Tests Unit stays 23 pass / 0 fail. Admin build clean — 0 errors, 0 warnings.

Closes

The third of the three Admin UI gap items the user selected to complete this round (Fleet dashboard = PR 27, Cert trust = PR 28, Account page = this one). Driver-specific admin pages remain deferred until driver options are finalized.

Expands the minimal sidebar role display into a dedicated `/account` route. ## What's shown - **Identity** — username (from `ClaimTypes.NameIdentifier`) + display name (from `ClaimTypes.Name`). - **Admin roles** — the set of Admin roles as badges (from `ClaimTypes.Role`, populated from LDAP group mapping at sign-in). - **LDAP groups** — raw LDAP groups that produced those roles (from the `ldap_group` claim that `Login.razor` already adds). - **Capability table** — each Admin capability, its required role, and a Yes/No badge for whether this session has it. Mirrors `Program.cs`'s `AddAuthorizationBuilder` policies + each page's `[Authorize]` attribute so operators can self-service check access without trial-and-error navigation. Capabilities covered: | Capability | Required role | | --- | --- | | View clusters + fleet status | any admin role | | Edit configuration drafts (`CanEdit`) | ConfigEditor or FleetAdmin | | Publish generations (`CanPublish`) | FleetAdmin | | Manage certificate trust | FleetAdmin (PR 28 gate) | | Manage external-ID reservations | ConfigEditor or FleetAdmin | ## Sidebar change The 'Signed in as' line in `MainLayout.razor` now wraps the display name in a link to `/account`. Sign-out stays where it is for muscle memory. ## Design notes - Page is `[Authorize]` (any authenticated user) — the capability table deliberately works for every signed-in session so operators can see what they **don't** have access to. Helps them file the right ticket with their LDAP admin instead of getting blank Access Denied after navigating blindly. - Capability list is a private record list in the page, not a service. It's a UI-presentation mirror; the runtime policy is `Program.cs` + each page's `[Authorize]`, and pulling it behind a service would just be indirection. A comment on the list reminds future-me to extend it when a new policy or `[Authorize]` page lands. ## Tests No new tests — the page is pure display over claims; its only logic (Any-overlap between session roles and required roles) is what `[Authorize(Roles=...)]` does in-framework, and mirroring that in a unit test would test ASP.NET rather than our code. Admin.Tests Unit stays 23 pass / 0 fail. Admin build clean — 0 errors, 0 warnings. ## Closes The third of the three Admin UI gap items the user selected to complete this round (Fleet dashboard = PR 27, Cert trust = PR 28, Account page = this one). Driver-specific admin pages remain deferred until driver options are finalized.
dohertj2 added 1 commit 2026-04-18 14:46:44 -04:00
Sidebar's 'Signed in as' line now wraps the display name in a link to /account so the existing sidebar-compact view becomes the entry point for the fuller page — keeps the sign-out button where it was for muscle memory, just adds the detail page one click away. Page is gated with [Authorize] (any authenticated admin) rather than a specific role — the capability table deliberately works for every signed-in user so they can see what they DON'T have access to, which helps them file the right ticket with their LDAP admin instead of getting a plain Access Denied when navigating blindly.
Capability → required-role table is defined as a private readonly record list in the page rather than pulled from a service because it's a UI-presentation concern, not runtime policy state — the runtime policy IS Program.cs's AddAuthorizationBuilder + each page's [Authorize] attribute, and this table just mirrors it for operator readability. Comment on the list reminds future-me to extend it when a new policy or [Authorize] page lands. No behavior change if roles are empty, but the page surfaces a hint ('Sign-in would have been blocked, so if you're seeing this, the session claim is likely stale') that nudges the operator toward signing out + back in.
No new tests added — the page is pure display over claims; its only logic is the 'has-capability' Any-overlap check which is exactly what ASP.NET's [Authorize(Roles=...)] does in-framework, and duplicating that in a unit test would test the framework rather than our code. Admin.Tests Unit stays 23 pass / 0 fail. Admin build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 901d2b8019 into v2 2026-04-18 14:46:46 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#28