mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-16 19:29:26 +02:00
fix(editor): don't wipe in-flight uploads on external content sync
When a brand-new chat's first file upload triggers lazy session creation, `setActiveSession(null → uuid)` flips ChatInput's draft key mid-upload, which changes `defaultValue` to the new (empty) session draft. ContentEditor's "sync external defaultValue" effect then ran `setContent` over a document that still held the `uploading` image/fileCard node, wiping it — so the upload's finalize could no longer find the node. The file vanished and the draft was left with an empty `!file[name]()`. The editor was never remounted (instance stays alive); the node was removed by the content-sync effect. An uploading node is local state an external sync must not overwrite, exactly like the existing dirty/focused guards. Add a guard that bails the sync while any `uploading` node is present. Pure frontend; affects only the first upload in a new chat (subsequent uploads hit an existing session, so no draft-key flip). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -384,6 +384,21 @@ const ContentEditor = forwardRef<ContentEditorRef, ContentEditorProps>(
|
||||
useEffect(() => {
|
||||
if (!editor || editor.isDestroyed) return;
|
||||
|
||||
// Guard 0: never clobber an in-flight upload. An external `defaultValue`
|
||||
// change can arrive mid-upload — e.g. chat lazy-creates a session on the
|
||||
// first file upload, which flips `activeSessionId` → the draft key →
|
||||
// `defaultValue`. If we `setContent` over a document that still holds an
|
||||
// `uploading` image/fileCard node, that node is wiped and the upload's
|
||||
// finalize can no longer find it (the file vanishes, leaving an empty
|
||||
// `!file[name]()`). Like the dirty guards below, an uploading node is
|
||||
// local state that an external sync must not overwrite.
|
||||
let hasUploadingNode = false;
|
||||
editor.state.doc.descendants((node) => {
|
||||
if (node.attrs.uploading) hasUploadingNode = true;
|
||||
return !hasUploadingNode;
|
||||
});
|
||||
if (hasUploadingNode) return;
|
||||
|
||||
const current = stripBlobUrls(editor.getMarkdown()).trimEnd();
|
||||
// "Dirty" = user has local edits not yet flushed through the debounced
|
||||
// `onUpdate`. `lastEmittedRef` is advanced only after a debounce fire,
|
||||
|
||||
Reference in New Issue
Block a user