From 694ff472696a05979d6686bafdcc9c0219a7e66f Mon Sep 17 00:00:00 2001 From: Comfy Org PR Bot Date: Sun, 10 Aug 2025 08:28:03 +0800 Subject: [PATCH] [backport 1.25] Fix Alt-Click-Drag-Copy of Subgraph Nodes (#4884) Co-authored-by: Christian Byrne --- browser_tests/tests/subgraph.spec.ts | 62 +++++++++++++++++++++++++++ src/lib/litegraph/src/LGraphCanvas.ts | 2 + 2 files changed, 64 insertions(+) diff --git a/browser_tests/tests/subgraph.spec.ts b/browser_tests/tests/subgraph.spec.ts index 16321e229..1c9c8d97b 100644 --- a/browser_tests/tests/subgraph.spec.ts +++ b/browser_tests/tests/subgraph.spec.ts @@ -196,6 +196,68 @@ test.describe('Subgraph Operations', () => { const deletedNode = await comfyPage.getNodeRefById('2') expect(await deletedNode.exists()).toBe(false) }) + + test.describe('Subgraph copy and paste', () => { + test('Can copy subgraph node by dragging + alt', async ({ + comfyPage + }) => { + await comfyPage.loadWorkflow('basic-subgraph') + + const subgraphNode = await comfyPage.getNodeRefById('2') + + // Get position of subgraph node + const subgraphPos = await subgraphNode.getPosition() + + // Alt + Click on the subgraph node + await comfyPage.page.mouse.move(subgraphPos.x + 16, subgraphPos.y + 16) + await comfyPage.page.keyboard.down('Alt') + await comfyPage.page.mouse.down() + await comfyPage.nextFrame() + + // Drag slightly to trigger the copy + await comfyPage.page.mouse.move(subgraphPos.x + 64, subgraphPos.y + 64) + await comfyPage.page.mouse.up() + await comfyPage.page.keyboard.up('Alt') + + // Find all subgraph nodes + const subgraphNodes = + await comfyPage.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE) + + // Expect a second subgraph node to be created (2 total) + expect(subgraphNodes.length).toBe(2) + }) + + test('Copying subgraph node by dragging + alt creates a new subgraph node with unique type', async ({ + comfyPage + }) => { + await comfyPage.loadWorkflow('basic-subgraph') + + const subgraphNode = await comfyPage.getNodeRefById('2') + + // Get position of subgraph node + const subgraphPos = await subgraphNode.getPosition() + + // Alt + Click on the subgraph node + await comfyPage.page.mouse.move(subgraphPos.x + 16, subgraphPos.y + 16) + await comfyPage.page.keyboard.down('Alt') + await comfyPage.page.mouse.down() + await comfyPage.nextFrame() + + // Drag slightly to trigger the copy + await comfyPage.page.mouse.move(subgraphPos.x + 64, subgraphPos.y + 64) + await comfyPage.page.mouse.up() + await comfyPage.page.keyboard.up('Alt') + + // Find all subgraph nodes and expect all unique IDs + const subgraphNodes = + await comfyPage.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE) + + // Expect the second subgraph node to have a unique type + const nodeType1 = await subgraphNodes[0].getType() + const nodeType2 = await subgraphNodes[1].getType() + expect(nodeType1).not.toBe(nodeType2) + }) + }) }) test.describe('Operations Inside Subgraphs', () => { diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 5b375c902..f17109baa 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -2299,6 +2299,8 @@ export class LGraphCanvas const node_data = node.clone()?.serialize() if (node_data?.type != null) { + // Ensure the cloned node is configured against the correct type (especially for SubgraphNodes) + node_data.type = newType const cloned = LiteGraph.createNode(newType) if (cloned) { cloned.configure(node_data)