Compare commits

...

1 Commits

Author SHA1 Message Date
dante01yoon
ba2b600f1b fix: preserve autogrow links on copy/paste for multi-spec nodes
The autogrow onConnectionsChange callback only called
ensureWidgetForInput when app.configuringGraph was true (graph load).
During paste, configuringGraph is false, so shim widgets were not
recreated for multi-spec autogrow inputs. This caused
onGraphConfigured to remove those inputs (no matching widget found),
breaking links.

Remove the app.configuringGraph guard since ensureWidgetForInput is
idempotent and safe to call in all contexts.

Fixes #9779

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:56:47 +09:00
2 changed files with 38 additions and 2 deletions

View File

@@ -210,4 +210,41 @@ describe('Autogrow', () => {
'aa'
])
})
test('Multi-spec autogrow recreates shim widgets on configure', () => {
const graph = new LGraph()
const node = testNode()
graph.add(node)
const multiInputsSpec = {
required: { value: ['IMAGE', {}], mask: ['IMAGE', {}] }
}
addAutogrow(node, { min: 1, input: multiInputsSpec })
// Multi-spec autogrow creates shim widgets via ensureWidgetForInput
const shimWidgets = node.widgets.filter((w) => w.type === 'shim')
expect(shimWidgets.length).toBe(2)
// Connect the last slot to trigger growth
connectInput(node, 0, graph)
expect(node.inputs.length).toBe(4)
// Simulate paste: manually add a serialized autogrow input with widget ref
// but missing its shim widget (reproducing the paste bug)
const shimsBefore = node.widgets.filter((w) => w.type === 'shim').length
const lastInput = node.inputs.at(-1)!
expect(lastInput.widget).toBeDefined()
// Remove all shim widgets to simulate paste (shim has serialize: false)
node.widgets = node.widgets.filter((w) => w.type !== 'shim')
expect(node.widgets.filter((w) => w.type === 'shim').length).toBe(0)
// Re-trigger onConnectionsChange for each input (simulates configure())
for (const [i, input] of node.inputs.entries()) {
node.onConnectionsChange?.(1, i, true, null, input)
}
// Shim widgets should be recreated
const shimsAfter = node.widgets.filter((w) => w.type === 'shim').length
expect(shimsAfter).toBe(shimsBefore)
})
})

View File

@@ -557,8 +557,7 @@ function withComfyAutogrow(node: LGraphNode): asserts node is AutogrowNode {
const key = input.name.slice(0, input.name.lastIndexOf('.'))
const autogrowGroup = this.comfyDynamic.autogrow[key]
if (!autogrowGroup) return
if (app.configuringGraph && input.widget)
ensureWidgetForInput(node, input)
if (input.widget) ensureWidgetForInput(node, input)
if (iscon) {
if (swappingConnection || !linf) return
autogrowInputConnected(slot, this)