mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-01 03:31:58 +00:00
fix: Prevent corruption of workflow data due to checkState during graph loading (#9531)
## Summary
During workflow loading, the workflow data & active workflow object can
be out of sync, meaning any checkState calls will overwrite data into
the wrong workflow.
Recreation steps:
* Open 2-3 workflows
* Enter builder mode > select step
* Select some different inputs on each
* Quickly tap the shift key (this triggers checkState) while switching
tabs
* After a while, you'll see the wrong inputs on the workflows
Alternatively, register an extension that guarantees to call checkState
during the bad phase, run this in browser devtools and switch tabs:
```
window.app.registerExtension({
name: 'bad',
async afterConfigureGraph() {
window.app.extensionManager.workflow.activeWorkflow.changeTracker.checkState()
}
})
```
## Changes
- **What**:
- Add loading graph flag
- Prevent checkState calls while loading
- Prevent app mode data sync while loading
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9531-fix-Prevent-corruption-of-workflow-data-due-to-checkState-during-graph-loading-31c6d73d365081e2ab91d9145bf1d025)
by [Unito](https://www.unito.io)
This commit is contained in:
@@ -9,6 +9,7 @@ import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||
import { flushScheduledSlotLayoutSync } from '@/renderer/extensions/vueNodes/composables/useSlotElementTracking'
|
||||
|
||||
import { st, t } from '@/i18n'
|
||||
import { ChangeTracker } from '@/scripts/changeTracker'
|
||||
import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces'
|
||||
import {
|
||||
LGraph,
|
||||
@@ -1306,6 +1307,8 @@ export class ComfyApp {
|
||||
}
|
||||
}
|
||||
|
||||
ChangeTracker.isLoadingGraph = true
|
||||
try {
|
||||
try {
|
||||
// @ts-expect-error Discrepancies between zod and litegraph - in progress
|
||||
this.rootGraph.configure(graphData)
|
||||
@@ -1376,7 +1379,9 @@ export class ComfyApp {
|
||||
values.length > 0 &&
|
||||
(widget.value == null ||
|
||||
(reset_invalid_values &&
|
||||
!values.includes(widget.value as string | number | boolean)))
|
||||
!values.includes(
|
||||
widget.value as string | number | boolean
|
||||
)))
|
||||
) {
|
||||
widget.value = values[0]
|
||||
}
|
||||
@@ -1436,6 +1441,9 @@ export class ComfyApp {
|
||||
requestAnimationFrame(() => {
|
||||
this.canvas.setDirty(true, true)
|
||||
})
|
||||
} finally {
|
||||
ChangeTracker.isLoadingGraph = false
|
||||
}
|
||||
}
|
||||
|
||||
async graphToPrompt(graph = this.rootGraph) {
|
||||
|
||||
@@ -28,6 +28,14 @@ logger.setLevel('info')
|
||||
|
||||
export class ChangeTracker {
|
||||
static MAX_HISTORY = 50
|
||||
/**
|
||||
* Guard flag to prevent checkState from running during loadGraphData.
|
||||
* Between rootGraph.configure() and afterLoadNewGraph(), the rootGraph
|
||||
* contains the NEW workflow's data while activeWorkflow still points to
|
||||
* the OLD workflow. Any checkState call in that window would serialize
|
||||
* the wrong graph into the old workflow's activeState, corrupting it.
|
||||
*/
|
||||
static isLoadingGraph = false
|
||||
/**
|
||||
* The active state of the workflow.
|
||||
*/
|
||||
@@ -131,7 +139,7 @@ export class ChangeTracker {
|
||||
}
|
||||
|
||||
checkState() {
|
||||
if (!app.graph || this.changeCount) return
|
||||
if (!app.graph || this.changeCount || ChangeTracker.isLoadingGraph) return
|
||||
const currentState = clone(app.rootGraph.serialize()) as ComfyWorkflowJSON
|
||||
if (!this.activeState) {
|
||||
this.activeState = currentState
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
|
||||
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
|
||||
import { app } from '@/scripts/app'
|
||||
import { ChangeTracker } from '@/scripts/changeTracker'
|
||||
import { resolveNode } from '@/utils/litegraphUtil'
|
||||
|
||||
export const useAppModeStore = defineStore('appMode', () => {
|
||||
@@ -77,7 +78,7 @@ export const useAppModeStore = defineStore('appMode', () => {
|
||||
? { inputs: selectedInputs, outputs: selectedOutputs }
|
||||
: null,
|
||||
(data) => {
|
||||
if (!data) return
|
||||
if (!data || ChangeTracker.isLoadingGraph) return
|
||||
const graph = app.rootGraph
|
||||
if (!graph) return
|
||||
const extra = (graph.extra ??= {})
|
||||
|
||||
Reference in New Issue
Block a user