diff --git a/browser_tests/assets/optional_input_correct_shape.json b/browser_tests/assets/optional_input_correct_shape.json new file mode 100644 index 000000000..9a40eeb85 --- /dev/null +++ b/browser_tests/assets/optional_input_correct_shape.json @@ -0,0 +1,57 @@ +{ + "last_node_id": 5, + "last_link_id": 0, + "nodes": [ + { + "id": 5, + "type": "DevToolsNodeWithOptionalInput", + "pos": { + "0": 19, + "1": 46 + }, + "size": { + "0": 302.4000244140625, + "1": 46 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [ + { + "name": "required_input", + "type": "IMAGE", + "link": null + }, + { + "name": "optional_input", + "type": "IMAGE", + "link": null, + "shape": 7 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": null + } + ], + "properties": { + "Node name for S&R": "DevToolsNodeWithOptionalInput" + } + } + ], + "links": [], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1, + "offset": [ + 0, + 0 + ] + } + }, + "version": 0.4 +} \ No newline at end of file diff --git a/browser_tests/assets/optional_input_no_shape.json b/browser_tests/assets/optional_input_no_shape.json new file mode 100644 index 000000000..e56acc0d9 --- /dev/null +++ b/browser_tests/assets/optional_input_no_shape.json @@ -0,0 +1,56 @@ +{ + "last_node_id": 5, + "last_link_id": 0, + "nodes": [ + { + "id": 5, + "type": "DevToolsNodeWithOptionalInput", + "pos": { + "0": 19, + "1": 46 + }, + "size": { + "0": 302.4000244140625, + "1": 46 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [ + { + "name": "required_input", + "type": "IMAGE", + "link": null + }, + { + "name": "optional_input", + "type": "IMAGE", + "link": null + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": null + } + ], + "properties": { + "Node name for S&R": "DevToolsNodeWithOptionalInput" + } + } + ], + "links": [], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1, + "offset": [ + 0, + 0 + ] + } + }, + "version": 0.4 +} \ No newline at end of file diff --git a/browser_tests/assets/optional_input_wrong_shape.json b/browser_tests/assets/optional_input_wrong_shape.json new file mode 100644 index 000000000..094ecdb4f --- /dev/null +++ b/browser_tests/assets/optional_input_wrong_shape.json @@ -0,0 +1,57 @@ +{ + "last_node_id": 5, + "last_link_id": 0, + "nodes": [ + { + "id": 5, + "type": "DevToolsNodeWithOptionalInput", + "pos": { + "0": 19, + "1": 46 + }, + "size": { + "0": 302.4000244140625, + "1": 46 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [ + { + "name": "required_input", + "type": "IMAGE", + "link": null + }, + { + "name": "optional_input", + "type": "IMAGE", + "link": null, + "shape": 6 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": null + } + ], + "properties": { + "Node name for S&R": "DevToolsNodeWithOptionalInput" + } + } + ], + "links": [], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1, + "offset": [ + 0, + 0 + ] + } + }, + "version": 0.4 +} \ No newline at end of file diff --git a/browser_tests/nodeBadge.spec.ts b/browser_tests/nodeBadge.spec.ts index d993f2c78..7ebb06fd3 100644 --- a/browser_tests/nodeBadge.spec.ts +++ b/browser_tests/nodeBadge.spec.ts @@ -9,7 +9,6 @@ test.describe('Node Badge', () => { const LGraphBadge = window['LGraphBadge'] const app = window['app'] as ComfyApp const graph = app.graph - // @ts-expect-error - accessing private property const nodes = graph.nodes for (const node of nodes) { @@ -27,7 +26,6 @@ test.describe('Node Badge', () => { const LGraphBadge = window['LGraphBadge'] const app = window['app'] as ComfyApp const graph = app.graph - // @ts-expect-error - accessing private property const nodes = graph.nodes for (const node of nodes) { @@ -48,7 +46,6 @@ test.describe('Node Badge', () => { const LGraphBadge = window['LGraphBadge'] const app = window['app'] as ComfyApp const graph = app.graph - // @ts-expect-error - accessing private property const nodes = graph.nodes for (const node of nodes) { diff --git a/browser_tests/nodeDisplay.spec.ts b/browser_tests/nodeDisplay.spec.ts new file mode 100644 index 000000000..d17b0cb16 --- /dev/null +++ b/browser_tests/nodeDisplay.spec.ts @@ -0,0 +1,21 @@ +import { expect } from '@playwright/test' +import { comfyPageFixture as test } from './ComfyPage' + +// If an input is optional by node definition, it should be shown as +// a hollow circle no matter what shape it was defined in the workflow JSON. +test.describe('Optional input', () => { + test('No shape specified', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('optional_input_no_shape') + await expect(comfyPage.canvas).toHaveScreenshot('optional_input.png') + }) + + test('Wrong shape specified', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('optional_input_wrong_shape') + await expect(comfyPage.canvas).toHaveScreenshot('optional_input.png') + }) + + test('Correct shape specified', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('optional_input_correct_shape') + await expect(comfyPage.canvas).toHaveScreenshot('optional_input.png') + }) +}) diff --git a/browser_tests/nodeDisplay.spec.ts-snapshots/optional-input-chromium-2x-linux.png b/browser_tests/nodeDisplay.spec.ts-snapshots/optional-input-chromium-2x-linux.png new file mode 100644 index 000000000..6d47c9441 Binary files /dev/null and b/browser_tests/nodeDisplay.spec.ts-snapshots/optional-input-chromium-2x-linux.png differ diff --git a/browser_tests/nodeDisplay.spec.ts-snapshots/optional-input-chromium-linux.png b/browser_tests/nodeDisplay.spec.ts-snapshots/optional-input-chromium-linux.png new file mode 100644 index 000000000..6824dc115 Binary files /dev/null and b/browser_tests/nodeDisplay.spec.ts-snapshots/optional-input-chromium-linux.png differ diff --git a/package-lock.json b/package-lock.json index a5f73cfba..7177f3c0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.2.60", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.2.1", - "@comfyorg/litegraph": "^0.7.75", + "@comfyorg/litegraph": "^0.7.76", "@primevue/themes": "^4.0.5", "@vitejs/plugin-vue": "^5.0.5", "@vueuse/core": "^11.0.0", @@ -1910,9 +1910,9 @@ "dev": true }, "node_modules/@comfyorg/litegraph": { - "version": "0.7.75", - "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.7.75.tgz", - "integrity": "sha512-RNYZVMoJ/a5btwP+S124FnrIVlwOdv6uNsTdYfwv7L8teDpwvf/TQa66QfCePqUlypBKEhKw+avTncLAu2FYUw==", + "version": "0.7.76", + "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.7.76.tgz", + "integrity": "sha512-SwlBq7WsolRyxqHsm+aXi8pSQDf3+Kt9ORBsznIvL42X+1RoAwetI0GDqML/zqKBI3zr9MbpjOboaeyVx3il1w==", "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { diff --git a/package.json b/package.json index 4879bc65f..d2e3a8948 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ }, "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.2.1", - "@comfyorg/litegraph": "^0.7.75", + "@comfyorg/litegraph": "^0.7.76", "@primevue/themes": "^4.0.5", "@vitejs/plugin-vue": "^5.0.5", "@vueuse/core": "^11.0.0", diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 9ac7ae785..42cadb7ab 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -1996,6 +1996,8 @@ export class ComfyApp { constructor(title?: string) { super(title) + const requiredInputs = nodeData.input.required + var inputs = nodeData['input']['required'] if (nodeData['input']['optional'] != undefined) { inputs = Object.assign( @@ -2025,7 +2027,12 @@ export class ComfyApp { } } else { // Node connection inputs - this.addInput(inputName, type) + const inputIsRequired = inputName in requiredInputs + const inputOptions = inputIsRequired + ? {} + : // @ts-expect-error LiteGraph.SlotShape is not typed. + { shape: LiteGraph.SlotShape.HollowCircle } + this.addInput(inputName, type, inputOptions) widgetCreated = false } // @ts-expect-error @@ -2048,10 +2055,11 @@ export class ComfyApp { let output = nodeData['output'][o] if (output instanceof Array) output = 'COMBO' const outputName = nodeData['output_name'][o] || output - const outputShape = nodeData['output_is_list'][o] - ? LiteGraph.GRID_SHAPE - : LiteGraph.CIRCLE_SHAPE - this.addOutput(outputName, output, { shape: outputShape }) + const outputIsList = nodeData['output_is_list'][o] + const outputOptions = outputIsList + ? { shape: LiteGraph.GRID_SHAPE } + : {} + this.addOutput(outputName, output, outputOptions) } const s = this.computeSize() @@ -2062,6 +2070,29 @@ export class ComfyApp { app.#invokeExtensionsAsync('nodeCreated', this) } + + configure(data: any) { + // Keep 'name', 'type', and 'shape' information from the original node definition. + const merge = ( + current: Record, + incoming: Record + ) => { + const result = { ...incoming } + for (const key of ['name', 'type', 'shape']) { + if (current[key] !== undefined) { + result[key] = current[key] + } + } + return result + } + for (const field of ['inputs', 'outputs']) { + const slots = data[field] ?? [] + data[field] = slots.map((slot, i) => + merge(this[field][i] ?? {}, slot) + ) + } + super.configure(data) + } } node.prototype.comfyClass = nodeData.name