fix(admin): refetch content after save/publish on non-i18n sites (#1557)#1568
Conversation
…ash-cms#1557) The content editor reads the item under a query key scoped to the active locale (undefined when i18n is off), but the save/publish/unpublish/discard/ schedule mutations invalidated a key scoped to rawItem.locale (the DB default "en"). React Query's partial matcher never matched, so the item was never refetched and the "Publish changes" / "Unpublish" buttons stayed stale until a hard refresh. Invalidate by (collection, id) prefix so it matches regardless of locale. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 18f6467 The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
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 |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
This is a focused, well-explained bug fix with a sound approach and solid test coverage.
Approach. The root cause is correctly diagnosed: the editor reads the content item with a React Query key that includes { locale: activeLocale }, but on non-i18n sites activeLocale is undefined; the save/publish mutations invalidated with { locale: rawItem?.locale ?? activeLocale } (which falls back to the DB default "en"), so React Query never matched the active query and the buttons stayed stale. Changing the invalidation to the ["content", collection, id] prefix is the right fix: it matches the locale-scoped read query regardless of whether activeLocale is undefined or a real locale, and because translations are separate rows with separate IDs, the id is already unique enough that the locale object is unnecessary for invalidation precision.
What I checked.
ContentEditPagereads withqueryKey: ["content", collection, id, { locale: activeLocale }]and the six mutations now invalidate withqueryKey: ["content", collection, id]. React Query v5 (5.90.21) matches by prefix by default, so this invalidates the active query.- The prefix is not over-broad: the list query uses
["content", collection], which is shorter and therefore is not matched by the item prefix. ContentEditorderives the publish button fromgetDraftStatus(item)(i.e.,liveRevisionIdvsdraftRevisionId), so the test fixtures correctly model the two reported symptoms.- No other
invalidateQueriesin the admin source uses the old["content", collection, id, { locale: ... }]shape, so the fix is complete for this bug. - The repro test renders the real router/editor (not a mocked
ContentEditor), exercises both the publish and save flows, and deliberately returns a "clean" PUT response so the button only appears from the invalidated GET refetch. - AGENTS.md conventions are respected: no new UI strings; only existing Lingui messages are used; Tailwind/i18n/authorization/SQL concerns don't apply; a changeset is present and user-focused.
I don't see any blocking issues. The changeset is well-written, the tests target the exact cache-key mismatch, and the fix is minimal and consistent across all six content mutations.
What does this PR do?
Fixes the publish/save controls going stale after editing a published post, as reported in #1557. After saving a title change, the "Publish changes" button now appears immediately (previously it only showed after a hard refresh), and after publishing, the button immediately flips to "Unpublish" (previously it stayed on "Publish changes").
Root cause: the editor reads the content item under a React Query key scoped to the active locale — which is
undefinedwhen i18n is not configured (router.tsx,ContentEditPage). The save/publish/unpublish/discard/schedule mutations, however, invalidated a key scoped torawItem.locale, which is the database default"en"even on non-i18n sites. React Query's partial matcher compares{ locale: undefined }against{ locale: "en" }, finds no match, and never refetches the item — so the draft-status pointers (liveRevisionId/draftRevisionId) the buttons key off stay stale until a manual refresh. This is why both reporters see it "since forever": it triggers on any site without i18n enabled.Fix: invalidate by the
["content", collection, id]prefix (dropping the locale object) in all six content mutations. Theidalready uniquely identifies the row (translations are separate rows), so the locale object was redundant for uniqueness — and a prefix match correctly refetches the item regardless of which locale tab is active.Closes #1557.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.ponot touched.AI-generated code disclosure
Screenshots / test output
New test
packages/admin/tests/publish-button-locale.test.tsxrenders the realContentEditorthrough the router with i18n off and covers both reported symptoms:flips 'Publish changes' to 'Unpublish' after a successful publishshows 'Publish changes' after editing the title and savingBoth fail on
main(button never updates) and pass with this fix. Verified red→green by reverting only the invalidation-key change. Full admin suite: 1015/1016 pass (the one unrelated failure, aMediaPickerModalURL-probe timing test, passes in isolation and is not touched by this change).