[Refactor] Extract workflow/workflow tabs restore into a composable (#2350)

This commit is contained in:
Chenlei Hu
2025-01-25 16:58:50 -05:00
committed by GitHub
parent 38b8a68e50
commit 2852720b2c
2 changed files with 137 additions and 110 deletions

View File

@@ -54,25 +54,24 @@ import SideToolbar from '@/components/sidebar/SideToolbar.vue'
import SecondRowWorkflowTabs from '@/components/topbar/SecondRowWorkflowTabs.vue'
import { CORE_SETTINGS } from '@/constants/coreSettings'
import { usePragmaticDroppable } from '@/hooks/dndHooks'
import { useWorkflowPersistence } from '@/hooks/workflowPersistenceHooks'
import { i18n } from '@/i18n'
import { api } from '@/scripts/api'
import { app as comfyApp } from '@/scripts/app'
import { ChangeTracker } from '@/scripts/changeTracker'
import { getStorageValue, setStorageValue } from '@/scripts/utils'
import { IS_CONTROL_WIDGET, updateControlWidgetLabel } from '@/scripts/widgets'
import { useColorPaletteService } from '@/services/colorPaletteService'
import { useLitegraphService } from '@/services/litegraphService'
import { useWorkflowService } from '@/services/workflowService'
import { useCommandStore } from '@/stores/commandStore'
import { useCanvasStore } from '@/stores/graphStore'
import { ComfyModelDef, useModelStore } from '@/stores/modelStore'
import { ComfyModelDef } from '@/stores/modelStore'
import {
ModelNodeProvider,
useModelToNodeStore
} from '@/stores/modelToNodeStore'
import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import { useSettingStore } from '@/stores/settingStore'
import { useWorkflowStore } from '@/stores/workflowStore'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import type { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
@@ -96,29 +95,6 @@ const canvasMenuEnabled = computed(() =>
)
const tooltipEnabled = computed(() => settingStore.get('Comfy.EnableTooltips'))
const storedWorkflows = JSON.parse(
getStorageValue('Comfy.OpenWorkflowsPaths') || '[]'
)
const storedActiveIndex = JSON.parse(
getStorageValue('Comfy.ActiveWorkflowIndex') || '-1'
)
const openWorkflows = computed(() => workspaceStore?.workflow?.openWorkflows)
const activeWorkflow = computed(() => workspaceStore?.workflow?.activeWorkflow)
const restoreState = computed<{ paths: string[]; activeIndex: number }>(() => {
if (!openWorkflows.value || !activeWorkflow.value) {
return { paths: [], activeIndex: -1 }
}
const paths = openWorkflows.value
.filter((workflow) => workflow?.isPersisted && !workflow.isModified)
.map((workflow) => workflow.path)
const activeIndex = openWorkflows.value.findIndex(
(workflow) => workflow.path === activeWorkflow.value?.path
)
return { paths, activeIndex }
})
watchEffect(() => {
const canvasInfoEnabled = settingStore.get('Comfy.Graph.CanvasInfo')
if (canvasStore.canvas) {
@@ -270,27 +246,6 @@ watch(
}
)
const workflowStore = useWorkflowStore()
const persistCurrentWorkflow = () => {
const workflow = JSON.stringify(comfyApp.serializeGraph())
localStorage.setItem('workflow', workflow)
if (api.clientId) {
sessionStorage.setItem(`workflow:${api.clientId}`, workflow)
}
}
watchEffect(() => {
if (workflowStore.activeWorkflow) {
const workflow = workflowStore.activeWorkflow
setStorageValue('Comfy.PreviousWorkflow', workflow.key)
// When the activeWorkflow changes, the graph has already been loaded.
// Saving the current state of the graph to the localStorage.
persistCurrentWorkflow()
}
})
api.addEventListener('graphChanged', persistCurrentWorkflow)
usePragmaticDroppable(() => canvasRef.value, {
onDrop: (event) => {
const loc = event.location.current.input
@@ -360,57 +315,9 @@ const loadCustomNodesI18n = async () => {
}
}
const loadWorkflowFromStorage = async (json: string, workflowName: string) => {
if (!json) return false
const workflow = JSON.parse(json)
await comfyApp.loadGraphData(workflow, true, true, workflowName)
return true
}
const loadPreviousWorkflowFromStorage = async () => {
const workflowName = getStorageValue('Comfy.PreviousWorkflow')
const clientId = api.initialClientId ?? api.clientId
// Try loading from session storage first
if (clientId) {
const sessionWorkflow = sessionStorage.getItem(`workflow:${clientId}`)
if (await loadWorkflowFromStorage(sessionWorkflow, workflowName)) {
return true
}
}
// Fall back to local storage
const localWorkflow = localStorage.getItem('workflow')
return await loadWorkflowFromStorage(localWorkflow, workflowName)
}
const loadDefaultWorkflow = async () => {
const settingStore = useSettingStore()
if (!settingStore.get('Comfy.TutorialCompleted')) {
await settingStore.set('Comfy.TutorialCompleted', true)
// Load model folders to ensure the missing models' corresponding folders
// can be correctly identified.
await useModelStore().loadModelFolders()
await useWorkflowService().loadTutorialWorkflow()
} else {
await comfyApp.loadGraphData()
}
}
const restorePreviousWorkflow = async () => {
try {
const restored = await loadPreviousWorkflowFromStorage()
if (!restored) {
await loadDefaultWorkflow()
}
} catch (err) {
console.error('Error loading previous workflow', err)
await loadDefaultWorkflow()
}
}
const comfyAppReady = ref(false)
const workflowPersistence = useWorkflowPersistence()
onMounted(async () => {
// Backward compatible
// Assign all properties of lg to window
@@ -450,19 +357,9 @@ onMounted(async () => {
'Comfy.CustomColorPalettes'
)
// Restore workflow from storage
await restorePreviousWorkflow()
const isRestorable = storedWorkflows?.length > 0 && storedActiveIndex >= 0
if (isRestorable)
workflowStore.openWorkflowsInBackground({
left: storedWorkflows.slice(0, storedActiveIndex),
right: storedWorkflows.slice(storedActiveIndex)
})
watch(restoreState, ({ paths, activeIndex }) => {
setStorageValue('Comfy.OpenWorkflowsPaths', JSON.stringify(paths))
setStorageValue('Comfy.ActiveWorkflowIndex', JSON.stringify(activeIndex))
})
// Restore workflow and workflow tabs state from storage
await workflowPersistence.restorePreviousWorkflow()
workflowPersistence.restoreWorkflowTabsState()
// Start watching for locale change after the initial value is loaded.
watch(

View File

@@ -0,0 +1,130 @@
import { computed, watch, watchEffect } from 'vue'
import { api } from '@/scripts/api'
import { app as comfyApp } from '@/scripts/app'
import { getStorageValue, setStorageValue } from '@/scripts/utils'
import { useWorkflowService } from '@/services/workflowService'
import { useModelStore } from '@/stores/modelStore'
import { useSettingStore } from '@/stores/settingStore'
import { useWorkflowStore } from '@/stores/workflowStore'
export function useWorkflowPersistence() {
const workflowStore = useWorkflowStore()
const settingStore = useSettingStore()
const persistCurrentWorkflow = () => {
const workflow = JSON.stringify(comfyApp.serializeGraph())
localStorage.setItem('workflow', workflow)
if (api.clientId) {
sessionStorage.setItem(`workflow:${api.clientId}`, workflow)
}
}
const loadWorkflowFromStorage = async (
json: string | null,
workflowName: string | null
) => {
if (!json) return false
const workflow = JSON.parse(json)
await comfyApp.loadGraphData(workflow, true, true, workflowName)
return true
}
const loadPreviousWorkflowFromStorage = async () => {
const workflowName = getStorageValue('Comfy.PreviousWorkflow')
const clientId = api.initialClientId ?? api.clientId
// Try loading from session storage first
if (clientId) {
const sessionWorkflow = sessionStorage.getItem(`workflow:${clientId}`)
if (await loadWorkflowFromStorage(sessionWorkflow, workflowName)) {
return true
}
}
// Fall back to local storage
const localWorkflow = localStorage.getItem('workflow')
return await loadWorkflowFromStorage(localWorkflow, workflowName)
}
const loadDefaultWorkflow = async () => {
if (!settingStore.get('Comfy.TutorialCompleted')) {
await settingStore.set('Comfy.TutorialCompleted', true)
await useModelStore().loadModelFolders()
await useWorkflowService().loadTutorialWorkflow()
} else {
await comfyApp.loadGraphData()
}
}
const restorePreviousWorkflow = async () => {
try {
const restored = await loadPreviousWorkflowFromStorage()
if (!restored) {
await loadDefaultWorkflow()
}
} catch (err) {
console.error('Error loading previous workflow', err)
await loadDefaultWorkflow()
}
}
// Setup watchers
watchEffect(() => {
if (workflowStore.activeWorkflow) {
const workflow = workflowStore.activeWorkflow
setStorageValue('Comfy.PreviousWorkflow', workflow.key)
// When the activeWorkflow changes, the graph has already been loaded.
// Saving the current state of the graph to the localStorage.
persistCurrentWorkflow()
}
})
api.addEventListener('graphChanged', persistCurrentWorkflow)
// Restore workflow tabs states
const openWorkflows = computed(() => workflowStore.openWorkflows)
const activeWorkflow = computed(() => workflowStore.activeWorkflow)
const restoreState = computed<{ paths: string[]; activeIndex: number }>(
() => {
if (!openWorkflows.value || !activeWorkflow.value) {
return { paths: [], activeIndex: -1 }
}
const paths = openWorkflows.value
.filter((workflow) => workflow?.isPersisted && !workflow.isModified)
.map((workflow) => workflow.path)
const activeIndex = openWorkflows.value.findIndex(
(workflow) => workflow.path === activeWorkflow.value?.path
)
return { paths, activeIndex }
}
)
// Get storage values before setting watchers
const storedWorkflows = JSON.parse(
getStorageValue('Comfy.OpenWorkflowsPaths') || '[]'
)
const storedActiveIndex = JSON.parse(
getStorageValue('Comfy.ActiveWorkflowIndex') || '-1'
)
watch(restoreState, ({ paths, activeIndex }) => {
setStorageValue('Comfy.OpenWorkflowsPaths', JSON.stringify(paths))
setStorageValue('Comfy.ActiveWorkflowIndex', JSON.stringify(activeIndex))
})
const restoreWorkflowTabsState = () => {
const isRestorable = storedWorkflows?.length > 0 && storedActiveIndex >= 0
if (isRestorable) {
workflowStore.openWorkflowsInBackground({
left: storedWorkflows.slice(0, storedActiveIndex),
right: storedWorkflows.slice(storedActiveIndex)
})
}
}
return {
restorePreviousWorkflow,
restoreWorkflowTabsState
}
}