From 014c3f3172e7997366c85313ed7c76565f3dedd9 Mon Sep 17 00:00:00 2001 From: AustinMroz Date: Fri, 11 Oct 2024 11:20:03 -0500 Subject: [PATCH] Fix load workflow with converted widget (#1222) f74973 introduced a regression where a node which has had an input added, will clobber a converted input of in a workflow created before the input was added. The prior behaviour was also incorrect (the new input would not exist on the node), but would often be runnable. Keeping the position of the converted widget and adding the new input to the end is an unfortunate compromise. Doing it the other way around breaks primitive nodes --- .../assets/old_workflow_converted_input.json | 128 ++++++++++++++++++ browser_tests/nodeDisplay.spec.ts | 12 ++ src/scripts/app.ts | 7 +- 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 browser_tests/assets/old_workflow_converted_input.json diff --git a/browser_tests/assets/old_workflow_converted_input.json b/browser_tests/assets/old_workflow_converted_input.json new file mode 100644 index 000000000..8734433b1 --- /dev/null +++ b/browser_tests/assets/old_workflow_converted_input.json @@ -0,0 +1,128 @@ +{ + "last_node_id": 2, + "last_link_id": 1, + "nodes": [ + { + "id": 1, + "type": "ControlNetApplyAdvanced", + "pos": { + "0": 449, + "1": 204 + }, + "size": [ + 340.20001220703125, + 166 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [ + { + "name": "positive", + "type": "CONDITIONING", + "link": null + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": null + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": null + }, + { + "name": "image", + "type": "IMAGE", + "link": null + }, + { + "name": "strength", + "type": "FLOAT", + "link": 1, + "widget": { + "name": "strength" + } + } + ], + "outputs": [ + { + "name": "positive", + "type": "CONDITIONING", + "links": null + }, + { + "name": "negative", + "type": "CONDITIONING", + "links": null + } + ], + "properties": { + "Node name for S&R": "ControlNetApplyAdvanced" + }, + "widgets_values": [ + 1, + 0, + 1 + ] + }, + { + "id": 2, + "type": "PrimitiveNode", + "pos": { + "0": 177, + "1": 265 + }, + "size": [ + 210, + 82 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "FLOAT", + "type": "FLOAT", + "links": [ + 1 + ], + "widget": { + "name": "strength" + } + } + ], + "properties": { + "Run widget replace on values": false + }, + "widgets_values": [ + 1, + "fixed" + ] + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 4, + "FLOAT" + ] + ], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1, + "offset": { + "0": 47.541666666666515, + "1": 186.9375 + } + } + }, + "version": 0.4 +} \ No newline at end of file diff --git a/browser_tests/nodeDisplay.spec.ts b/browser_tests/nodeDisplay.spec.ts index bbbf98ae5..05d0157ce 100644 --- a/browser_tests/nodeDisplay.spec.ts +++ b/browser_tests/nodeDisplay.spec.ts @@ -32,4 +32,16 @@ test.describe('Optional input', () => { // If the node's multiline text widget is visible, then it was loaded successfully expect(comfyPage.page.locator('.comfy-multiline-input')).toHaveCount(1) }) + test('Old workflow with converted input', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('old_workflow_converted_input') + const node = await comfyPage.getNodeRefById('1') + const inputs = await node.getProperty('inputs') + const vaeInput = inputs.find((w) => w.name === 'vae') + const convertedInput = inputs.find((w) => w.name === 'strength') + + expect(vaeInput).toBeDefined() + expect(convertedInput).toBeDefined() + expect(vaeInput.link).toBeNull() + expect(convertedInput.link).not.toBeNull() + }) }) diff --git a/src/scripts/app.ts b/src/scripts/app.ts index ff0fe446e..d1f250a10 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -38,7 +38,7 @@ import { SYSTEM_NODE_DEFS, useNodeDefStore } from '@/stores/nodeDefStore' -import { Vector2 } from '@comfyorg/litegraph' +import { INodeInputSlot, Vector2 } from '@comfyorg/litegraph' import _ from 'lodash' import { showExecutionErrorDialog, @@ -2093,6 +2093,11 @@ export class ComfyApp { incoming: Record ) => { const result = { ...incoming } + if (current.widget === undefined && incoming.widget !== undefined) { + // Field must be input as only inputs can be converted + this.inputs.push(current as INodeInputSlot) + return incoming + } for (const key of ['name', 'type', 'shape']) { if (current[key] !== undefined) { result[key] = current[key]