mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Import copy-pasted workflow only after nodes are added to new canvas (no-changelog) (#11434)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
This commit is contained in:
parent
d4c4db823e
commit
ad292350b3
|
@ -3,6 +3,7 @@ import type { IConnection, 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';
|
||||||
import type { CanvasNode } from '@/types';
|
import type { CanvasNode } from '@/types';
|
||||||
|
import { CanvasConnectionMode } from '@/types';
|
||||||
import type { ICredentialsResponse, INodeUi, IWorkflowDb } from '@/Interface';
|
import type { ICredentialsResponse, INodeUi, IWorkflowDb } from '@/Interface';
|
||||||
import { RemoveNodeCommand } from '@/models/history';
|
import { RemoveNodeCommand } from '@/models/history';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
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 { SET_NODE_TYPE, STICKY_NODE_TYPE, STORES } from '@/constants';
|
||||||
import type { Connection } from '@vue-flow/core';
|
import type { Connection } from '@vue-flow/core';
|
||||||
import { useClipboard } from '@/composables/useClipboard';
|
import { useClipboard } from '@/composables/useClipboard';
|
||||||
|
import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2';
|
||||||
|
|
||||||
vi.mock('vue-router', async (importOriginal) => {
|
vi.mock('vue-router', async (importOriginal) => {
|
||||||
const actual = await importOriginal<{}>();
|
const actual = await importOriginal<{}>();
|
||||||
|
@ -966,7 +968,17 @@ describe('useCanvasOperations', () => {
|
||||||
const connections = [
|
const connections = [
|
||||||
{
|
{
|
||||||
source: nodes[0].id,
|
source: nodes[0].id,
|
||||||
|
sourceHandle: createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Output,
|
||||||
|
index: 0,
|
||||||
|
type: NodeConnectionType.Main,
|
||||||
|
}),
|
||||||
target: nodes[1].id,
|
target: nodes[1].id,
|
||||||
|
targetHandle: createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Input,
|
||||||
|
index: 0,
|
||||||
|
type: NodeConnectionType.Main,
|
||||||
|
}),
|
||||||
data: {
|
data: {
|
||||||
source: { type: NodeConnectionType.Main, index: 0 },
|
source: { type: NodeConnectionType.Main, index: 0 },
|
||||||
target: { type: NodeConnectionType.Main, index: 0 },
|
target: { type: NodeConnectionType.Main, index: 0 },
|
||||||
|
@ -974,7 +986,17 @@ describe('useCanvasOperations', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: nodes[1].id,
|
source: nodes[1].id,
|
||||||
|
sourceHandle: createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Output,
|
||||||
|
index: 0,
|
||||||
|
type: NodeConnectionType.Main,
|
||||||
|
}),
|
||||||
target: nodes[2].id,
|
target: nodes[2].id,
|
||||||
|
targetHandle: createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Input,
|
||||||
|
index: 0,
|
||||||
|
type: NodeConnectionType.Main,
|
||||||
|
}),
|
||||||
data: {
|
data: {
|
||||||
source: { type: NodeConnectionType.Main, index: 0 },
|
source: { type: NodeConnectionType.Main, index: 0 },
|
||||||
target: { type: NodeConnectionType.Main, index: 0 },
|
target: { type: NodeConnectionType.Main, index: 0 },
|
||||||
|
@ -993,7 +1015,7 @@ describe('useCanvasOperations', () => {
|
||||||
nodeTypesStore.getNodeType = vi.fn().mockReturnValue(nodeType);
|
nodeTypesStore.getNodeType = vi.fn().mockReturnValue(nodeType);
|
||||||
|
|
||||||
const { addConnections } = useCanvasOperations({ router });
|
const { addConnections } = useCanvasOperations({ router });
|
||||||
addConnections(connections);
|
await addConnections(connections);
|
||||||
|
|
||||||
expect(workflowsStore.addConnection).toHaveBeenCalledWith({
|
expect(workflowsStore.addConnection).toHaveBeenCalledWith({
|
||||||
connection: [
|
connection: [
|
||||||
|
|
|
@ -71,7 +71,6 @@ import {
|
||||||
generateOffsets,
|
generateOffsets,
|
||||||
PUSH_NODES_OFFSET,
|
PUSH_NODES_OFFSET,
|
||||||
} from '@/utils/nodeViewUtils';
|
} from '@/utils/nodeViewUtils';
|
||||||
import { isValidNodeConnectionType } from '@/utils/typeGuards';
|
|
||||||
import type { Connection } from '@vue-flow/core';
|
import type { Connection } from '@vue-flow/core';
|
||||||
import type {
|
import type {
|
||||||
IConnection,
|
IConnection,
|
||||||
|
@ -1374,36 +1373,18 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
return targetNodeHasInputConnectionOfType && targetNodeHasInputConnectionPortOfType;
|
return targetNodeHasInputConnectionOfType && targetNodeHasInputConnectionPortOfType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addConnections(
|
async function addConnections(
|
||||||
connections: CanvasConnectionCreateData[] | CanvasConnection[],
|
connections: CanvasConnectionCreateData[] | CanvasConnection[],
|
||||||
{ trackBulk = true, trackHistory = false } = {},
|
{ trackBulk = true, trackHistory = false } = {},
|
||||||
) {
|
) {
|
||||||
|
await nextTick(); // Connection creation relies on the nodes being already added to the store
|
||||||
|
|
||||||
if (trackBulk && trackHistory) {
|
if (trackBulk && trackHistory) {
|
||||||
historyStore.startRecordingUndo();
|
historyStore.startRecordingUndo();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const { source, target, data } of connections) {
|
for (const connection of connections) {
|
||||||
createConnection(
|
createConnection(connection, { trackHistory });
|
||||||
{
|
|
||||||
source,
|
|
||||||
sourceHandle: createCanvasConnectionHandleString({
|
|
||||||
mode: CanvasConnectionMode.Output,
|
|
||||||
type: isValidNodeConnectionType(data?.source.type)
|
|
||||||
? data?.source.type
|
|
||||||
: NodeConnectionType.Main,
|
|
||||||
index: data?.source.index ?? 0,
|
|
||||||
}),
|
|
||||||
target,
|
|
||||||
targetHandle: createCanvasConnectionHandleString({
|
|
||||||
mode: CanvasConnectionMode.Input,
|
|
||||||
type: isValidNodeConnectionType(data?.target.type)
|
|
||||||
? data?.target.type
|
|
||||||
: NodeConnectionType.Main,
|
|
||||||
index: data?.target.index ?? 0,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{ trackHistory },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackBulk && trackHistory) {
|
if (trackBulk && trackHistory) {
|
||||||
|
@ -1621,7 +1602,7 @@ export function useCanvasOperations({ router }: { router: ReturnType<typeof useR
|
||||||
}
|
}
|
||||||
|
|
||||||
await addNodes(Object.values(tempWorkflow.nodes), { trackBulk: false, trackHistory });
|
await addNodes(Object.values(tempWorkflow.nodes), { trackBulk: false, trackHistory });
|
||||||
addConnections(
|
await addConnections(
|
||||||
mapLegacyConnectionsToCanvasConnections(
|
mapLegacyConnectionsToCanvasConnections(
|
||||||
tempWorkflow.connectionsBySourceNode,
|
tempWorkflow.connectionsBySourceNode,
|
||||||
Object.values(tempWorkflow.nodes),
|
Object.values(tempWorkflow.nodes),
|
||||||
|
|
|
@ -124,7 +124,9 @@ export type CanvasConnection = DefaultEdge<CanvasConnectionData>;
|
||||||
|
|
||||||
export type CanvasConnectionCreateData = {
|
export type CanvasConnectionCreateData = {
|
||||||
source: string;
|
source: string;
|
||||||
|
sourceHandle: string;
|
||||||
target: string;
|
target: string;
|
||||||
|
targetHandle: string;
|
||||||
data: {
|
data: {
|
||||||
source: PartialBy<IConnection, 'node'>;
|
source: PartialBy<IConnection, 'node'>;
|
||||||
target: PartialBy<IConnection, 'node'>;
|
target: PartialBy<IConnection, 'node'>;
|
||||||
|
|
|
@ -46,7 +46,7 @@ import type {
|
||||||
CanvasNodeMoveEvent,
|
CanvasNodeMoveEvent,
|
||||||
ConnectStartEvent,
|
ConnectStartEvent,
|
||||||
} from '@/types';
|
} from '@/types';
|
||||||
import { CanvasNodeRenderType } from '@/types';
|
import { CanvasNodeRenderType, CanvasConnectionMode } from '@/types';
|
||||||
import {
|
import {
|
||||||
CHAT_TRIGGER_NODE_TYPE,
|
CHAT_TRIGGER_NODE_TYPE,
|
||||||
EnterpriseEditionFeature,
|
EnterpriseEditionFeature,
|
||||||
|
@ -105,6 +105,8 @@ import { useClipboard } from '@/composables/useClipboard';
|
||||||
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
||||||
import { getResourcePermissions } from '@/permissions';
|
import { getResourcePermissions } from '@/permissions';
|
||||||
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
||||||
|
import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2';
|
||||||
|
import { isValidNodeConnectionType } from '@/utils/typeGuards';
|
||||||
|
|
||||||
const LazyNodeCreation = defineAsyncComponent(
|
const LazyNodeCreation = defineAsyncComponent(
|
||||||
async () => await import('@/components/Node/NodeCreation.vue'),
|
async () => await import('@/components/Node/NodeCreation.vue'),
|
||||||
|
@ -879,7 +881,17 @@ async function onAddNodesAndConnections(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
source: fromNode.id,
|
source: fromNode.id,
|
||||||
|
sourceHandle: createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Output,
|
||||||
|
type: isValidNodeConnectionType(type) ? type : NodeConnectionType.Main,
|
||||||
|
index: from.outputIndex ?? 0,
|
||||||
|
}),
|
||||||
target: toNode.id,
|
target: toNode.id,
|
||||||
|
targetHandle: createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Input,
|
||||||
|
type: isValidNodeConnectionType(type) ? type : NodeConnectionType.Main,
|
||||||
|
index: to.inputIndex ?? 0,
|
||||||
|
}),
|
||||||
data: {
|
data: {
|
||||||
source: {
|
source: {
|
||||||
index: from.outputIndex ?? 0,
|
index: from.outputIndex ?? 0,
|
||||||
|
@ -893,7 +905,7 @@ async function onAddNodesAndConnections(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
addConnections(mappedConnections);
|
await addConnections(mappedConnections);
|
||||||
|
|
||||||
uiStore.resetLastInteractedWith();
|
uiStore.resetLastInteractedWith();
|
||||||
selectNodes([addedNodes[addedNodes.length - 1].id]);
|
selectNodes([addedNodes[addedNodes.length - 1].id]);
|
||||||
|
|
Loading…
Reference in a new issue