From 5f7a6e7aba7aadb133484e6208ec054aa2d0d9c6 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sat, 14 Feb 2026 02:50:05 -0800 Subject: [PATCH] fix: clear draft on workflow close to prevent stale state on reopen (#8854) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Clear the workflow draft from localStorage when any workflow tab is closed, preventing stale cached state from being served when the workflow is re-opened. ## Changes - **What**: `closeWorkflow()` in `workflowStore.ts` now calls `removeDraft()` for all workflows, not just temporary ones. `closeWorkflow()` in `workflowService.ts` removes the draft before switching tabs, preventing `beforeLoadNewGraph()` from re-saving it. ## Review Focus - Draft is removed before the tab switch in `workflowService.closeWorkflow()` to prevent `beforeLoadNewGraph()` from re-saving it during the switch - Crash recovery is preserved: drafts are only cleared on explicit close, not on unload/crash - Tab restore on restart is unaffected: drafts for intentionally-open tabs are saved on graph change events, not on close Fixes #8778 Fixes https://github.com/Comfy-Org/ComfyUI/issues/12323 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8854-fix-clear-draft-on-workflow-close-to-prevent-stale-state-on-reopen-3066d73d365081a2a633c9b352d0b0d1) by [Unito](https://www.unito.io) --- .../workflow/core/services/workflowService.ts | 2 + .../management/stores/workflowStore.test.ts | 38 +++++++++++++++++++ .../management/stores/workflowStore.ts | 4 +- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/platform/workflow/core/services/workflowService.ts b/src/platform/workflow/core/services/workflowService.ts index e2638d058a..c4647cc8ad 100644 --- a/src/platform/workflow/core/services/workflowService.ts +++ b/src/platform/workflow/core/services/workflowService.ts @@ -215,6 +215,8 @@ export const useWorkflowService = () => { } } + workflowDraftStore.removeDraft(workflow.path) + // If this is the last workflow, create a new default temporary workflow if (workflowStore.openWorkflows.length === 1) { await loadDefaultWorkflow() diff --git a/src/platform/workflow/management/stores/workflowStore.test.ts b/src/platform/workflow/management/stores/workflowStore.test.ts index f13daf21c0..22a153e1ca 100644 --- a/src/platform/workflow/management/stores/workflowStore.test.ts +++ b/src/platform/workflow/management/stores/workflowStore.test.ts @@ -12,6 +12,7 @@ import { useWorkflowBookmarkStore, useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore' +import { useWorkflowDraftStore } from '@/platform/workflow/persistence/stores/workflowDraftStore' import { api } from '@/scripts/api' import { app as comfyApp } from '@/scripts/app' import { defaultGraph, defaultGraphJSON } from '@/scripts/defaultGraph' @@ -911,4 +912,41 @@ describe('useWorkflowStore', () => { expect(mostRecent).toBeNull() }) }) + + describe('closeWorkflow draft cleanup', () => { + it('should remove draft for persisted workflows on close', async () => { + const draftStore = useWorkflowDraftStore() + await syncRemoteWorkflows(['a.json']) + const workflow = store.getWorkflowByPath('workflows/a.json')! + + draftStore.saveDraft('workflows/a.json', { + data: '{"dirty":true}', + updatedAt: Date.now(), + name: 'a.json', + isTemporary: false + }) + expect(draftStore.getDraft('workflows/a.json')).toBeDefined() + + await store.closeWorkflow(workflow) + + expect(draftStore.getDraft('workflows/a.json')).toBeUndefined() + }) + + it('should remove draft for temporary workflows on close', async () => { + const draftStore = useWorkflowDraftStore() + const workflow = store.createTemporary('temp.json') + + draftStore.saveDraft(workflow.path, { + data: '{"dirty":true}', + updatedAt: Date.now(), + name: 'temp.json', + isTemporary: true + }) + expect(draftStore.getDraft(workflow.path)).toBeDefined() + + await store.closeWorkflow(workflow) + + expect(draftStore.getDraft(workflow.path)).toBeUndefined() + }) + }) }) diff --git a/src/platform/workflow/management/stores/workflowStore.ts b/src/platform/workflow/management/stores/workflowStore.ts index fea16a993f..2faa542a21 100644 --- a/src/platform/workflow/management/stores/workflowStore.ts +++ b/src/platform/workflow/management/stores/workflowStore.ts @@ -320,11 +320,9 @@ export const useWorkflowStore = defineStore('workflow', () => { openWorkflowPaths.value = openWorkflowPaths.value.filter( (path) => path !== workflow.path ) + useWorkflowDraftStore().removeDraft(workflow.path) if (workflow.isTemporary) { - // Clear thumbnail when temporary workflow is closed clearThumbnail(workflow.key) - // Clear draft when unsaved workflow tab is closed - useWorkflowDraftStore().removeDraft(workflow.path) delete workflowLookup.value[workflow.path] } else { workflow.unload()