From 1ed485085812b6dd82f40228f17a2af2d582053e Mon Sep 17 00:00:00 2001 From: Edwin van den Houdt Date: Wed, 22 Jul 2026 16:53:26 +0200 Subject: [PATCH] =?UTF-8?q?feat(dev):=20WP-33=20=E2=80=94=20in-app=20dev?= =?UTF-8?q?=20switchers=20for=20scenario=20+=20role?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surface the ?scenario= and ?role= dev stand-ins as dropdowns in the existing debug-state devtool, so a demo can flip them with a click instead of editing the URL. scenario.ts/role.ts gain set* setters + exported valid-value lists (reused by the panel, no duplicated source of truth); scenario becomes tab-sticky like role so it survives navigation. Applied via location.reload() since both are read per-request in interceptors. Extends the debug-state eslint exemption to the ui→infrastructure rule (same devtool precedent). Co-Authored-By: Claude Opus 4.8 --- docs/project/backlog/README.md | 2 +- docs/project/backlog/WP-33-dev-switchers.md | 39 +++++++++++++ eslint.config.mjs | 5 +- src/app/shared/infrastructure/role.ts | 9 ++- .../shared/infrastructure/scenario.spec.ts | 29 ++++++++++ src/app/shared/infrastructure/scenario.ts | 27 +++++++-- .../ui/debug-state/debug-state.component.ts | 58 +++++++++++++++++++ 7 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 docs/project/backlog/WP-33-dev-switchers.md create mode 100644 src/app/shared/infrastructure/scenario.spec.ts diff --git a/docs/project/backlog/README.md b/docs/project/backlog/README.md index 5412328..9dc31c1 100644 --- a/docs/project/backlog/README.md +++ b/docs/project/backlog/README.md @@ -77,7 +77,7 @@ for its existing violations, so every WP ends green. | [WP-30](WP-30-ci-perf-followups.md) | CI performance follow-ups (node_modules cache, runner image, path filters) | follow-on · CI/infra | todo | | [WP-31](WP-31-shared-store-helpers.md) | Shared store helpers (ActionState/SaveState, history, debounced-save, RemoteData) | 7 · refinements | done | | [WP-32](WP-32-stamdata-undo.md) | Undo/redo in the stamdata editor | 7 · refinements | done | -| [WP-33](WP-33-dev-switchers.md) | In-app dev switchers (scenario + role) | 7 · refinements | todo | +| [WP-33](WP-33-dev-switchers.md) | In-app dev switchers (scenario + role) | 7 · refinements | done | | [WP-34](WP-34-adres-phone-brp-readonly.md) | Adres: phone field + BRP address read-only | 7 · refinements | todo | | [WP-35](WP-35-one-concept-per-type.md) | One Concept per case type (server-enforced) | 7 · refinements | todo | | [WP-36](WP-36-admin-cases.md) | Admin cases page + admin delete | 7 · refinements | todo | diff --git a/docs/project/backlog/WP-33-dev-switchers.md b/docs/project/backlog/WP-33-dev-switchers.md new file mode 100644 index 0000000..f82a9ab --- /dev/null +++ b/docs/project/backlog/WP-33-dev-switchers.md @@ -0,0 +1,39 @@ +# WP-33 — In-app dev switchers (scenario + role) + +Status: done +Phase: 7 — refinements + +## Why + +The two dev-only stand-ins — the async `?scenario=` toggle (`scenario.interceptor.ts`) and the +faked `?role=` (`role.interceptor.ts`) — were driven by hand-editing the URL query string. +Awkward for demos: you had to remember the valid values and retype them. This WP surfaces both +as dropdowns in the existing dev panel so a scenario/role can be flipped with a click. + +## Decisions (pre-made, don't relitigate) + +- **No new component/shell wiring.** The switchers live inside the existing `debug-state` + devtool (the sanctioned dev-only fab/panel already mounted in the shell under `isDevMode()`). +- **Reuse the mechanism modules, don't duplicate their source of truth.** `scenario.ts`/`role.ts` + gain a `set*` setter + an exported valid-values list; the panel imports them. `debug-state` is + added to the `ui→infrastructure` eslint exemption (same precedent as its existing cross-context + exemption) rather than re-declaring the storage keys / valid lists in the UI. +- **Scenario becomes tab-sticky (sessionStorage), mirroring role.** Without this the switcher + would be near-useless: navigation drops the query param and reverts to `default` mid-demo. +- **Apply by `location.reload()`.** Both values are read per-request in interceptors and gate + server-computed decision flags already fetched by eager `httpResource`s — a reload is the + simplest correct way to re-run them. Acceptable for a dev tool. + +## Files + +- `shared/infrastructure/scenario.ts` — tab-sticky read (mirrors role), `setScenario`, exported + `SCENARIOS`; co-located `scenario.spec.ts`. +- `shared/infrastructure/role.ts` — `setRole`, exported `ROLES`. +- `shared/ui/debug-state/debug-state.component.ts` — two ` + @for (r of roles; track r) { + + } + + + +
{{ snapshot() | json }}
} @@ -92,6 +134,22 @@ export class DebugStateComponent { pendingHerregistratie: this.profileStore?.pendingHerregistratie(), })); + // Dev switchers (WP-33): flip role/scenario without hand-editing the URL. Both are + // read per-request in interceptors, so a reload re-runs them and re-fetches decisions. + protected readonly roles = ROLES; + protected readonly scenarios = SCENARIOS; + protected readonly role = currentRole(); + protected readonly scenario = currentScenario(); + + switchRole(r: Role): void { + setRole(r); + location.reload(); + } + switchScenario(s: Scenario): void { + setScenario(s); + location.reload(); + } + toggle(): void { if (!this.visible()) this.profileStore ??= this.injector.get(BigProfileStore); this.visible.update((v) => !v);