Skip to content

fix(admin): surface create-content failures as an error toast - #2366

Open
edrpls wants to merge 1 commit into
emdash-cms:mainfrom
edrpls:fix/content-create-error-toast
Open

fix(admin): surface create-content failures as an error toast#2366
edrpls wants to merge 1 commit into
emdash-cms:mainfrom
edrpls:fix/content-create-error-toast

Conversation

@edrpls

@edrpls edrpls commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

A rejected content CREATE (e.g. the 409 SLUG_CONFLICT when the auto-generated slug collides with an existing entry) was fully silent: ContentNewPage.createMutation has no onError, the page has no toast manager, and the QueryClient has no global mutation error handler — so the thrown Error (which already carries the server's human-readable message, via throwResponseError) died in mutation state. The Save button reset and the editor stayed on /new with zero feedback.

Every other mutation in router.tsx surfaces failures (the edit page's handleContentUpdateError → "Failed to save" toast); this adds the equivalent handler to the create mutation. It follows the settings-components pattern (useKumoToastManager + variant: "error") rather than Toast.useToastManager + type: "error": Kumo styles toast severity off variant (danger ring + error icon), while Base UI's type field is inert for styling — verified by rendering both. Strings are lingui-wrapped.

The regression test drives the real route with a mocked 409 SLUG_CONFLICT response and asserts the toast title, the server's message, the error affordance (the variant-driven toast icon — mutation-tested: dropping variant fails the test), and that the router stays on /content/posts/new. Repro proof: fails unpatched (1/14), passes patched (14/14).

Closes #2365

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (pnpm --filter @emdash-cms/admin typecheck — tsgo clean)
  • pnpm lint passes (type-aware oxlint on the changed files — clean; full-workspace lint not runnable on this machine, native build scripts unavailable)
  • pnpm test passes (or targeted tests for my change) — packages/admin vitest run tests/router.test.tsx: 14/14
  • pnpm format has been run (oxfmt — no reflow beyond the change)
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: n/a (bug fix)

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Fable 5 (Claude Code)

Screenshots / test output

❯ |chromium| tests/router.test.tsx (14 tests | 1 failed)   ← unpatched
    × shows a toast with the server's message on a slug conflict (and stays on /new)

❯ |chromium| tests/router.test.tsx (14 tests)              ← patched
 Test Files  1 passed (1)
      Tests  14 passed (14)

Related follow-up (deliberately NOT in this PR — behavior change): the server's generateUniqueSlug auto-suffixing never runs on normal creates because the admin always sends its client-side slug; omitting slug when the editor hasn't touched the field would make this collision a non-event. Flagged in #2365 for maintainer input.

@changeset-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b713423

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
@emdash-cms/admin Patch
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/plugin-mcp-smoke Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet area/admin size/M labels Aug 7, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@2366

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@2366

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@2366

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@2366

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@2366

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@2366

emdash

npm i https://pkg.pr.new/emdash@2366

create-emdash

npm i https://pkg.pr.new/create-emdash@2366

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@2366

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@2366

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@2366

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@2366

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@2366

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@2366

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@2366

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@2366

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@2366

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@2366

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@2366

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@2366

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@2366

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@2366

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@2366

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@2366

commit: b713423

A rejected create (e.g. the 409 SLUG_CONFLICT when the auto-generated
slug collides with an existing entry) was fully silent: createMutation
had no onError, ContentNewPage had no toast manager, and the QueryClient
has no global mutation error handler — the thrown Error (carrying the
server's human-readable message) died in mutation state, the Save button
reset, and the editor stayed on /new with zero feedback. Every other
mutation in router.tsx surfaces failures; only the create path lacked a
handler.

The handler follows the settings-components pattern (useKumoToastManager
+ variant: "error") rather than Toast.useToastManager + type: "error":
Kumo styles toast severity off variant (danger ring + error icon), while
Base UI's type field is inert for styling — verified by rendering both.

The regression test drives the real route with a mocked 409 SLUG_CONFLICT
response and asserts the toast title, the server's message, the error
affordance (the variant-driven toast icon), and that the router stays on
/content/posts/new (fails unpatched: 1/14; passes patched: 14/14).
@edrpls
edrpls force-pushed the fix/content-create-error-toast branch from 65d0be0 to b713423 Compare August 7, 2026 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Admin: creating an entry whose slug collides fails silently — no toast, no error, Save just resets

1 participant