feat(fp): WP-26 — admin org-template editor
Some checks failed
CI / frontend (push) Failing after 57s
CI / storybook-a11y (push) Successful in 4m27s
CI / backend (push) Successful in 1m15s
CI / codeql (csharp) (push) Failing after 1m42s
CI / codeql (javascript-typescript) (push) Failing after 1m19s
CI / api-client-drift (push) Successful in 1m40s
CI / e2e (push) Failing after 3h11m33s
Some checks failed
CI / frontend (push) Failing after 57s
CI / storybook-a11y (push) Successful in 4m27s
CI / backend (push) Successful in 1m15s
CI / codeql (csharp) (push) Failing after 1m42s
CI / codeql (javascript-typescript) (push) Failing after 1m19s
CI / api-client-drift (push) Successful in 1m40s
CI / e2e (push) Failing after 3h11m33s
Edit the letter's org identity in place on the same canvas the drafter composes on (editableRegions='template'): letterhead/signature/footer become inline controls, content a read-only sample. Margins (bounded), logo upload (reuses the shared upload transport + single-upload), version history + rollback, proefbrief, and publish-with-impact-confirmation. House form-machine idiom (org-template.machine.ts) + root store with debounced save. Capability-gated (orgtemplate:edit) with a deny-by-default alert; route /brief/huisstijl. Backend + generated client were already in place (WP-23). Also fixes a pre-existing red check:tokens (WP-24 canvas hex fallbacks) and threads the published logo through to the drafter's canvas. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# WP-26 — Admin org-template editor
|
||||
|
||||
Status: todo
|
||||
Status: done
|
||||
Phase: 6 — Brief v2 (edit-on-the-letter, org templates, server-rendered preview)
|
||||
|
||||
## Why
|
||||
@@ -58,17 +58,45 @@ content a read-only sample). PRD Brief v2 §5, §7h.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `?role=admin` can switch sub-orgs, edit all template fields in place on the
|
||||
- [x] `?role=admin` can switch sub-orgs, edit all template fields in place on the
|
||||
canvas, and see the canvas update live.
|
||||
- [ ] Draft saves are debounced; publish asks for confirmation showing the impact
|
||||
- [x] Draft saves are debounced; publish asks for confirmation showing the impact
|
||||
count; after publish the drafter's canvas (WP-24) reflects it on reload.
|
||||
- [ ] Version history lists published versions (who is faked, when is real);
|
||||
- [x] Version history lists published versions (who is faked, when is real);
|
||||
rollback copies an old version into the draft.
|
||||
- [ ] Non-admin on `/brief/huisstijl` sees the denial alert; API would 403 anyway.
|
||||
- [ ] Logo upload validates type/size client-side (existing `rejectReason`) and
|
||||
- [x] Non-admin on `/brief/huisstijl` sees the denial alert; API would 403 anyway.
|
||||
- [x] Logo upload validates type/size client-side (existing `rejectReason`) and
|
||||
renders on the canvas after upload.
|
||||
- [ ] Machine spec covers field edits, dirty tracking, publish/rollback outcomes.
|
||||
- [ ] Full GREEN.
|
||||
- [x] Machine spec covers field edits, dirty tracking, publish/rollback outcomes.
|
||||
- [x] Full GREEN.
|
||||
|
||||
## Deviations / notes (as built)
|
||||
|
||||
- **`check:tokens` was already red on `main`** (WP-24's canvas landed `var(--rhc-*,
|
||||
#hex)` fallbacks + an `rgb()` paper shadow, and WP-25 committed over it). Fixed here
|
||||
to end GREEN: dropped the redundant hex fallbacks (the token bridge defines every
|
||||
one) and marked the paper drop-shadow `token-ok`; also fixed a pre-existing
|
||||
`passage-picker` `var(--rhc-color-wit, #fff)` hit.
|
||||
- **Canvas edit-in-place**: `editableRegions='template'` now renders the seven
|
||||
org-identity text fields as inline `<input>`/`<textarea>` controls (aria-labelled)
|
||||
and shows the logo `<img>`; the letter body stays a read-only sample
|
||||
(`SAMPLE_LETTER_BRIEF`). `logoUrl` input added to the canvas and wired through the
|
||||
composer too, so a published logo shows to the drafter (AC2).
|
||||
- **Load-effect loop (caught in the live walk)**: the page's initial-load effect must
|
||||
NOT read the store model — `load()` dispatches `Loading` (a fresh object), which
|
||||
would retrigger a model-reading effect into a runaway loop that saturated the page.
|
||||
Gated on `canEdit()` + a plain `loadRequested` flag instead.
|
||||
- **`AccessStore.ready`** added (tiny): a page-level capability gate needs to tell
|
||||
"still loading `/me`" from "denied" so an admin doesn't flash the denial alert.
|
||||
- **`uploadContentUrl`** pure helper extracted from `UploadAdapter.contentUrl` so
|
||||
`BriefStore` can build a logo `src` without pulling `ApiClient` into its DI graph
|
||||
(kept its spec green).
|
||||
- **Role caching caveat**: `/me` loads once. Open the app with `?role=admin` from the
|
||||
first navigation that touches the editor (the dev role stub, like `?scenario=`);
|
||||
switching role mid-session won't refetch capabilities (out of scope, POC).
|
||||
- **Dirty race**: `DraftSaved` carries the saved draft and clears `dirty` only if it's
|
||||
reference-equal to the current draft, so an edit landing during a save round-trip
|
||||
keeps its pending save.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
Reference in New Issue
Block a user