mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-01 19:20:10 +00:00
Make optional node input's slot hollow circle (#912)
* Use hollow circle for optional input * nit * Show hollow shape for optional input * Add playwright tests * Update litegraph * Update test expectations [skip ci] --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
57
browser_tests/assets/optional_input_correct_shape.json
Normal file
57
browser_tests/assets/optional_input_correct_shape.json
Normal file
@@ -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
|
||||
}
|
||||
56
browser_tests/assets/optional_input_no_shape.json
Normal file
56
browser_tests/assets/optional_input_no_shape.json
Normal file
@@ -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
|
||||
}
|
||||
57
browser_tests/assets/optional_input_wrong_shape.json
Normal file
57
browser_tests/assets/optional_input_wrong_shape.json
Normal file
@@ -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
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
21
browser_tests/nodeDisplay.spec.ts
Normal file
21
browser_tests/nodeDisplay.spec.ts
Normal file
@@ -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')
|
||||
})
|
||||
})
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
8
package-lock.json
generated
8
package-lock.json
generated
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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<string, any>,
|
||||
incoming: Record<string, any>
|
||||
) => {
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user