From ad292350b3206d92ffe69d0eea01a0c4f396781a Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Mon, 28 Oct 2024 17:47:12 +0200 Subject: [PATCH] fix(editor): Import copy-pasted workflow only after nodes are added to new canvas (no-changelog) (#11434) --- .../__tests__/useCanvasOperations.spec.ts | 24 +++++++++++++- .../src/composables/useCanvasOperations.ts | 31 ++++--------------- packages/editor-ui/src/types/canvas.ts | 2 ++ packages/editor-ui/src/views/NodeView.v2.vue | 16 ++++++++-- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/packages/editor-ui/src/composables/__tests__/useCanvasOperations.spec.ts b/packages/editor-ui/src/composables/__tests__/useCanvasOperations.spec.ts index d54f7ccbfc..7128c223fe 100644 --- a/packages/editor-ui/src/composables/__tests__/useCanvasOperations.spec.ts +++ b/packages/editor-ui/src/composables/__tests__/useCanvasOperations.spec.ts @@ -3,6 +3,7 @@ import type { IConnection, Workflow } from 'n8n-workflow'; import { NodeConnectionType, NodeHelpers } from 'n8n-workflow'; import { useCanvasOperations } from '@/composables/useCanvasOperations'; import type { CanvasNode } from '@/types'; +import { CanvasConnectionMode } from '@/types'; import type { ICredentialsResponse, INodeUi, IWorkflowDb } from '@/Interface'; import { RemoveNodeCommand } from '@/models/history'; import { useWorkflowsStore } from '@/stores/workflows.store'; @@ -25,6 +26,7 @@ import { mockedStore } from '@/__tests__/utils'; import { SET_NODE_TYPE, STICKY_NODE_TYPE, STORES } from '@/constants'; import type { Connection } from '@vue-flow/core'; import { useClipboard } from '@/composables/useClipboard'; +import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2'; vi.mock('vue-router', async (importOriginal) => { const actual = await importOriginal<{}>(); @@ -966,7 +968,17 @@ describe('useCanvasOperations', () => { const connections = [ { source: nodes[0].id, + sourceHandle: createCanvasConnectionHandleString({ + mode: CanvasConnectionMode.Output, + index: 0, + type: NodeConnectionType.Main, + }), target: nodes[1].id, + targetHandle: createCanvasConnectionHandleString({ + mode: CanvasConnectionMode.Input, + index: 0, + type: NodeConnectionType.Main, + }), data: { source: { type: NodeConnectionType.Main, index: 0 }, target: { type: NodeConnectionType.Main, index: 0 }, @@ -974,7 +986,17 @@ describe('useCanvasOperations', () => { }, { source: nodes[1].id, + sourceHandle: createCanvasConnectionHandleString({ + mode: CanvasConnectionMode.Output, + index: 0, + type: NodeConnectionType.Main, + }), target: nodes[2].id, + targetHandle: createCanvasConnectionHandleString({ + mode: CanvasConnectionMode.Input, + index: 0, + type: NodeConnectionType.Main, + }), data: { source: { type: NodeConnectionType.Main, index: 0 }, target: { type: NodeConnectionType.Main, index: 0 }, @@ -993,7 +1015,7 @@ describe('useCanvasOperations', () => { nodeTypesStore.getNodeType = vi.fn().mockReturnValue(nodeType); const { addConnections } = useCanvasOperations({ router }); - addConnections(connections); + await addConnections(connections); expect(workflowsStore.addConnection).toHaveBeenCalledWith({ connection: [ diff --git a/packages/editor-ui/src/composables/useCanvasOperations.ts b/packages/editor-ui/src/composables/useCanvasOperations.ts index 4ee13581d2..3950e16ecf 100644 --- a/packages/editor-ui/src/composables/useCanvasOperations.ts +++ b/packages/editor-ui/src/composables/useCanvasOperations.ts @@ -71,7 +71,6 @@ import { generateOffsets, PUSH_NODES_OFFSET, } from '@/utils/nodeViewUtils'; -import { isValidNodeConnectionType } from '@/utils/typeGuards'; import type { Connection } from '@vue-flow/core'; import type { IConnection, @@ -1374,36 +1373,18 @@ export function useCanvasOperations({ router }: { router: ReturnType; export type CanvasConnectionCreateData = { source: string; + sourceHandle: string; target: string; + targetHandle: string; data: { source: PartialBy; target: PartialBy; diff --git a/packages/editor-ui/src/views/NodeView.v2.vue b/packages/editor-ui/src/views/NodeView.v2.vue index 60f4f8983b..95dee594a7 100644 --- a/packages/editor-ui/src/views/NodeView.v2.vue +++ b/packages/editor-ui/src/views/NodeView.v2.vue @@ -46,7 +46,7 @@ import type { CanvasNodeMoveEvent, ConnectStartEvent, } from '@/types'; -import { CanvasNodeRenderType } from '@/types'; +import { CanvasNodeRenderType, CanvasConnectionMode } from '@/types'; import { CHAT_TRIGGER_NODE_TYPE, EnterpriseEditionFeature, @@ -105,6 +105,8 @@ import { useClipboard } from '@/composables/useClipboard'; import { useBeforeUnload } from '@/composables/useBeforeUnload'; import { getResourcePermissions } from '@/permissions'; import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue'; +import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2'; +import { isValidNodeConnectionType } from '@/utils/typeGuards'; const LazyNodeCreation = defineAsyncComponent( async () => await import('@/components/Node/NodeCreation.vue'), @@ -879,7 +881,17 @@ async function onAddNodesAndConnections( return { source: fromNode.id, + sourceHandle: createCanvasConnectionHandleString({ + mode: CanvasConnectionMode.Output, + type: isValidNodeConnectionType(type) ? type : NodeConnectionType.Main, + index: from.outputIndex ?? 0, + }), target: toNode.id, + targetHandle: createCanvasConnectionHandleString({ + mode: CanvasConnectionMode.Input, + type: isValidNodeConnectionType(type) ? type : NodeConnectionType.Main, + index: to.inputIndex ?? 0, + }), data: { source: { index: from.outputIndex ?? 0, @@ -893,7 +905,7 @@ async function onAddNodesAndConnections( }; }); - addConnections(mappedConnections); + await addConnections(mappedConnections); uiStore.resetLastInteractedWith(); selectNodes([addedNodes[addedNodes.length - 1].id]);