Cleanup app.graph usage (#7399)

Prior to the release of subgraphs, there was a single graph accessed
through `app.graph`. Now that there's multiple graphs, there's a lot of
code that needs to be reviewed and potentially updated depending on if
it cares about nearby nodes, all nodes, or something else requiring
specific attention.

This was done by simply changing the type of `app.graph` to unknown so
the typechecker will complain about every place it's currently used.
References were then updated to `app.rootGraph` if the previous usage
was correct, or actually rewritten.

By not getting rid of `app.graph`, this change already ensures that
there's no loss of functionality for custom nodes, but the prior typing
of `app.graph` can always be restored if future dissuasion of
`app.graph` usage creates issues.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7399-Cleanup-app-graph-usage-2c76d73d365081178743dfdcf07f44d0)
by [Unito](https://www.unito.io)
This commit is contained in:
AustinMroz
2025-12-11 22:37:34 -08:00
committed by GitHub
parent 88bdc605a7
commit f2a0e5102e
39 changed files with 192 additions and 209 deletions

View File

@@ -58,7 +58,7 @@ const { mode: queueMode, batchCount } = storeToRefs(useQueueSettingsStore())
const nodeDefStore = useNodeDefStore()
const hasMissingNodes = computed(() =>
graphHasMissingNodes(app.graph, nodeDefStore.nodeDefsByName)
graphHasMissingNodes(app.rootGraph, nodeDefStore.nodeDefsByName)
)
const { t } = useI18n()

View File

@@ -83,7 +83,7 @@ const props = withDefaults(defineProps<Props>(), {
const nodeDefStore = useNodeDefStore()
const hasMissingNodes = computed(() =>
graphHasMissingNodes(app.graph, nodeDefStore.nodeDefsByName)
graphHasMissingNodes(app.rootGraph, nodeDefStore.nodeDefsByName)
)
const { t } = useI18n()

View File

@@ -128,7 +128,7 @@ onMounted(async () => {
reportContent.value = generateErrorReport({
systemStats: systemStatsStore.systemStats!,
serverLogs: logs,
workflow: app.graph.serialize(),
workflow: app.rootGraph.serialize(),
exceptionType: error.exceptionType,
exceptionMessage: error.exceptionMessage,
traceback: error.traceback,

View File

@@ -159,6 +159,7 @@ import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import { isNativeWindow } from '@/utils/envUtil'
import { forEachNode } from '@/utils/graphTraversalUtil'
import SelectionRectangle from './SelectionRectangle.vue'
@@ -269,20 +270,18 @@ watch(
() => {
if (!canvasStore.canvas) return
for (const n of comfyApp.graph.nodes) {
if (!n.widgets) continue
forEachNode(comfyApp.rootGraph, (n) => {
if (!n.widgets) return
for (const w of n.widgets) {
if (w[IS_CONTROL_WIDGET]) {
updateControlWidgetLabel(w)
if (w.linkedWidgets) {
for (const l of w.linkedWidgets) {
updateControlWidgetLabel(l)
}
}
if (!w[IS_CONTROL_WIDGET]) continue
updateControlWidgetLabel(w)
if (!w.linkedWidgets) continue
for (const l of w.linkedWidgets) {
updateControlWidgetLabel(l)
}
}
}
comfyApp.graph.setDirtyCanvas(true)
})
canvasStore.canvas.setDirty(true)
}
)
@@ -332,7 +331,7 @@ watch(
}
// Force canvas redraw to ensure progress updates are visible
canvas.graph.setDirtyCanvas(true, false)
canvas.setDirty(true, false)
},
{ deep: true }
)
@@ -344,7 +343,7 @@ watch(
(lastNodeErrors) => {
if (!comfyApp.graph) return
for (const node of comfyApp.graph.nodes) {
forEachNode(comfyApp.rootGraph, (node) => {
// Clear existing errors
for (const slot of node.inputs) {
delete slot.hasErrors
@@ -354,7 +353,7 @@ watch(
}
const nodeErrors = lastNodeErrors?.[node.id]
if (!nodeErrors) continue
if (!nodeErrors) return
const validErrors = nodeErrors.errors.filter(
(error) => error.extra_info?.input_name !== undefined
@@ -367,9 +366,9 @@ watch(
node.inputs[inputIndex].hasErrors = true
}
})
}
})
comfyApp.canvas.draw(true, true)
comfyApp.canvas.setDirty(true, true)
}
)

View File

@@ -58,7 +58,7 @@ const onEdit = (newValue: string) => {
target.subgraph.name = trimmedTitle
}
app.graph.setDirtyCanvas(true, true)
app.canvas.setDirty(true, true)
}
showInput.value = false
titleEditorStore.titleEditorTarget = null

View File

@@ -33,7 +33,7 @@ const toast = useToast()
const workflowStore = useWorkflowStore()
const migrateToLitegraphReroute = async () => {
const workflowJSON = app.graph.serialize() as unknown as WorkflowJSON04
const workflowJSON = app.rootGraph.serialize() as unknown as WorkflowJSON04
const migratedWorkflowJSON = migrateLegacyRerouteNodes(workflowJSON)
await app.loadGraphData(
migratedWorkflowJSON,