Skip to content

Commit 582e3c4

Browse files
committed
Restore draft on mount or when sessionId/editor changes
1 parent f347015 commit 582e3c4

2 files changed

Lines changed: 28 additions & 5 deletions

File tree

apps/array/src/renderer/features/message-editor/stores/draftStore.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { AvailableCommand } from "@agentclientprotocol/sdk";
2+
import { electronStorage } from "@renderer/lib/electronStorage";
23
import { create } from "zustand";
34
import { persist } from "zustand/middleware";
45
import { immer } from "zustand/middleware/immer";
@@ -52,16 +53,19 @@ export const useDraftStore = create<DraftStore>()(
5253
_hasHydrated: false,
5354

5455
actions: {
55-
setHasHydrated: (hydrated) => set({ _hasHydrated: hydrated }),
56+
setHasHydrated: (hydrated) => {
57+
set({ _hasHydrated: hydrated });
58+
},
5659

57-
setDraft: (sessionId, draft) =>
60+
setDraft: (sessionId, draft) => {
5861
set((state) => {
5962
if (draft === null) {
6063
delete state.drafts[sessionId];
6164
} else {
6265
state.drafts[sessionId] = draft;
6366
}
64-
}),
67+
});
68+
},
6569

6670
getDraft: (sessionId) => get().drafts[sessionId] ?? null,
6771

@@ -110,6 +114,7 @@ export const useDraftStore = create<DraftStore>()(
110114
})),
111115
{
112116
name: "message-editor-drafts",
117+
storage: electronStorage,
113118
partialize: (state) => ({ drafts: state.drafts }),
114119
onRehydrateStorage: () => (state) => {
115120
state?.actions.setHasHydrated(true);

apps/array/src/renderer/features/message-editor/tiptap/useDraftSync.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,27 @@ export function useDraftSync(
103103
context?: DraftContext,
104104
) {
105105
const hasRestoredRef = useRef(false);
106+
const lastSessionIdRef = useRef(sessionId);
107+
const lastEditorRef = useRef(editor);
106108
const editorRef = useRef(editor);
107109
editorRef.current = editor;
108110

109111
const draftActions = useDraftStore((s) => s.actions);
110112
const draft = useDraftStore((s) => s.drafts[sessionId] ?? null);
111113
const hasHydrated = useDraftStore((s) => s._hasHydrated);
112114

115+
// Reset restoration flag when sessionId changes (e.g., navigating between tasks)
116+
if (lastSessionIdRef.current !== sessionId) {
117+
lastSessionIdRef.current = sessionId;
118+
hasRestoredRef.current = false;
119+
}
120+
121+
// Reset restoration flag when editor instance changes (e.g., when disabled state changes)
122+
if (lastEditorRef.current !== editor && editor !== null) {
123+
lastEditorRef.current = editor;
124+
hasRestoredRef.current = false;
125+
}
126+
113127
// Set context for this session
114128
useLayoutEffect(() => {
115129
draftActions.setContext(sessionId, {
@@ -121,7 +135,7 @@ export function useDraftSync(
121135
};
122136
}, [sessionId, context?.taskId, context?.repoPath, draftActions]);
123137

124-
// Restore draft on mount
138+
// Restore draft on mount or when sessionId/editor changes
125139
useLayoutEffect(() => {
126140
if (!hasHydrated || !editor || hasRestoredRef.current) return;
127141
if (!draft || isContentEmpty(draft)) return;
@@ -137,14 +151,18 @@ export function useDraftSync(
137151

138152
const saveDraft = useCallback(
139153
(e: Editor) => {
154+
// Don't save until store has hydrated from storage
155+
// This prevents overwriting stored drafts with empty content before restoration
156+
if (!hasHydrated) return;
157+
140158
const json = e.getJSON();
141159
const content = tiptapJsonToEditorContent(json);
142160
draftActions.setDraft(
143161
sessionId,
144162
isContentEmpty(content) ? null : content,
145163
);
146164
},
147-
[sessionId, draftActions],
165+
[sessionId, draftActions, hasHydrated],
148166
);
149167

150168
const clearDraft = useCallback(() => {

0 commit comments

Comments
 (0)