mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-04 17:37:28 -08:00
fix(editor): Fix reordered switch connections when copying nodes on new canvas (#11788)
This commit is contained in:
parent
de0e86150f
commit
6c2dad7914
|
@ -4,6 +4,7 @@ import type {
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
IWebhookDescription,
|
IWebhookDescription,
|
||||||
Workflow,
|
Workflow,
|
||||||
|
INodeConnections,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { NodeConnectionType, NodeHelpers } from 'n8n-workflow';
|
import { NodeConnectionType, NodeHelpers } from 'n8n-workflow';
|
||||||
import { useCanvasOperations } from '@/composables/useCanvasOperations';
|
import { useCanvasOperations } from '@/composables/useCanvasOperations';
|
||||||
|
@ -2049,7 +2050,6 @@ describe('useCanvasOperations', () => {
|
||||||
expect(workflowsStore.setNodes).toHaveBeenCalled();
|
expect(workflowsStore.setNodes).toHaveBeenCalled();
|
||||||
expect(workflowsStore.setConnections).toHaveBeenCalled();
|
expect(workflowsStore.setConnections).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should initialize node data from node type description', () => {
|
it('should initialize node data from node type description', () => {
|
||||||
const nodeTypesStore = mockedStore(useNodeTypesStore);
|
const nodeTypesStore = mockedStore(useNodeTypesStore);
|
||||||
|
@ -2082,6 +2082,100 @@ describe('useCanvasOperations', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('filterConnectionsByNodes', () => {
|
||||||
|
it('should return filtered connections when all nodes are included', () => {
|
||||||
|
const connections: INodeConnections = {
|
||||||
|
[NodeConnectionType.Main]: [
|
||||||
|
[
|
||||||
|
{ node: 'node1', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
{ node: 'node2', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
],
|
||||||
|
[{ node: 'node3', type: NodeConnectionType.Main, index: 0 }],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const includeNodeNames = new Set<string>(['node1', 'node2', 'node3']);
|
||||||
|
|
||||||
|
const { filterConnectionsByNodes } = useCanvasOperations({ router });
|
||||||
|
const result = filterConnectionsByNodes(connections, includeNodeNames);
|
||||||
|
|
||||||
|
expect(result).toEqual(connections);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty connections when no nodes are included', () => {
|
||||||
|
const connections: INodeConnections = {
|
||||||
|
[NodeConnectionType.Main]: [
|
||||||
|
[
|
||||||
|
{ node: 'node1', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
{ node: 'node2', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
],
|
||||||
|
[{ node: 'node3', type: NodeConnectionType.Main, index: 0 }],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const includeNodeNames = new Set<string>();
|
||||||
|
|
||||||
|
const { filterConnectionsByNodes } = useCanvasOperations({ router });
|
||||||
|
const result = filterConnectionsByNodes(connections, includeNodeNames);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
[NodeConnectionType.Main]: [[], []],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return partially filtered connections when some nodes are included', () => {
|
||||||
|
const connections: INodeConnections = {
|
||||||
|
[NodeConnectionType.Main]: [
|
||||||
|
[
|
||||||
|
{ node: 'node1', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
{ node: 'node2', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
],
|
||||||
|
[{ node: 'node3', type: NodeConnectionType.Main, index: 0 }],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const includeNodeNames = new Set<string>(['node1']);
|
||||||
|
|
||||||
|
const { filterConnectionsByNodes } = useCanvasOperations({ router });
|
||||||
|
const result = filterConnectionsByNodes(connections, includeNodeNames);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
[NodeConnectionType.Main]: [
|
||||||
|
[{ node: 'node1', type: NodeConnectionType.Main, index: 0 }],
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty connections input', () => {
|
||||||
|
const connections: INodeConnections = {};
|
||||||
|
const includeNodeNames = new Set<string>(['node1']);
|
||||||
|
|
||||||
|
const { filterConnectionsByNodes } = useCanvasOperations({ router });
|
||||||
|
const result = filterConnectionsByNodes(connections, includeNodeNames);
|
||||||
|
|
||||||
|
expect(result).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle connections with no valid nodes', () => {
|
||||||
|
const connections: INodeConnections = {
|
||||||
|
[NodeConnectionType.Main]: [
|
||||||
|
[
|
||||||
|
{ node: 'node4', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
{ node: 'node5', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
],
|
||||||
|
[{ node: 'node6', type: NodeConnectionType.Main, index: 0 }],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const includeNodeNames = new Set<string>(['node1', 'node2', 'node3']);
|
||||||
|
|
||||||
|
const { filterConnectionsByNodes } = useCanvasOperations({ router });
|
||||||
|
const result = filterConnectionsByNodes(connections, includeNodeNames);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
[NodeConnectionType.Main]: [[], []],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function buildImportNodes() {
|
function buildImportNodes() {
|
||||||
return [
|
return [
|
||||||
mockNode({ id: '1', name: 'Node 1', type: SET_NODE_TYPE }),
|
mockNode({ id: '1', name: 'Node 1', type: SET_NODE_TYPE }),
|
||||||
|
|
|
@ -1809,17 +1809,15 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterConnectionsByNodes(
|
function filterConnectionsByNodes(
|
||||||
connections: Record<string, IConnection[][]>,
|
connections: INodeConnections,
|
||||||
includeNodeNames: Set<string>,
|
includeNodeNames: Set<string>,
|
||||||
): INodeConnections {
|
): INodeConnections {
|
||||||
const filteredConnections: INodeConnections = {};
|
const filteredConnections: INodeConnections = {};
|
||||||
|
|
||||||
for (const [type, typeConnections] of Object.entries(connections)) {
|
for (const [type, typeConnections] of Object.entries(connections)) {
|
||||||
const validConnections = typeConnections
|
const validConnections = typeConnections.map((sourceConnections) =>
|
||||||
.map((sourceConnections) =>
|
|
||||||
sourceConnections.filter((connection) => includeNodeNames.has(connection.node)),
|
sourceConnections.filter((connection) => includeNodeNames.has(connection.node)),
|
||||||
)
|
);
|
||||||
.filter((sourceConnections) => sourceConnections.length > 0);
|
|
||||||
|
|
||||||
if (validConnections.length) {
|
if (validConnections.length) {
|
||||||
filteredConnections[type] = validConnections;
|
filteredConnections[type] = validConnections;
|
||||||
|
@ -1888,6 +1886,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
revertDeleteConnection,
|
revertDeleteConnection,
|
||||||
deleteConnectionsByNodeId,
|
deleteConnectionsByNodeId,
|
||||||
isConnectionAllowed,
|
isConnectionAllowed,
|
||||||
|
filterConnectionsByNodes,
|
||||||
importWorkflowData,
|
importWorkflowData,
|
||||||
fetchWorkflowDataFromUrl,
|
fetchWorkflowDataFromUrl,
|
||||||
resetWorkspace,
|
resetWorkspace,
|
||||||
|
|
Loading…
Reference in a new issue