diff --git a/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts b/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts index cdceb4736..8f13efe2c 100644 --- a/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts +++ b/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts @@ -1,5 +1,5 @@ -import { tryOnScopeDispose } from '@vueuse/core' -import { computed, watch } from 'vue' +import { tryOnScopeDispose, useDebounceFn } from '@vueuse/core' +import { computed, ref, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' import { @@ -47,12 +47,31 @@ export function useWorkflowPersistence() { settingStore.get('Comfy.Workflow.Persist') ) - const persistCurrentWorkflow = () => { + const lastSavedJsonByPath = ref>({}) + + const persistCurrentWorkflow = useDebounceFn(() => { if (!workflowPersistenceEnabled.value) return const activeWorkflow = workflowStore.activeWorkflow if (!activeWorkflow) return const graphData = comfyApp.rootGraph.serialize() const workflowJson = JSON.stringify(graphData) + const workflowPath = activeWorkflow.path + + if (workflowJson === lastSavedJsonByPath.value[workflowPath]) return + lastSavedJsonByPath.value[workflowPath] = workflowJson + + try { + workflowDraftStore.saveDraft(activeWorkflow.path, { + data: workflowJson, + updatedAt: Date.now(), + name: activeWorkflow.key, + isTemporary: activeWorkflow.isTemporary + }) + } catch (error) { + console.error('Failed to save draft', error) + // If draft store fails, don't continue saving to storage + return + } try { localStorage.setItem('workflow', workflowJson) @@ -81,14 +100,7 @@ export function useWorkflowPersistence() { workflowDraftStore.removeDraft(activeWorkflow.path) return } - - workflowDraftStore.saveDraft(activeWorkflow.path, { - data: workflowJson, - updatedAt: Date.now(), - name: activeWorkflow.key, - isTemporary: activeWorkflow.isTemporary - }) - } + }, 1_000) const loadPreviousWorkflowFromStorage = async () => { const workflowName = getStorageValue('Comfy.PreviousWorkflow') @@ -144,9 +156,11 @@ export function useWorkflowPersistence() { setStorageValue('Comfy.PreviousWorkflow', activeWorkflowKey) // When the activeWorkflow changes, the graph has already been loaded. // Saving the current state of the graph to the localStorage. + // Use debounced version to avoid immediate save on tab switch persistCurrentWorkflow() } ) + api.addEventListener('graphChanged', persistCurrentWorkflow) // Clean up event listener when component unmounts diff --git a/src/platform/workflow/persistence/stores/workflowDraftStore.ts b/src/platform/workflow/persistence/stores/workflowDraftStore.ts index a53d669a3..4098f8824 100644 --- a/src/platform/workflow/persistence/stores/workflowDraftStore.ts +++ b/src/platform/workflow/persistence/stores/workflowDraftStore.ts @@ -2,10 +2,12 @@ import { useStorage } from '@vueuse/core' import { defineStore } from 'pinia' import { computed } from 'vue' +import type { + DraftCacheState, + WorkflowDraftSnapshot +} from '@/platform/workflow/persistence/base/draftCache' import { - type DraftCacheState, MAX_DRAFTS, - type WorkflowDraftSnapshot, createDraftCacheState, mostRecentDraftPath, moveDraft as moveDraftEntry, @@ -43,7 +45,23 @@ export const useWorkflowDraftStore = defineStore('workflowDraft', () => { } const saveDraft = (path: string, snapshot: WorkflowDraftSnapshot) => { - updateState(upsertDraft(currentState(), path, snapshot, MAX_DRAFTS)) + try { + updateState(upsertDraft(currentState(), path, snapshot, MAX_DRAFTS)) + } catch (error) { + if ( + error instanceof DOMException && + error.name === 'QuotaExceededError' + ) { + const state = currentState() + if (state.order.length > 0) { + const oldestPath = state.order[0] + updateState(removeDraftEntry(state, oldestPath)) + updateState(upsertDraft(currentState(), path, snapshot, MAX_DRAFTS)) + } + } else { + throw error + } + } } const removeDraft = (path: string) => {