From dece40fd5e8831602c744b8d3aa3fee069b6dddf Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 27 Sep 2026 22:20:33 -0500 Subject: [PATCH] fix(ui): settle restored draft submissions only once Co-Authored-By: Paperclip --- ui/src/components/IssueChatThread.test.tsx | 51 ++++++++++++++++++++++ ui/src/components/IssueChatThread.tsx | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/ui/src/components/IssueChatThread.test.tsx b/ui/src/components/IssueChatThread.test.tsx index 82268181708..cfccdd5d7ad 100644 --- a/ui/src/components/IssueChatThread.test.tsx +++ b/ui/src/components/IssueChatThread.test.tsx @@ -3276,6 +3276,57 @@ describe("IssueChatThread", () => { act(() => root.unmount()); }); + it("settles a restored submission only once through StrictMode effect replay", () => { + const key = "strict-restored-submission"; + const attemptId = "aaf8228f-0be7-45ae-a104-6fbe0af6f1d3"; + const submitted = "One text-only save interrupted by reload."; + const nextDraft = "A newer draft written while delivery was pending."; + localStorage.setItem(key, `${submitted}\n\n${nextDraft}`); + localStorage.setItem(`${key}:submission:v1`, JSON.stringify({ + version: 1, + draftKey: key, + attemptId, + reviewed: false, + nextDraftOffset: submitted.length + 2, + submittedAttachmentIds: [], + })); + const root = createRoot(container); + try { + act(() => root.render( + + + {}} + draftKey={key} + enableLiveTranscriptPolling={false} + /> + + , + )); + expect(container.querySelector( + 'textarea[aria-label="Issue chat editor"]', + )?.value).toBe(nextDraft); + expect(localStorage.getItem(key)).toBe(nextDraft); + expect(localStorage.getItem(`${key}:submission:v1`)).toBeNull(); + expect(container.textContent).not.toContain("We couldn’t confirm"); + } finally { + act(() => root.unmount()); + } + expect(localStorage.getItem(key)).toBe(nextDraft); + }); + it("stores and restores the composer draft per issue key", () => { vi.useFakeTimers(); const root = createRoot(container); diff --git a/ui/src/components/IssueChatThread.tsx b/ui/src/components/IssueChatThread.tsx index cd1c4d5b0e4..5d8d2412b53 100644 --- a/ui/src/components/IssueChatThread.tsx +++ b/ui/src/components/IssueChatThread.tsx @@ -4824,7 +4824,7 @@ const IssueChatComposer = forwardRef< if (!uncertainSubmission || !confirmedSubmissionIds.has(uncertainSubmission.attemptId)) return; const nextDraft = uncertainSubmission.nextDraftOffset === undefined ? "" : bodyRef.current.slice(uncertainSubmission.nextDraftOffset); - if (draftKey) settleDraftSubmission(draftKey, uncertainSubmission.attemptId, nextDraft); + if (draftKey && !settleDraftSubmission(draftKey, uncertainSubmission.attemptId, nextDraft)) return; setUncertainSubmission(null); setBody(nextDraft); bodyRef.current = nextDraft;