Files
apf_portal/libs/shared
Julien Gautier c49a807966
CI / scan (pull_request) Successful in 3m16s
CI / commits (pull_request) Successful in 3m54s
CI / check (pull_request) Successful in 4m11s
CI / a11y (pull_request) Successful in 2m19s
CI / perf (pull_request) Successful in 5m8s
feat(shared-ui): move the role label from the portal-shell sidebar into the user menu
The "Role: Anonymous / User / Administrator" widget at the bottom of
the portal-shell sidebar always struck the same audience as the user
menu — it told the reader who they were and what they could do. With
the menu now carrying the full identity card (displayName, username,
role-curated actions like "Open Portal Admin"), keeping the role
in the sidebar duplicates the surface and surfaces the label on
anonymous traffic where it carries no real information ("Role:
Anonymous" was a verbose synonym for "Sign in").

This PR moves the role chip into the user-menu panel header, where
it sits between the username and the menu rows. Hidden on anonymous
traffic by construction — the `<lib-user-menu>` only renders for
the authenticated case in both apps' headers.

Shape:

* `UserMenu` (shared-ui) gains an **optional `role` input**. When
  set, a small brand-tinted pill renders inside the panel header
  below the username (`data-testid="user-menu-role"`). When
  undefined, the entire chip is omitted — keeps backwards compat
  with any future caller that doesn't carry a role concept.

* `portal-shell`'s header computes `roleLabel` from the existing
  `CapabilitiesService.canAccessAdmin` signal (the same logic that
  previously lived in the sidebar), passing the localised string
  through the new input. The sidebar role widget — HTML +
  `roleLabel` / `roleAriaLabel` computeds + the `AuthService` and
  `CapabilitiesService` injections — is removed.

* `portal-admin`'s header passes a hardcoded `'Administrator'`.
  Every reader who reaches the admin app already carries
  `Portal.Admin` (guard precondition); no need to re-derive. No
  i18n marks per ADR-0020's source-locale-only chrome.

* The `sidebar.role.{anonymous,administrator,user,aria,label}`
  translation units are removed from `messages.fr.xlf`. Replaced by
  `common.role.{administrator,user}` (the new owners are the user
  menu in either app, hence the generic prefix). The "Anonymous"
  string is gone too — the chip is hidden on anonymous traffic, the
  label served no purpose without the user menu rendering it.

* The portal-shell sidebar spec drops its three "role label" tests
  (the widget is gone) and grows a guard test asserting the
  `data-testid="sidebar-role"` element no longer exists. The
  setup is simplified back to the pre-#151 shape — no Http
  testing infrastructure needed, since the sidebar no longer
  injects `AuthService` / `CapabilitiesService`.

* The portal-shell header spec gains two assertions for the role
  chip inside the open menu panel (Administrator / User).

* The shared `UserMenu` spec gains two assertions covering the new
  input's presence/absence semantics.

Verification:
  * 43 portal-shell specs pass (header +2, sidebar -2 net, balanced).
  * 50 portal-admin specs pass (no spec edits).
  * 10 shared-ui specs pass (was 8, +2 for the role chip).
  * `pnpm nx run portal-shell:build:production` (i18n-strict) green
    — confirms the xlf cleanup + new `common.role.*` keys are
    consistent with the source-locale usage.
2026-05-16 03:05:22 +02:00
..