fix(editor): Delete all connections of nodes with multiple ones when removed from canvas (#15713)

This commit is contained in:
Daria
2025-05-27 13:43:30 +03:00
committed by GitHub
parent 3223f52bbf
commit c4ea7578fe
2 changed files with 79 additions and 2 deletions

View File

@@ -2419,6 +2419,82 @@ describe('useCanvasOperations', () => {
expect(workflowsStore.removeConnection).not.toHaveBeenCalled();
});
it('should delete all connections of a node with multiple connections', () => {
const workflowsStore = mockedStore(useWorkflowsStore);
const { deleteConnectionsByNodeId } = useCanvasOperations({ router });
const sourceNode = createTestNode({ id: 'source', name: 'Source Node' });
const targetNode = createTestNode({ id: 'target', name: 'Target Node' });
workflowsStore.workflow.nodes = [sourceNode, targetNode];
workflowsStore.workflow.connections = {
[sourceNode.name]: {
[NodeConnectionTypes.Main]: [
[
{ node: targetNode.name, type: NodeConnectionTypes.Main, index: 0 },
{ node: targetNode.name, type: NodeConnectionTypes.Main, index: 1 },
],
],
},
[targetNode.name]: {
[NodeConnectionTypes.Main]: [],
},
};
workflowsStore.getNodeById = vi.fn().mockImplementation((id) => {
if (id === sourceNode.id) return sourceNode;
if (id === targetNode.id) return targetNode;
return null;
});
workflowsStore.getNodeByName = vi.fn().mockImplementation((name) => {
if (name === sourceNode.name) return sourceNode;
if (name === targetNode.name) return targetNode;
return null;
});
workflowsStore.removeConnection = vi
.fn()
.mockImplementation((data: { connection: IConnection[] }) => {
const sourceData = data.connection[0];
const destinationData = data.connection[1];
const connections =
workflowsStore.workflow.connections[sourceData.node][sourceData.type][sourceData.index];
for (const index in connections) {
if (
connections[+index].node === destinationData.node &&
connections[+index].type === destinationData.type &&
connections[+index].index === destinationData.index
) {
connections.splice(parseInt(index, 10), 1);
}
}
});
deleteConnectionsByNodeId(targetNode.id);
expect(workflowsStore.removeConnection).toHaveBeenCalledTimes(2);
expect(workflowsStore.removeConnection).toHaveBeenCalledWith({
connection: [
{ node: sourceNode.name, type: NodeConnectionTypes.Main, index: 0 },
{ node: targetNode.name, type: NodeConnectionTypes.Main, index: 0 },
],
});
expect(workflowsStore.removeConnection).toHaveBeenCalledWith({
connection: [
{ node: sourceNode.name, type: NodeConnectionTypes.Main, index: 0 },
{ node: targetNode.name, type: NodeConnectionTypes.Main, index: 1 },
],
});
expect(
workflowsStore.workflow.connections[sourceNode.name][NodeConnectionTypes.Main][0],
).toEqual([]);
});
});
describe('duplicateNodes', () => {

View File

@@ -109,6 +109,7 @@ import type { CanvasLayoutEvent } from './useCanvasLayout';
import { chatEventBus } from '@n8n/chat/event-buses';
import { isChatNode } from '@/components/CanvasChat/utils';
import { useLogsStore } from '@/stores/logs.store';
import { cloneDeep } from 'lodash-es';
type AddNodeData = Partial<INodeUi> & {
type: string;
@@ -1122,7 +1123,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
);
for (const nodeName of checkNodes) {
const node = workflowsStore.nodesByName[nodeName];
if (node.position[0] < sourceNode.position[0]) {
if (!node || !sourceNode || node.position[0] < sourceNode.position[0]) {
continue;
}
@@ -1210,7 +1211,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
historyStore.startRecordingUndo();
}
const connections = workflowsStore.workflow.connections;
const connections = cloneDeep(workflowsStore.workflow.connections);
for (const nodeName of Object.keys(connections)) {
const node = workflowsStore.getNodeByName(nodeName);
if (!node) {