mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 14:54:37 +00:00
Workflow Management Reworked (#1406)
* Merge temp userfile Basic migration Remove deprecated isFavourite Rename nit nit Rework open/load Refactor save Refactor delete Remove workflow dep on manager WIP Change map to record Fix directory nit isActive Move nit Add unload Add close workflow Remove workflowManager.closeWorkflow nit Remove workflowManager.storePrompt move from commandStore move more from commandStore nit Use workflowservice nit nit implement setWorkflow nit Remove workflows.ts Fix strict errors nit nit Resolves circular dep nit nit Fix workflow switching Add openworkflowPaths Fix store Fix key Serialize by default Fix proxy nit Update path Proper sync Fix tabs WIP nit Resolve merge conflict Fix userfile store tests Update jest test Update tabs patch tests Fix changeTracker init Move insert to service nit Fix insert nit Handle bookmark rename Refactor tests Add delete workflow Add test on deleting workflow Add closeWorkflow tests nit * Fix path * Move load next/previous * Move logic from store to service * nit * nit * nit * nit * nit * Add ChangeTracker.initialState * ChangeTracker load/unload * Remove app.changeWorkflow * Hook to app.ts * Changetracker restore * nit * nit * nit * Add debug logs * Remove unnecessary checkState on graphLoad * nit * Fix strict * Fix temp workflow name * Track ismodified * Fix reactivity * nit * Fix graph equal * nit * update test * nit * nit * Fix modified state * nit * Fix modified state * Sidebar force close * tabs force close * Fix save * Add load remote workflow test * Force save * Add save test * nit * Correctly handle delete last opened workflow * nit * Fix workflow rename * Fix save * Fix tests * Fix strict * Update playwright tests * Fix filename conflict handling * nit * Merge temporary and persisted ref * Update playwright expectations * nit * nit * Fix saveAs * Add playwright test * nit
This commit is contained in:
@@ -25,7 +25,7 @@ import { ComfyNodeDef, StatusWsMessageStatus } from '@/types/apiTypes'
|
||||
import { adjustColor, ColorAdjustOptions } from '@/utils/colorUtil'
|
||||
import { ComfyAppMenu } from './ui/menu/index'
|
||||
import { getStorageValue } from './utils'
|
||||
import { ComfyWorkflowManager, ComfyWorkflow } from './workflows'
|
||||
import { ComfyWorkflow, useWorkflowStore } from '@/stores/workflowStore'
|
||||
import {
|
||||
LGraphCanvas,
|
||||
LGraph,
|
||||
@@ -58,6 +58,7 @@ import { KeyComboImpl, useKeybindingStore } from '@/stores/keybindingStore'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { shallowReactive } from 'vue'
|
||||
import { type IBaseWidget } from '@comfyorg/litegraph/dist/types/widgets'
|
||||
import { workflowService } from '@/services/workflowService'
|
||||
|
||||
export const ANIM_PREVIEW_WIDGET = '$$comfy_animation_preview'
|
||||
|
||||
@@ -141,7 +142,6 @@ export class ComfyApp {
|
||||
multiUserServer: boolean
|
||||
ctx: CanvasRenderingContext2D
|
||||
widgets: Record<string, ComfyWidgetConstructor>
|
||||
workflowManager: ComfyWorkflowManager
|
||||
bodyTop: HTMLElement
|
||||
bodyLeft: HTMLElement
|
||||
bodyRight: HTMLElement
|
||||
@@ -170,7 +170,6 @@ export class ComfyApp {
|
||||
this.vueAppReady = false
|
||||
this.ui = new ComfyUI(this)
|
||||
this.logging = new ComfyLogging(this)
|
||||
this.workflowManager = new ComfyWorkflowManager(this)
|
||||
this.bodyTop = $el('div.comfyui-body-top', { parent: document.body })
|
||||
this.bodyLeft = $el('div.comfyui-body-left', { parent: document.body })
|
||||
this.bodyRight = $el('div.comfyui-body-right', { parent: document.body })
|
||||
@@ -1789,7 +1788,7 @@ export class ComfyApp {
|
||||
this.resizeCanvas()
|
||||
|
||||
await Promise.all([
|
||||
this.workflowManager.loadWorkflows(),
|
||||
useWorkspaceStore().workflow.syncWorkflows(),
|
||||
this.ui.settings.load()
|
||||
])
|
||||
await this.#loadExtensions()
|
||||
@@ -2160,21 +2159,6 @@ export class ComfyApp {
|
||||
})
|
||||
}
|
||||
|
||||
async changeWorkflow(callback, workflow = null) {
|
||||
try {
|
||||
this.workflowManager.activeWorkflow?.changeTracker?.store()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
await callback()
|
||||
try {
|
||||
this.workflowManager.setWorkflow(workflow)
|
||||
this.workflowManager.activeWorkflow?.track()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
async loadGraphData(
|
||||
graphData?: ComfyWorkflowJSON,
|
||||
clean: boolean = true,
|
||||
@@ -2198,12 +2182,6 @@ export class ComfyApp {
|
||||
graphData = structuredClone(graphData)
|
||||
}
|
||||
|
||||
try {
|
||||
this.workflowManager.setWorkflow(workflow)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
if (useSettingStore().get('Comfy.Validation.Workflows')) {
|
||||
// TODO: Show validation error in a dialog.
|
||||
const validatedGraphData = await validateComfyWorkflow(
|
||||
@@ -2217,6 +2195,8 @@ export class ComfyApp {
|
||||
graphData = validatedGraphData ?? graphData
|
||||
}
|
||||
|
||||
workflowService.beforeLoadNewGraph()
|
||||
|
||||
const missingNodeTypes: MissingNodeType[] = []
|
||||
const missingModels = []
|
||||
await this.#invokeExtensionsAsync(
|
||||
@@ -2270,12 +2250,6 @@ export class ComfyApp {
|
||||
this.canvas.ds.offset = graphData.extra.ds.offset
|
||||
this.canvas.ds.scale = graphData.extra.ds.scale
|
||||
}
|
||||
|
||||
try {
|
||||
this.workflowManager.activeWorkflow?.track()
|
||||
} catch (error) {
|
||||
// TODO: Do we want silently fail here?
|
||||
}
|
||||
} catch (error) {
|
||||
let errorHint = []
|
||||
// Try extracting filename to see if it was caused by an extension script
|
||||
@@ -2384,6 +2358,8 @@ export class ComfyApp {
|
||||
this.#showMissingModelsError(missingModels, paths)
|
||||
}
|
||||
await this.#invokeExtensionsAsync('afterConfigureGraph', missingNodeTypes)
|
||||
// @ts-expect-error zod types issue. Will be fixed after we enable ts-strict
|
||||
workflowService.afterLoadNewGraph(workflow, this.graph.serialize())
|
||||
requestAnimationFrame(() => {
|
||||
this.graph.setDirtyCanvas(true, true)
|
||||
})
|
||||
@@ -2602,9 +2578,11 @@ export class ComfyApp {
|
||||
this.canvas.draw(true, true)
|
||||
} else {
|
||||
try {
|
||||
this.workflowManager.storePrompt({
|
||||
useExecutionStore().storePrompt({
|
||||
id: res.prompt_id,
|
||||
nodes: Object.keys(p.output)
|
||||
nodes: Object.keys(p.output),
|
||||
workflow: useWorkspaceStore().workflow
|
||||
.activeWorkflow as ComfyWorkflow
|
||||
})
|
||||
} catch (error) {}
|
||||
}
|
||||
@@ -2678,9 +2656,12 @@ export class ComfyApp {
|
||||
} else if (pngInfo?.prompt) {
|
||||
this.loadApiJson(JSON.parse(pngInfo.prompt), fileName)
|
||||
} else if (pngInfo?.parameters) {
|
||||
this.changeWorkflow(() => {
|
||||
importA1111(this.graph, pngInfo.parameters)
|
||||
}, fileName)
|
||||
// Note: Not putting this in `importA1111` as it is mostly not used
|
||||
// by external callers, and `importA1111` has no access to `app`.
|
||||
workflowService.beforeLoadNewGraph()
|
||||
importA1111(this.graph, pngInfo.parameters)
|
||||
// @ts-expect-error zod type issue on ComfyWorkflowJSON. Should be resolved after enabling ts-strict globally.
|
||||
workflowService.afterLoadNewGraph(fileName, this.serializeGraph())
|
||||
} else {
|
||||
this.showErrorOnFileLoad(file)
|
||||
}
|
||||
@@ -2764,6 +2745,8 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
loadApiJson(apiData, fileName: string) {
|
||||
workflowService.beforeLoadNewGraph()
|
||||
|
||||
const missingNodeTypes = Object.values(apiData).filter(
|
||||
// @ts-expect-error
|
||||
(n) => !LiteGraph.registered_node_types[n.class_type]
|
||||
@@ -2786,40 +2769,38 @@ export class ComfyApp {
|
||||
app.graph.add(node)
|
||||
}
|
||||
|
||||
this.changeWorkflow(() => {
|
||||
for (const id of ids) {
|
||||
const data = apiData[id]
|
||||
const node = app.graph.getNodeById(id)
|
||||
for (const input in data.inputs ?? {}) {
|
||||
const value = data.inputs[input]
|
||||
if (value instanceof Array) {
|
||||
const [fromId, fromSlot] = value
|
||||
const fromNode = app.graph.getNodeById(fromId)
|
||||
let toSlot = node.inputs?.findIndex((inp) => inp.name === input)
|
||||
if (toSlot == null || toSlot === -1) {
|
||||
try {
|
||||
// Target has no matching input, most likely a converted widget
|
||||
const widget = node.widgets?.find((w) => w.name === input)
|
||||
// @ts-expect-error
|
||||
if (widget && node.convertWidgetToInput?.(widget)) {
|
||||
toSlot = node.inputs?.length - 1
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
if (toSlot != null || toSlot !== -1) {
|
||||
fromNode.connect(fromSlot, node, toSlot)
|
||||
}
|
||||
} else {
|
||||
const widget = node.widgets?.find((w) => w.name === input)
|
||||
if (widget) {
|
||||
widget.value = value
|
||||
widget.callback?.(value)
|
||||
}
|
||||
for (const id of ids) {
|
||||
const data = apiData[id]
|
||||
const node = app.graph.getNodeById(id)
|
||||
for (const input in data.inputs ?? {}) {
|
||||
const value = data.inputs[input]
|
||||
if (value instanceof Array) {
|
||||
const [fromId, fromSlot] = value
|
||||
const fromNode = app.graph.getNodeById(fromId)
|
||||
let toSlot = node.inputs?.findIndex((inp) => inp.name === input)
|
||||
if (toSlot == null || toSlot === -1) {
|
||||
try {
|
||||
// Target has no matching input, most likely a converted widget
|
||||
const widget = node.widgets?.find((w) => w.name === input)
|
||||
// @ts-expect-error
|
||||
if (widget && node.convertWidgetToInput?.(widget)) {
|
||||
toSlot = node.inputs?.length - 1
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
if (toSlot != null || toSlot !== -1) {
|
||||
fromNode.connect(fromSlot, node, toSlot)
|
||||
}
|
||||
} else {
|
||||
const widget = node.widgets?.find((w) => w.name === input)
|
||||
if (widget) {
|
||||
widget.value = value
|
||||
widget.callback?.(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
app.graph.arrange()
|
||||
}, fileName)
|
||||
}
|
||||
app.graph.arrange()
|
||||
|
||||
for (const id of ids) {
|
||||
const data = apiData[id]
|
||||
@@ -2854,6 +2835,9 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
app.graph.arrange()
|
||||
|
||||
// @ts-expect-error zod type issue on ComfyWorkflowJSON. Should be resolved after enabling ts-strict globally.
|
||||
workflowService.afterLoadNewGraph(fileName, this.serializeGraph())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user