From 195d779035c44a044a4db353eddf4b99cd006396 Mon Sep 17 00:00:00 2001 From: Comfy Org PR Bot Date: Tue, 9 Dec 2025 09:55:22 +0900 Subject: [PATCH] [backport core/1.33] When moving subgraphInput link, properly disconnect old link (#7255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of #7229 to `core/1.33` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7255-backport-core-1-33-When-moving-subgraphInput-link-properly-disconnect-old-link-2c46d73d365081cda606e81ec4cbfeec) by [Unito](https://www.unito.io) Co-authored-by: AustinMroz --- .../src/canvas/ToInputFromIoNodeLink.ts | 3 + ...nkConnectorSubgraphInputValidation.test.ts | 65 ++++++++++++++++--- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/lib/litegraph/src/canvas/ToInputFromIoNodeLink.ts b/src/lib/litegraph/src/canvas/ToInputFromIoNodeLink.ts index e98c59d87..073c777f1 100644 --- a/src/lib/litegraph/src/canvas/ToInputFromIoNodeLink.ts +++ b/src/lib/litegraph/src/canvas/ToInputFromIoNodeLink.ts @@ -63,6 +63,9 @@ export class ToInputFromIoNodeLink implements RenderLink { if (existingLink) { // Moving an existing link + const { input, inputNode } = existingLink.resolve(this.network) + if (inputNode && input) + this.node._disconnectNodeInput(inputNode, input, existingLink) events.dispatch('input-moved', this) } else { // Creating a new link diff --git a/tests-ui/tests/litegraph/canvas/LinkConnectorSubgraphInputValidation.test.ts b/tests-ui/tests/litegraph/canvas/LinkConnectorSubgraphInputValidation.test.ts index 957076526..072a0fb4c 100644 --- a/tests-ui/tests/litegraph/canvas/LinkConnectorSubgraphInputValidation.test.ts +++ b/tests-ui/tests/litegraph/canvas/LinkConnectorSubgraphInputValidation.test.ts @@ -1,15 +1,20 @@ // TODO: Fix these tests after migration import { beforeEach, describe, expect, it, vi } from 'vitest' -import { LinkConnector } from '@/lib/litegraph/src/litegraph' -import { MovingOutputLink } from '@/lib/litegraph/src/litegraph' -import { ToOutputRenderLink } from '@/lib/litegraph/src/litegraph' -import { LGraphNode, LLink } from '@/lib/litegraph/src/litegraph' +import { + LinkConnector, + MovingOutputLink, + ToOutputRenderLink, + LGraphNode, + LLink +} from '@/lib/litegraph/src/litegraph' +import { ToInputFromIoNodeLink } from '@/lib/litegraph/src/canvas/ToInputFromIoNodeLink' import type { NodeInputSlot } from '@/lib/litegraph/src/litegraph' +import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' import { createTestSubgraph } from '../subgraph/fixtures/subgraphHelpers' -describe.skip('LinkConnector SubgraphInput connection validation', () => { +describe('LinkConnector SubgraphInput connection validation', () => { let connector: LinkConnector const mockSetConnectingLinks = vi.fn() @@ -17,8 +22,50 @@ describe.skip('LinkConnector SubgraphInput connection validation', () => { connector = new LinkConnector(mockSetConnectingLinks) vi.clearAllMocks() }) + describe('Link disconnection validation', () => { + it('should properly cleanup a moved input link', () => { + const subgraph = createTestSubgraph({ + inputs: [{ name: 'number_input', type: 'number' }] + }) - describe.skip('MovingOutputLink validation', () => { + const fromTargetNode = new LGraphNode('TargetNode') + fromTargetNode.addInput('number_in', 'number') + subgraph.add(fromTargetNode) + + const toTargetNode = new LGraphNode('TargetNode') + toTargetNode.addInput('number_in', 'number') + subgraph.add(toTargetNode) + + const startLink = subgraph.inputNode.slots[0].connect( + fromTargetNode.inputs[0], + fromTargetNode + ) + + fromTargetNode.onConnectionsChange = vi.fn() + toTargetNode.onConnectionsChange = vi.fn() + + const renderLink = new ToInputFromIoNodeLink( + subgraph, + subgraph.inputNode, + subgraph.inputNode.slots[0], + undefined, + LinkDirection.CENTER, + startLink + ) + renderLink.connectToInput( + toTargetNode, + toTargetNode.inputs[0], + connector.events + ) + + expect(fromTargetNode.inputs[0].link).toBeNull() + expect(toTargetNode.inputs[0].link).not.toBeNull() + expect(toTargetNode.onConnectionsChange).toHaveBeenCalledTimes(1) + expect(fromTargetNode.onConnectionsChange).toHaveBeenCalledTimes(1) + }) + }) + + describe('MovingOutputLink validation', () => { it('should implement canConnectToSubgraphInput method', () => { const subgraph = createTestSubgraph({ inputs: [{ name: 'number_input', type: 'number' }] @@ -113,7 +160,7 @@ describe.skip('LinkConnector SubgraphInput connection validation', () => { }) }) - describe.skip('ToOutputRenderLink validation', () => { + describe('ToOutputRenderLink validation', () => { it('should implement canConnectToSubgraphInput method', () => { // Create a minimal valid setup const subgraph = createTestSubgraph() @@ -130,7 +177,7 @@ describe.skip('LinkConnector SubgraphInput connection validation', () => { }) }) - describe.skip('dropOnIoNode validation', () => { + describe('dropOnIoNode validation', () => { it('should prevent invalid connections when dropping on SubgraphInputNode', () => { const subgraph = createTestSubgraph({ inputs: [{ name: 'number_input', type: 'number' }] @@ -232,7 +279,7 @@ describe.skip('LinkConnector SubgraphInput connection validation', () => { }) }) - describe.skip('isSubgraphInputValidDrop', () => { + describe('isSubgraphInputValidDrop', () => { it('should check if render links can connect to SubgraphInput', () => { const subgraph = createTestSubgraph({ inputs: [{ name: 'number_input', type: 'number' }]