fix(spa): detail-page action toast colour by level (#632) + verify-and-lock #629 / #636 + release 1.4.12#639
Merged
Conversation
Plus lock-in tests for two audit verifications that already worked (#629 / #636 — close-with-tests). ## #632 — toast colour by Django level The detail page's `ObjectActionButton.onSuccess` was unconditionally calling `toast.success(message || 'Done')` — so a `message_user(..., level=messages.ERROR)` from a per-object action toasted GREEN instead of red. The list page already dispatched by level correctly; the asymmetry was hidden behind the legacy `runObjectAction` adapter in `@dar/data/mutations.ts`, which collapsed the `ActionRunResponse.messages[]` (each with a level) into a single `message` string and dropped the level. Fix: - `ObjectActionRunResponse` now carries `messages?: UserMessage[]` alongside the legacy `message?: string`. - `runObjectAction` propagates the full list. - A new shared `toastMessages(toast, messages)` helper lives next to `useToast` and maps each level to the right toast method (`error` / `warning` → red, `info` / `debug` → blue, `success` / unknown → green) — mirrors what the list page already does inline. - `DetailPage`'s `onSuccess` now uses the helper when `messages[]` is present; falls back to `toast.success(message || 'Done')` for back-compat with v1.4.x APIs that don't emit messages. ## #629 — prepopulated_fields verify-and-lock The wire already carries `prepopulated_fields`; `CreatePage` already slugifies the target from sources on each keystroke and opts the target out of further auto-fill once the operator edits it by hand. Pulled the logic out of `handleFieldChange` into a pure `applyPrepopulate(...)` helper so a vitest can pin the four behaviours (single source, joined sources, manual-edit lock, empty fallback) without rendering the whole CreatePage. ## #636 — open-redirect protection on `?next=` `DarLoginView` is a `LoginView` subclass that doesn't override `get_success_url` / `form_valid` / `success_url_allowed_hosts`, so the parent's same-host check on `?next=` is intact today. Added a pytest that POSTs the login with `?next=https://evil.example.com/` and asserts the redirect target is NOT off-host — locks the property so a future override can't silently re-introduce the open-redirect. ## Verification - `pnpm -r typecheck` ✓ - `pnpm lint` (js + css + darkmode) ✓ - `pnpm test` — 174 / 174 (up from 163; +11 new) ✓ - `poetry run pytest tests/test_login_next_redirect.py -v` — 2 / 2 ✓ - `pnpm -w build` ✓ Closes #629, closes #632, closes #636. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #629, closes #632, closes #636. First release on the OIDC
publish.ymlTrusted Publisher path.#632 — toast colour by message level (real bug fix)
The detail page's
ObjectActionButton.onSuccesswas unconditionally toasting green — amessage_user(..., level=messages.ERROR)from a per-object action came up the same colour as a success. List page already dispatched correctly; the asymmetry was hidden behind the legacyrunObjectActionadapter in@dar/data/mutations.ts, which collapsedmessages[]into a single string and dropped the level.ObjectActionRunResponsenow carriesmessages?: UserMessage[].toastMessages(toast, messages)helper next touseToastmaps each level to the right method (mirrors the inline list-page logic).DetailPageuses the helper whenmessages[]is present.#629 — prepopulated_fields verify-and-lock (no behaviour change)
Already worked. Pulled the slugify-on-change logic out of
CreatePage.handleFieldChangeinto a pureapplyPrepopulate(...)helper, added a vitest that locks the four behaviours (single source / joined sources / manual-edit lock / empty fallback).#636 —
?next=open-redirect verify-and-lock (no behaviour change)DarLoginViewdoesn't override the redirect helpers, soLoginView's parent allow-list check is intact today. Added a pytest that POSTs login with?next=https://evil.example.com/and asserts the redirect target stays same-host.Verification
pnpm -r typecheck✓pnpm lint(js + css + darkmode) ✓pnpm test— 174 / 174 (up from 163; +11 new) ✓poetry run pytest tests/test_login_next_redirect.py -v— 2 / 2 ✓pnpm -w build✓Smoke test for the new publish.yml flow
Once merged + tag +
gh release create v1.4.12fires, the newpublish.ymlworkflow should auto-publish via OIDC Trusted Publishing (no local.envneeded). The idempotency guard means we can't break anything by accident.🤖 Generated with Claude Code