diff --git a/browser_tests/assets/mixed_graph_items.json b/browser_tests/assets/mixed_graph_items.json new file mode 100644 index 000000000..506285e2d --- /dev/null +++ b/browser_tests/assets/mixed_graph_items.json @@ -0,0 +1,227 @@ +{ + "last_node_id": 3, + "last_link_id": 0, + "nodes": [ + { + "id": 2, + "type": "KSampler", + "pos": { + "0": 420, + "1": 130 + }, + "size": { + "0": 315, + "1": 262 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": null + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": null + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": null + }, + { + "name": "latent_image", + "type": "LATENT", + "link": null + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": null + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 0, + "randomize", + 20, + 8, + "euler", + "normal", + 1 + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": { + "0": 820, + "1": 130 + }, + "size": { + "0": 315, + "1": 262 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": null + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": null + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": null + }, + { + "name": "latent_image", + "type": "LATENT", + "link": null + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": null + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 0, + "randomize", + 20, + 8, + "euler", + "normal", + 1 + ] + }, + { + "id": 1, + "type": "KSampler", + "pos": { + "0": 30, + "1": 130 + }, + "size": { + "0": 315, + "1": 262 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": null + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": null + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": null + }, + { + "name": "latent_image", + "type": "LATENT", + "link": null + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": null + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 0, + "randomize", + 20, + 8, + "euler", + "normal", + 1 + ] + } + ], + "links": [], + "groups": [ + { + "id": 0, + "title": "Group", + "bounding": [ + 406.9701232910156, + 59.079444885253906, + 335, + 345.6000061035156 + ], + "color": "#3f789e", + "font_size": 24, + "flags": {} + }, + { + "id": 3, + "title": "Group Parent", + "bounding": [ + 796.9703979492188, + 14.796443939208984, + 355, + 399.20001220703125 + ], + "color": "#3f789e", + "font_size": 24, + "flags": {} + }, + { + "id": 2, + "title": "Group Child", + "bounding": [ + 806.9703979492188, + 58.39643096923828, + 335, + 345.6000061035156 + ], + "color": "#3f789e", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 1, + "offset": [ + 0, + 0 + ] + } + }, + "version": 0.4 +} \ No newline at end of file diff --git a/browser_tests/interaction.spec.ts b/browser_tests/interaction.spec.ts index a8c08ac50..a3c8540ea 100644 --- a/browser_tests/interaction.spec.ts +++ b/browser_tests/interaction.spec.ts @@ -1,6 +1,16 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from './fixtures/ComfyPage' +test.describe('Item Interaction', () => { + test('Can select/delete all items', async ({ comfyPage }) => { + await comfyPage.loadWorkflow('mixed_graph_items') + await comfyPage.canvas.press('Control+a') + await expect(comfyPage.canvas).toHaveScreenshot('selected-all.png') + await comfyPage.canvas.press('Delete') + await expect(comfyPage.canvas).toHaveScreenshot('deleted-all.png') + }) +}) + test.describe('Node Interaction', () => { test('Can enter prompt', async ({ comfyPage }) => { const textBox = comfyPage.widgetTextBox @@ -12,7 +22,7 @@ test.describe('Node Interaction', () => { }) test.describe('Node Selection', () => { - const multiSelectModifiers = ['Control', 'Shift', 'Meta'] + const multiSelectModifiers = ['Control', 'Shift', 'Meta'] as const multiSelectModifiers.forEach((modifier) => { test(`Can add multiple nodes to selection using ${modifier}+Click`, async ({ diff --git a/browser_tests/interaction.spec.ts-snapshots/deleted-all-chromium-2x-linux.png b/browser_tests/interaction.spec.ts-snapshots/deleted-all-chromium-2x-linux.png new file mode 100644 index 000000000..640617794 Binary files /dev/null and b/browser_tests/interaction.spec.ts-snapshots/deleted-all-chromium-2x-linux.png differ diff --git a/browser_tests/interaction.spec.ts-snapshots/deleted-all-chromium-linux.png b/browser_tests/interaction.spec.ts-snapshots/deleted-all-chromium-linux.png new file mode 100644 index 000000000..0d2635ee3 Binary files /dev/null and b/browser_tests/interaction.spec.ts-snapshots/deleted-all-chromium-linux.png differ diff --git a/browser_tests/interaction.spec.ts-snapshots/selected-all-chromium-2x-linux.png b/browser_tests/interaction.spec.ts-snapshots/selected-all-chromium-2x-linux.png new file mode 100644 index 000000000..845746b57 Binary files /dev/null and b/browser_tests/interaction.spec.ts-snapshots/selected-all-chromium-2x-linux.png differ diff --git a/browser_tests/interaction.spec.ts-snapshots/selected-all-chromium-linux.png b/browser_tests/interaction.spec.ts-snapshots/selected-all-chromium-linux.png new file mode 100644 index 000000000..18d2656f0 Binary files /dev/null and b/browser_tests/interaction.spec.ts-snapshots/selected-all-chromium-linux.png differ diff --git a/package-lock.json b/package-lock.json index e8cd07847..f7317a38f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.3.31", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", - "@comfyorg/litegraph": "^0.8.15", + "@comfyorg/litegraph": "^0.8.17", "@primevue/themes": "^4.0.5", "@vueuse/core": "^11.0.0", "axios": "^1.7.4", @@ -1911,9 +1911,9 @@ "dev": true }, "node_modules/@comfyorg/litegraph": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.15.tgz", - "integrity": "sha512-Wq3QxgBNs93cR7gN8aboKbsvmVoWmj9kIxuI1wm1xZUMEI3PfpwGVhRLjABxk5AMtxFOOMiQIcJvbYTAoW+itQ==", + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.17.tgz", + "integrity": "sha512-koNvj7Bei1MWELlLC9OuvGb2TGTzfqxExYbl/m0bK6taoLk82Xu3mnHz2T9iuxZMih+jwnriI6nNjCFvu1jTfA==", "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { diff --git a/package.json b/package.json index 6973115f6..16e54d4f4 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ }, "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", - "@comfyorg/litegraph": "^0.8.15", + "@comfyorg/litegraph": "^0.8.17", "@primevue/themes": "^4.0.5", "@vueuse/core": "^11.0.0", "axios": "^1.7.4", diff --git a/src/extensions/core/groupOptions.ts b/src/extensions/core/groupOptions.ts index ef40b8391..dfdb919f4 100644 --- a/src/extensions/core/groupOptions.ts +++ b/src/extensions/core/groupOptions.ts @@ -1,66 +1,17 @@ // @ts-strict-ignore import { LGraphGroup } from '@comfyorg/litegraph' import { app } from '../../scripts/app' -import { LGraphCanvas, LiteGraph } from '@comfyorg/litegraph' +import { LGraphCanvas } from '@comfyorg/litegraph' +import type { Positionable } from '@comfyorg/litegraph/dist/interfaces' +import type { LGraphNode } from '@comfyorg/litegraph' -function setNodeMode(node, mode) { +function setNodeMode(node: LGraphNode, mode: number) { node.mode = mode - node.graph.change() + node.graph?.change() } -function addNodesToGroup(group, nodes = []) { - var x1, y1, x2, y2 - var nx1, ny1, nx2, ny2 - var node - - x1 = y1 = x2 = y2 = -1 - nx1 = ny1 = nx2 = ny2 = -1 - - for (var n of [group.nodes, nodes]) { - for (var i in n) { - node = n[i] - - nx1 = node.pos[0] - ny1 = node.pos[1] - nx2 = node.pos[0] + node.size[0] - ny2 = node.pos[1] + node.size[1] - - if (node.type != 'Reroute') { - ny1 -= LiteGraph.NODE_TITLE_HEIGHT - } - - if (node.flags?.collapsed) { - ny2 = ny1 + LiteGraph.NODE_TITLE_HEIGHT - - if (node?._collapsed_width) { - nx2 = nx1 + Math.round(node._collapsed_width) - } - } - - if (x1 == -1 || nx1 < x1) { - x1 = nx1 - } - - if (y1 == -1 || ny1 < y1) { - y1 = ny1 - } - - if (x2 == -1 || nx2 > x2) { - x2 = nx2 - } - - if (y2 == -1 || ny2 > y2) { - y2 = ny2 - } - } - } - - var padding = 10 - - y1 = y1 - Math.round(group.font_size * 1.4) - - group.pos = [x1 - padding, y1 - padding] - group.size = [x2 - x1 + padding * 2, y2 - y1 + padding * 2] +function addNodesToGroup(group: LGraphGroup, items: Iterable) { + group.resizeTo([...group.children, ...items]) } app.registerExtension({ @@ -68,7 +19,9 @@ app.registerExtension({ setup() { const orig = LGraphCanvas.prototype.getCanvasMenuOptions // graph_mouse - LGraphCanvas.prototype.getCanvasMenuOptions = function () { + LGraphCanvas.prototype.getCanvasMenuOptions = function ( + this: LGraphCanvas + ) { const options = orig.apply(this, arguments) const group = this.graph.getGroupOnPos( this.graph_mouse[0], @@ -77,11 +30,11 @@ app.registerExtension({ if (!group) { options.push({ content: 'Add Group For Selected Nodes', - disabled: !Object.keys(app.canvas.selected_nodes || {}).length, + disabled: !this.selectedItems?.size, callback: () => { const group = new LGraphGroup() - addNodesToGroup(group, this.selected_nodes) - app.canvas.graph.add(group) + addNodesToGroup(group, this.selectedItems) + this.graph.add(group) this.graph.change() } }) @@ -95,9 +48,9 @@ app.registerExtension({ options.push({ content: 'Add Selected Nodes To Group', - disabled: !Object.keys(app.canvas.selected_nodes || {}).length, + disabled: !this.selectedItems?.size, callback: () => { - addNodesToGroup(group, this.selected_nodes) + addNodesToGroup(group, this.selectedItems) this.graph.change() } }) @@ -122,7 +75,8 @@ app.registerExtension({ options.push({ content: 'Fit Group To Nodes', callback: () => { - addNodesToGroup(group) + group.recomputeInsideNodes() + group.resizeTo(group.children) this.graph.change() } }) diff --git a/src/stores/commandStore.ts b/src/stores/commandStore.ts index dd64a4398..59640b42e 100644 --- a/src/stores/commandStore.ts +++ b/src/stores/commandStore.ts @@ -361,14 +361,13 @@ export const useCommandStore = defineStore('command', () => { label: 'Group Selected Nodes', versionAdded: '1.3.7', function: () => { - if ( - !app.canvas.selected_nodes || - Object.keys(app.canvas.selected_nodes).length === 0 - ) { + const { canvas } = app + if (!canvas.selectedItems?.size) { useToastStore().add({ severity: 'error', - summary: 'No nodes selected', - detail: 'Please select nodes to group', + summary: 'Nothing to group', + detail: + 'Please select the nodes (or other groups) to create a group for', life: 3000 }) return @@ -377,8 +376,8 @@ export const useCommandStore = defineStore('command', () => { const padding = useSettingStore().get( 'Comfy.GroupSelectedNodes.Padding' ) - group.addNodes(Object.values(app.canvas.selected_nodes), padding) - app.canvas.graph.add(group) + group.resizeTo(canvas.selectedItems, padding) + canvas.graph.add(group) useTitleEditorStore().titleEditorTarget = group } },