fix(admin): prevent autosave from overwriting in-progress edits#272
fix(admin): prevent autosave from overwriting in-progress edits#272tasdemir wants to merge 1 commit intoemdash-cms:mainfrom
Conversation
When editing content fields (title, slug, excerpt, etc.) in the admin editor, user input was being silently reverted to server values. This made normal-speed editing nearly impossible — only rapid copy-paste would survive. Root cause: a circular data refresh loop between autosave and the form state synchronization effect: 1. User edits a field → local form state updates → isDirty becomes true 2. After 2s idle, autosave fires → sends current form data to server 3. Autosave onSuccess called invalidateQueries() for the content query 4. React Query refetched the content from the server 5. The form-sync useEffect depended on item.updatedAt, which changed on every server write (even autosave) 6. The effect unconditionally reset all form state (formData, slug, status, bylines) to the refetched server values 7. Any edits made between step 2 and step 6 were silently lost This was particularly noticeable on fields like slug and excerpt where users type at normal speed, but also affected the title and rich text body fields. Fix (two changes): 1. router.tsx — Remove invalidateQueries() from the autosave mutation's onSuccess callback. Autosave already sent the latest data to the server; there is no need to immediately refetch it back. The query cache refreshes naturally on manual save, page navigation, or window refocus (React Query default behavior). 2. ContentEditor.tsx — Remove item.updatedAt from the form-sync useEffect's dependency array. The timestamp changes on every server write but carries no meaningful data change. The effect now only fires when actual content (itemDataString), slug, or status change, which correctly covers explicit actions like "Discard Draft" and "Restore Revision" while ignoring timestamp-only updates from autosave or refetch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@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-forms
@emdash-cms/plugin-webhook-notifier
commit: |
Summary
Fixes a bug where editing content fields (title, slug, excerpt, body) in the admin editor would silently revert user input to the previous server-stored values. Normal-speed typing was nearly impossible — only rapid copy-paste would survive the revert cycle.
Root Cause
A circular data refresh loop between autosave and the form state synchronization:
The
updatedAttimestamp changes on every server write, including autosave. So the form-sync effect fired after every autosave, unconditionally resetting all form state — even though the server data was identical to what the user already had (because autosave just sent it).Additionally, React Query's default
refetchOnWindowFocus: truecombined withstaleTime: 60smeant that even without autosave invalidation, any window focus event after 60 seconds would refetch and reset the form.Fix
Two changes, both in
packages/admin/:1.
src/router.tsx— RemoveinvalidateQueriesfrom autosaveonSuccessAutosave already sent the current form data to the server. There is no benefit to immediately refetching it back — and doing so triggers the form reset. The query cache refreshes naturally via:
updateMutationstill invalidates)staleTime)2.
src/components/ContentEditor.tsx— Removeitem?.updatedAtfrom useEffect depsThe form-sync effect's dependency array was
[item?.updatedAt, itemDataString, item?.slug, item?.status]. TheupdatedAttimestamp changes on every write but carries no meaningful content change. Removing it means the effect only fires when actual content changes:itemDataStringchanges?item?.slugchanges?Test Plan
🤖 Generated with Claude Code