mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-19 11:01:15 +00:00
refactor(editor): Remove part of getCurrentWorkflow usages (#16148)
This commit is contained in:
@@ -174,8 +174,7 @@ function useJsonFieldCompletions() {
|
||||
try {
|
||||
const activeNode = ndvStore.activeNode;
|
||||
if (activeNode) {
|
||||
const workflow = workflowsStore.getCurrentWorkflow();
|
||||
const input = workflow.connectionsByDestinationNode[activeNode.name];
|
||||
const input = workflowsStore.connectionsByDestinationNode[activeNode.name];
|
||||
return input.main[0] ? input.main[0][0].node : null;
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -84,7 +84,7 @@ function getMultipleNodesText(nodeName: string): string {
|
||||
return '';
|
||||
|
||||
const activeNodeConnections =
|
||||
props.workflow.connectionsByDestinationNode[activeNode.value.name].main || [];
|
||||
workflowsStore.connectionsByDestinationNode[activeNode.value.name].main || [];
|
||||
// Collect indexes of connected nodes
|
||||
const connectedInputIndexes = activeNodeConnections.reduce((acc: number[], node, index) => {
|
||||
if (node?.[0] && node[0].node === nodeName) return [...acc, index];
|
||||
|
||||
@@ -804,7 +804,8 @@ function getNodeHints(): NodeHint[] {
|
||||
node: node.value,
|
||||
nodeType: nodeType.value,
|
||||
nodeOutputData,
|
||||
workflow: props.workflow,
|
||||
nodes: workflowsStore.allNodes,
|
||||
connections: workflowsStore.connectionsBySourceNode,
|
||||
hasNodeRun: hasNodeRun.value,
|
||||
hasMultipleInputItems,
|
||||
});
|
||||
|
||||
@@ -114,6 +114,7 @@ const expressionResolveCtx = computed<ExpressionLocalResolveContext | undefined>
|
||||
nodeName,
|
||||
additionalKeys: {},
|
||||
inputNode: findInputNode(),
|
||||
connections: workflowsStore.connectionsBySourceNode,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -216,6 +216,8 @@ describe('useCanvasMapping', () => {
|
||||
});
|
||||
|
||||
it('should handle input and output connections', () => {
|
||||
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||
|
||||
const [manualTriggerNode, setNode] = mockNodes.slice(0, 2);
|
||||
const nodes = [manualTriggerNode, setNode];
|
||||
const connections = {
|
||||
@@ -225,6 +227,9 @@ describe('useCanvasMapping', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
workflowsStore.workflow.connections = connections;
|
||||
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes,
|
||||
connections,
|
||||
|
||||
@@ -59,6 +59,7 @@ import { useNodeHelpers } from './useNodeHelpers';
|
||||
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
||||
import { useNodeDirtiness } from '@/composables/useNodeDirtiness';
|
||||
import { getNodeIconSource } from '../utils/nodeIcon';
|
||||
import * as workflowUtils from 'n8n-workflow/common';
|
||||
|
||||
export function useCanvasMapping({
|
||||
nodes,
|
||||
@@ -571,56 +572,62 @@ export function useCanvasMapping({
|
||||
}, {});
|
||||
});
|
||||
|
||||
const mappedNodes = computed<CanvasNode[]>(() => [
|
||||
...nodes.value.map<CanvasNode>((node) => {
|
||||
const inputConnections = workflowObject.value.connectionsByDestinationNode[node.name] ?? {};
|
||||
const outputConnections = workflowObject.value.connectionsBySourceNode[node.name] ?? {};
|
||||
const mappedNodes = computed<CanvasNode[]>(() => {
|
||||
const connectionsBySourceNode = connections.value;
|
||||
const connectionsByDestinationNode =
|
||||
workflowUtils.mapConnectionsByDestination(connectionsBySourceNode);
|
||||
|
||||
const data: CanvasNodeData = {
|
||||
id: node.id,
|
||||
name: node.name,
|
||||
subtitle: nodeSubtitleById.value[node.id] ?? '',
|
||||
type: node.type,
|
||||
typeVersion: node.typeVersion,
|
||||
disabled: node.disabled,
|
||||
inputs: nodeInputsById.value[node.id] ?? [],
|
||||
outputs: nodeOutputsById.value[node.id] ?? [],
|
||||
connections: {
|
||||
[CanvasConnectionMode.Input]: inputConnections,
|
||||
[CanvasConnectionMode.Output]: outputConnections,
|
||||
},
|
||||
issues: {
|
||||
items: nodeIssuesById.value[node.id],
|
||||
visible: nodeHasIssuesById.value[node.id],
|
||||
},
|
||||
pinnedData: {
|
||||
count: nodePinnedDataById.value[node.id]?.length ?? 0,
|
||||
visible: !!nodePinnedDataById.value[node.id],
|
||||
},
|
||||
execution: {
|
||||
status: nodeExecutionStatusById.value[node.id],
|
||||
waiting: nodeExecutionWaitingById.value[node.id],
|
||||
waitingForNext: nodeExecutionWaitingForNextById.value[node.id],
|
||||
running: nodeExecutionRunningById.value[node.id],
|
||||
},
|
||||
runData: {
|
||||
outputMap: nodeExecutionRunDataOutputMapById.value[node.id],
|
||||
iterations: nodeExecutionRunDataById.value[node.id]?.length ?? 0,
|
||||
visible: !!nodeExecutionRunDataById.value[node.id],
|
||||
},
|
||||
render: renderTypeByNodeId.value[node.id] ?? { type: 'default', options: {} },
|
||||
};
|
||||
return [
|
||||
...nodes.value.map<CanvasNode>((node) => {
|
||||
const outputConnections = connectionsBySourceNode[node.name] ?? {};
|
||||
const inputConnections = connectionsByDestinationNode[node.name] ?? {};
|
||||
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.name,
|
||||
type: 'canvas-node',
|
||||
position: { x: node.position[0], y: node.position[1] },
|
||||
data,
|
||||
...additionalNodePropertiesById.value[node.id],
|
||||
};
|
||||
}),
|
||||
]);
|
||||
const data: CanvasNodeData = {
|
||||
id: node.id,
|
||||
name: node.name,
|
||||
subtitle: nodeSubtitleById.value[node.id] ?? '',
|
||||
type: node.type,
|
||||
typeVersion: node.typeVersion,
|
||||
disabled: node.disabled,
|
||||
inputs: nodeInputsById.value[node.id] ?? [],
|
||||
outputs: nodeOutputsById.value[node.id] ?? [],
|
||||
connections: {
|
||||
[CanvasConnectionMode.Input]: inputConnections,
|
||||
[CanvasConnectionMode.Output]: outputConnections,
|
||||
},
|
||||
issues: {
|
||||
items: nodeIssuesById.value[node.id],
|
||||
visible: nodeHasIssuesById.value[node.id],
|
||||
},
|
||||
pinnedData: {
|
||||
count: nodePinnedDataById.value[node.id]?.length ?? 0,
|
||||
visible: !!nodePinnedDataById.value[node.id],
|
||||
},
|
||||
execution: {
|
||||
status: nodeExecutionStatusById.value[node.id],
|
||||
waiting: nodeExecutionWaitingById.value[node.id],
|
||||
waitingForNext: nodeExecutionWaitingForNextById.value[node.id],
|
||||
running: nodeExecutionRunningById.value[node.id],
|
||||
},
|
||||
runData: {
|
||||
outputMap: nodeExecutionRunDataOutputMapById.value[node.id],
|
||||
iterations: nodeExecutionRunDataById.value[node.id]?.length ?? 0,
|
||||
visible: !!nodeExecutionRunDataById.value[node.id],
|
||||
},
|
||||
render: renderTypeByNodeId.value[node.id] ?? { type: 'default', options: {} },
|
||||
};
|
||||
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.name,
|
||||
type: 'canvas-node',
|
||||
position: { x: node.position[0], y: node.position[1] },
|
||||
data,
|
||||
...additionalNodePropertiesById.value[node.id],
|
||||
};
|
||||
}),
|
||||
];
|
||||
});
|
||||
|
||||
const mappedConnections = computed<CanvasConnection[]>(() => {
|
||||
return mapLegacyConnectionsToCanvasConnections(connections.value ?? [], nodes.value ?? []).map(
|
||||
|
||||
@@ -253,6 +253,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||
if (sourceData === null) {
|
||||
const parentNodes = workflow.getParentNodes(name, NodeConnectionTypes.Main, 1);
|
||||
const executeData = workflowHelpers.executeData(
|
||||
workflow.connectionsBySourceNode,
|
||||
parentNodes,
|
||||
name,
|
||||
NodeConnectionTypes.Main,
|
||||
|
||||
@@ -14,11 +14,8 @@ import {
|
||||
createTestWorkflowExecutionResponse,
|
||||
createTestWorkflowObject,
|
||||
} from '@/__tests__/mocks';
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
WEBHOOK_NODE_TYPE,
|
||||
type AssignmentCollectionValue,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, WEBHOOK_NODE_TYPE } from 'n8n-workflow';
|
||||
import type { AssignmentCollectionValue, IConnections } from 'n8n-workflow';
|
||||
import * as apiWebhooks from '@n8n/rest-api-client/api/webhooks';
|
||||
import { mockedStore } from '@/__tests__/utils';
|
||||
|
||||
@@ -519,7 +516,7 @@ describe('useWorkflowHelpers', () => {
|
||||
const inputName = 'main';
|
||||
const runIndex = 0;
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const result = executeData({}, parentNodes, currentNode, inputName, runIndex);
|
||||
|
||||
expect(result).toEqual({
|
||||
node: {},
|
||||
@@ -538,18 +535,15 @@ describe('useWorkflowHelpers', () => {
|
||||
const jsonData = {
|
||||
name: 'Test',
|
||||
};
|
||||
workflowsStore.getCurrentWorkflow.mockReturnValue({
|
||||
connectionsByDestinationNode: {
|
||||
Set: {
|
||||
main: [
|
||||
[
|
||||
{ node: 'Start', index: 0, type: 'main' },
|
||||
{ node: 'Set', index: 0, type: 'main' },
|
||||
],
|
||||
],
|
||||
},
|
||||
|
||||
const connectionsBySourceNode: IConnections = {
|
||||
Start: {
|
||||
main: [[{ node: 'Set', index: 0, type: 'main' }]],
|
||||
},
|
||||
} as never);
|
||||
Set: {
|
||||
main: [[{ node: 'Start', index: 0, type: 'main' }]],
|
||||
},
|
||||
};
|
||||
|
||||
workflowsStore.workflowExecutionData = {
|
||||
data: {
|
||||
@@ -575,7 +569,13 @@ describe('useWorkflowHelpers', () => {
|
||||
},
|
||||
} as unknown as IExecutionResponse;
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const result = executeData(
|
||||
connectionsBySourceNode,
|
||||
parentNodes,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
node: {},
|
||||
@@ -609,18 +609,15 @@ describe('useWorkflowHelpers', () => {
|
||||
const jsonData = {
|
||||
name: 'Test',
|
||||
};
|
||||
workflowsStore.getCurrentWorkflow.mockReturnValue({
|
||||
connectionsByDestinationNode: {
|
||||
Set: {
|
||||
main: [
|
||||
[
|
||||
{ node: 'Start', index: 0, type: 'main' },
|
||||
{ node: 'Set', index: 0, type: 'main' },
|
||||
],
|
||||
],
|
||||
},
|
||||
|
||||
const connectionsBySourceNode: IConnections = {
|
||||
Start: {
|
||||
main: [[{ node: 'Set', index: 0, type: 'main' }]],
|
||||
},
|
||||
} as never);
|
||||
Set: {
|
||||
main: [[{ node: 'Start', index: 0, type: 'main' }]],
|
||||
},
|
||||
};
|
||||
|
||||
workflowsStore.workflowExecutionData = {
|
||||
data: {
|
||||
@@ -646,7 +643,13 @@ describe('useWorkflowHelpers', () => {
|
||||
},
|
||||
} as unknown as IExecutionResponse;
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const result = executeData(
|
||||
connectionsBySourceNode,
|
||||
parentNodes,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
node: {},
|
||||
@@ -686,22 +689,20 @@ describe('useWorkflowHelpers', () => {
|
||||
name: 'Test B',
|
||||
};
|
||||
|
||||
workflowsStore.getCurrentWorkflow.mockReturnValue({
|
||||
connectionsByDestinationNode: {
|
||||
Set: {
|
||||
main: [
|
||||
[
|
||||
{ node: 'Parent A', index: 0, type: 'main' },
|
||||
{ node: 'Set', index: 0, type: 'main' },
|
||||
],
|
||||
[
|
||||
{ node: 'Parent B', index: 0, type: 'main' },
|
||||
{ node: 'Set', index: 0, type: 'main' },
|
||||
],
|
||||
],
|
||||
},
|
||||
const connectionsBySourceNode: IConnections = {
|
||||
'Parent A': {
|
||||
main: [[{ node: 'Set', type: 'main', index: 0 }]],
|
||||
},
|
||||
} as never);
|
||||
'Parent B': {
|
||||
main: [[{ node: 'Set', type: 'main', index: 1 }]],
|
||||
},
|
||||
Set: {
|
||||
main: [
|
||||
[{ node: 'Set', type: 'main', index: 0 }],
|
||||
[{ node: 'Set', type: 'main', index: 1 }],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
workflowsStore.workflowExecutionData = {
|
||||
data: {
|
||||
@@ -742,7 +743,13 @@ describe('useWorkflowHelpers', () => {
|
||||
},
|
||||
} as unknown as IExecutionResponse;
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const result = executeData(
|
||||
connectionsBySourceNode,
|
||||
parentNodes,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
node: {},
|
||||
@@ -779,7 +786,7 @@ describe('useWorkflowHelpers', () => {
|
||||
};
|
||||
workflowsStore.shouldReplaceInputDataWithPinData = true;
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const result = executeData({}, parentNodes, currentNode, inputName, runIndex);
|
||||
|
||||
expect(result.data).toEqual({ main: [[{ json: { key: 'value' } }]] });
|
||||
expect(result.source).toEqual({ main: [{ previousNode: 'ParentNode' }] });
|
||||
@@ -802,20 +809,23 @@ describe('useWorkflowHelpers', () => {
|
||||
} as never,
|
||||
],
|
||||
};
|
||||
workflowsStore.getCurrentWorkflow.mockReturnValue({
|
||||
connectionsByDestinationNode: {
|
||||
CurrentNode: {
|
||||
main: [
|
||||
[
|
||||
{ node: 'ParentNode', index: 0, type: 'main' },
|
||||
{ node: 'CurrentNode', index: 0, type: 'main' },
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
} as never);
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const connectionsBySourceNode: IConnections = {
|
||||
CurrentNode: {
|
||||
main: [[{ node: 'CurrentNode', index: 0, type: 'main' }]],
|
||||
},
|
||||
ParentNode: {
|
||||
main: [[{ node: 'CurrentNode', index: 0, type: 'main' }]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = executeData(
|
||||
connectionsBySourceNode,
|
||||
parentNodes,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
);
|
||||
|
||||
expect(result.data).toEqual({ main: [[{ json: { key: 'valueFromRunData' } }]] });
|
||||
expect(result.source).toEqual({
|
||||
@@ -841,20 +851,24 @@ describe('useWorkflowHelpers', () => {
|
||||
} as never,
|
||||
],
|
||||
};
|
||||
workflowsStore.getCurrentWorkflow.mockReturnValue({
|
||||
connectionsByDestinationNode: {
|
||||
CurrentNode: {
|
||||
main: [
|
||||
[
|
||||
{ node: 'ParentNode', index: 1, type: 'main' },
|
||||
{ node: 'CurrentNode', index: 0, type: 'main' },
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
} as never);
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex, parentRunIndex);
|
||||
const connectionsBySourceNode: IConnections = {
|
||||
CurrentNode: {
|
||||
main: [[{ node: 'CurrentNode', index: 0, type: 'main' }]],
|
||||
},
|
||||
ParentNode: {
|
||||
main: [[], [{ node: 'CurrentNode', index: 1, type: 'main' }]],
|
||||
},
|
||||
};
|
||||
|
||||
const result = executeData(
|
||||
connectionsBySourceNode,
|
||||
parentNodes,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
parentRunIndex,
|
||||
);
|
||||
|
||||
expect(result.data).toEqual({ main: [[{ json: { key: 'valueFromRunData' } }]] });
|
||||
expect(result.source).toEqual({
|
||||
@@ -874,7 +888,7 @@ describe('useWorkflowHelpers', () => {
|
||||
workflowsStore.shouldReplaceInputDataWithPinData = false;
|
||||
workflowsStore.getWorkflowRunData = null;
|
||||
|
||||
const result = executeData(parentNodes, currentNode, inputName, runIndex);
|
||||
const result = executeData({}, parentNodes, currentNode, inputName, runIndex);
|
||||
|
||||
expect(result.data).toEqual({});
|
||||
expect(result.source).toBeNull();
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
NodeHelpers,
|
||||
WEBHOOK_NODE_TYPE,
|
||||
} from 'n8n-workflow';
|
||||
import * as workflowUtils from 'n8n-workflow/common';
|
||||
|
||||
import type {
|
||||
ICredentialsResponse,
|
||||
@@ -71,6 +72,7 @@ export type ResolveParameterOptions = {
|
||||
additionalKeys?: IWorkflowDataProxyAdditionalKeys;
|
||||
isForCredential?: boolean;
|
||||
contextNodeName?: string;
|
||||
connections?: IConnections;
|
||||
};
|
||||
|
||||
export function resolveParameter<T = IDataObject>(
|
||||
@@ -81,6 +83,7 @@ export function resolveParameter<T = IDataObject>(
|
||||
return resolveParameterImpl(
|
||||
parameter,
|
||||
() => opts.workflow,
|
||||
opts.connections,
|
||||
opts.envVars,
|
||||
opts.workflow.getNode(opts.nodeName),
|
||||
opts.execution,
|
||||
@@ -100,6 +103,7 @@ export function resolveParameter<T = IDataObject>(
|
||||
return resolveParameterImpl(
|
||||
parameter,
|
||||
workflowsStore.getCurrentWorkflow,
|
||||
workflowsStore.connectionsBySourceNode,
|
||||
useEnvironmentsStore().variablesAsObject,
|
||||
useNDVStore().activeNode,
|
||||
workflowsStore.workflowExecutionData,
|
||||
@@ -113,6 +117,7 @@ export function resolveParameter<T = IDataObject>(
|
||||
function resolveParameterImpl<T = IDataObject>(
|
||||
parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
getContextWorkflow: () => Workflow,
|
||||
connections: IConnections,
|
||||
envVars: Record<string, string | boolean | number>,
|
||||
ndvActiveNode: INodeUi | null,
|
||||
executionData: IExecutionResponse | null,
|
||||
@@ -200,11 +205,11 @@ function resolveParameterImpl<T = IDataObject>(
|
||||
}
|
||||
|
||||
let _connectionInputData = connectionInputData(
|
||||
connections,
|
||||
parentNode,
|
||||
contextNode!.name,
|
||||
inputName,
|
||||
runIndexParent,
|
||||
getContextWorkflow,
|
||||
shouldReplaceInputDataWithPinData,
|
||||
pinData,
|
||||
executionData?.data?.resultData.runData ?? null,
|
||||
@@ -215,11 +220,11 @@ function resolveParameterImpl<T = IDataObject>(
|
||||
// For Sub-Nodes connected to Trigger-Nodes use the data of the root-node
|
||||
// (Gets for example used by the Memory connected to the Chat-Trigger-Node)
|
||||
const _executeData = executeDataImpl(
|
||||
connections,
|
||||
[contextNode.name],
|
||||
contextNode.name,
|
||||
inputName,
|
||||
0,
|
||||
getContextWorkflow,
|
||||
shouldReplaceInputDataWithPinData,
|
||||
pinData,
|
||||
executionData?.data?.resultData.runData ?? null,
|
||||
@@ -265,11 +270,11 @@ function resolveParameterImpl<T = IDataObject>(
|
||||
runIndexCurrent = workflowRunData[contextNode!.name].length - 1;
|
||||
}
|
||||
let _executeData = executeDataImpl(
|
||||
connections,
|
||||
parentNode,
|
||||
contextNode!.name,
|
||||
inputName,
|
||||
runIndexCurrent,
|
||||
getContextWorkflow,
|
||||
shouldReplaceInputDataWithPinData,
|
||||
pinData,
|
||||
executionData?.data?.resultData.runData ?? null,
|
||||
@@ -279,11 +284,11 @@ function resolveParameterImpl<T = IDataObject>(
|
||||
if (!_executeData.source) {
|
||||
// fallback to parent's run index for multi-output case
|
||||
_executeData = executeDataImpl(
|
||||
connections,
|
||||
parentNode,
|
||||
contextNode!.name,
|
||||
inputName,
|
||||
runIndexParent,
|
||||
getContextWorkflow,
|
||||
shouldReplaceInputDataWithPinData,
|
||||
pinData,
|
||||
executionData?.data?.resultData.runData ?? null,
|
||||
@@ -310,6 +315,7 @@ export function resolveRequiredParameters(
|
||||
currentParameter: INodeProperties,
|
||||
parameters: INodeParameters,
|
||||
opts: {
|
||||
connections?: IConnections;
|
||||
targetItem?: TargetItem;
|
||||
inputNodeName?: string;
|
||||
inputRunIndex?: number;
|
||||
@@ -382,11 +388,11 @@ function getNodeTypes(): INodeTypes {
|
||||
// TODO: move to separate file
|
||||
// Returns connectionInputData to be able to execute an expression.
|
||||
function connectionInputData(
|
||||
connections: IConnections,
|
||||
parentNode: string[],
|
||||
currentNode: string,
|
||||
inputName: string,
|
||||
runIndex: number,
|
||||
getContextWorkflow: () => Workflow,
|
||||
shouldReplaceInputDataWithPinData: boolean,
|
||||
pinData: IPinData | undefined,
|
||||
workflowRunData: IRunData | null,
|
||||
@@ -394,11 +400,11 @@ function connectionInputData(
|
||||
): INodeExecutionData[] | null {
|
||||
let connectionInputData: INodeExecutionData[] | null = null;
|
||||
const _executeData = executeDataImpl(
|
||||
connections,
|
||||
parentNode,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
getContextWorkflow,
|
||||
shouldReplaceInputDataWithPinData,
|
||||
pinData,
|
||||
workflowRunData,
|
||||
@@ -431,6 +437,7 @@ function connectionInputData(
|
||||
}
|
||||
|
||||
export function executeData(
|
||||
connections: IConnections,
|
||||
parentNodes: string[],
|
||||
currentNode: string,
|
||||
inputName: string,
|
||||
@@ -440,11 +447,11 @@ export function executeData(
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
|
||||
return executeDataImpl(
|
||||
connections,
|
||||
parentNodes,
|
||||
currentNode,
|
||||
inputName,
|
||||
runIndex,
|
||||
workflowsStore.getCurrentWorkflow,
|
||||
workflowsStore.shouldReplaceInputDataWithPinData,
|
||||
workflowsStore.pinnedWorkflowData,
|
||||
workflowsStore.getWorkflowRunData,
|
||||
@@ -454,16 +461,18 @@ export function executeData(
|
||||
|
||||
// TODO: move to separate file
|
||||
function executeDataImpl(
|
||||
connections: IConnections,
|
||||
parentNodes: string[],
|
||||
currentNode: string,
|
||||
inputName: string,
|
||||
runIndex: number,
|
||||
getContextWorkflow: () => Workflow,
|
||||
shouldReplaceInputDataWithPinData: boolean,
|
||||
pinData: IPinData | undefined,
|
||||
workflowRunData: IRunData | null,
|
||||
parentRunIndex?: number,
|
||||
): IExecuteData {
|
||||
const connectionsByDestinationNode = workflowUtils.mapConnectionsByDestination(connections);
|
||||
|
||||
const executeData = {
|
||||
node: {},
|
||||
data: {},
|
||||
@@ -507,15 +516,12 @@ function executeDataImpl(
|
||||
[inputName]: workflowRunData[currentNode][runIndex].source,
|
||||
};
|
||||
} else {
|
||||
const workflow = getContextWorkflow();
|
||||
|
||||
let previousNodeOutput: number | undefined;
|
||||
// As the node can be connected through either of the outputs find the correct one
|
||||
// and set it to make pairedItem work on not executed nodes
|
||||
if (workflow.connectionsByDestinationNode[currentNode]?.main) {
|
||||
mainConnections: for (const mainConnections of workflow.connectionsByDestinationNode[
|
||||
currentNode
|
||||
].main) {
|
||||
if (connectionsByDestinationNode[currentNode]?.main) {
|
||||
mainConnections: for (const mainConnections of connectionsByDestinationNode[currentNode]
|
||||
.main) {
|
||||
for (const connection of mainConnections ?? []) {
|
||||
if (
|
||||
connection.type === NodeConnectionTypes.Main &&
|
||||
|
||||
@@ -149,9 +149,8 @@ export const useNDVStore = defineStore(STORES.NDV, () => {
|
||||
|
||||
const ndvNodeInputNumber = computed(() => {
|
||||
const returnData: { [nodeName: string]: number[] } = {};
|
||||
const workflow = workflowsStore.getCurrentWorkflow();
|
||||
const activeNodeConections = (
|
||||
workflow.connectionsByDestinationNode[activeNode.value?.name || ''] ?? {}
|
||||
workflowsStore.connectionsByDestinationNode[activeNode.value?.name || ''] ?? {}
|
||||
).main;
|
||||
|
||||
if (!activeNodeConections || activeNodeConections.length < 2) return returnData;
|
||||
|
||||
@@ -66,6 +66,7 @@ import {
|
||||
Workflow,
|
||||
TelemetryHelpers,
|
||||
} from 'n8n-workflow';
|
||||
import * as workflowUtils from 'n8n-workflow/common';
|
||||
import findLast from 'lodash/findLast';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import pick from 'lodash/pick';
|
||||
@@ -294,10 +295,17 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
|
||||
const getPastChatMessages = computed(() => Array.from(new Set(chatMessages.value)));
|
||||
|
||||
/**
|
||||
* This section contains functions migrated from the workflow class
|
||||
*/
|
||||
|
||||
const connectionsBySourceNode = computed(() => workflow.value.connections);
|
||||
const connectionsByDestinationNode = computed(() =>
|
||||
Workflow.getConnectionsByDestination(workflow.value.connections),
|
||||
workflowUtils.mapConnectionsByDestination(workflow.value.connections),
|
||||
);
|
||||
|
||||
// End section
|
||||
|
||||
const selectableTriggerNodes = computed(() =>
|
||||
workflowTriggerNodes.value.filter((node) => !node.disabled && !isChatNode(node)),
|
||||
);
|
||||
@@ -384,7 +392,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
}
|
||||
|
||||
function getNodeByName(nodeName: string): INodeUi | null {
|
||||
return nodesByName.value[nodeName] || null;
|
||||
return workflowUtils.getNodeByName(nodesByName.value, nodeName);
|
||||
}
|
||||
|
||||
function getNodeById(nodeId: string): INodeUi | undefined {
|
||||
@@ -1955,6 +1963,8 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
getWorkflowResultDataByNodeName,
|
||||
allConnections,
|
||||
allNodes,
|
||||
connectionsBySourceNode,
|
||||
connectionsByDestinationNode,
|
||||
isWaitingExecution,
|
||||
isWorkflowRunning,
|
||||
canvasNames,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Basic, IExecutionResponse } from '@/Interface';
|
||||
import type { IWorkflowDataProxyAdditionalKeys, Workflow } from 'n8n-workflow';
|
||||
import type { IConnections, IWorkflowDataProxyAdditionalKeys, Workflow } from 'n8n-workflow';
|
||||
|
||||
type Range = { from: number; to: number };
|
||||
|
||||
@@ -40,6 +40,7 @@ export interface ExpressionLocalResolveContext {
|
||||
envVars: Record<string, Basic>;
|
||||
additionalKeys: IWorkflowDataProxyAdditionalKeys;
|
||||
workflow: Workflow;
|
||||
connections: IConnections;
|
||||
execution: IExecutionResponse | null;
|
||||
nodeName: string;
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,8 @@ import { SET_NODE_TYPE, STICKY_NODE_TYPE } from '@/constants';
|
||||
import { createTestNode } from '@/__tests__/mocks';
|
||||
import type { GraphNode } from '@vue-flow/core';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { setActivePinia } from 'pinia';
|
||||
|
||||
describe('getGenericHints', () => {
|
||||
let mockWorkflowNode: MockProxy<INode>;
|
||||
@@ -34,6 +36,9 @@ describe('getGenericHints', () => {
|
||||
let hasNodeRun: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
const pinia = createTestingPinia({});
|
||||
setActivePinia(pinia);
|
||||
|
||||
mockWorkflowNode = mock<INode>();
|
||||
mockNode = mock<INodeUi>({ type: 'test' });
|
||||
mockNodeType = mock<INodeTypeDescription>();
|
||||
@@ -55,8 +60,9 @@ describe('getGenericHints', () => {
|
||||
nodeType: mockNodeType,
|
||||
nodeOutputData: mockNodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow: mockWorkflow,
|
||||
hasNodeRun,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
});
|
||||
|
||||
expect(hints).toEqual([
|
||||
@@ -80,8 +86,9 @@ describe('getGenericHints', () => {
|
||||
nodeType: mockNodeType,
|
||||
nodeOutputData: mockNodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow: mockWorkflow,
|
||||
hasNodeRun,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
});
|
||||
|
||||
expect(hints).toEqual([
|
||||
@@ -118,8 +125,9 @@ describe('getGenericHints', () => {
|
||||
nodeType: mockNodeType,
|
||||
nodeOutputData: mockNodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow: mockWorkflow,
|
||||
hasNodeRun,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
});
|
||||
|
||||
expect(hints).toEqual([
|
||||
@@ -142,8 +150,9 @@ describe('getGenericHints', () => {
|
||||
nodeType: mockNodeType,
|
||||
nodeOutputData: mockNodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow: mockWorkflow,
|
||||
hasNodeRun,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
});
|
||||
|
||||
expect(hints).toEqual([
|
||||
@@ -166,8 +175,9 @@ describe('getGenericHints', () => {
|
||||
nodeType: mockNodeType,
|
||||
nodeOutputData: mockNodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow: mockWorkflow,
|
||||
hasNodeRun,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
});
|
||||
|
||||
expect(hints).toEqual([
|
||||
@@ -191,8 +201,9 @@ describe('getGenericHints', () => {
|
||||
nodeType: mockNodeType,
|
||||
nodeOutputData: mockNodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow: mockWorkflow,
|
||||
hasNodeRun,
|
||||
nodes: [],
|
||||
connections: {},
|
||||
});
|
||||
|
||||
expect(hints).toEqual([
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
import type { INodeUi, XYPosition } from '@/Interface';
|
||||
import type {
|
||||
AssignmentCollectionValue,
|
||||
IConnections,
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
INodeTypeDescription,
|
||||
NodeHint,
|
||||
Workflow,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeHelpers, SEND_AND_WAIT_OPERATION } from 'n8n-workflow';
|
||||
import type { RouteLocation } from 'vue-router';
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
type Rect,
|
||||
type ViewportTransform,
|
||||
} from '@vue-flow/core';
|
||||
import * as workflowUtils from 'n8n-workflow/common';
|
||||
|
||||
/*
|
||||
* Canvas constants and functions
|
||||
@@ -371,7 +372,8 @@ export function getGenericHints({
|
||||
nodeType,
|
||||
nodeOutputData,
|
||||
hasMultipleInputItems,
|
||||
workflow,
|
||||
nodes,
|
||||
connections,
|
||||
hasNodeRun,
|
||||
}: {
|
||||
workflowNode: INode;
|
||||
@@ -379,7 +381,8 @@ export function getGenericHints({
|
||||
nodeType: INodeTypeDescription;
|
||||
nodeOutputData: INodeExecutionData[];
|
||||
hasMultipleInputItems: boolean;
|
||||
workflow: Workflow;
|
||||
nodes: INode[];
|
||||
connections: IConnections;
|
||||
hasNodeRun: boolean;
|
||||
}) {
|
||||
const nodeHints: NodeHint[] = [];
|
||||
@@ -417,7 +420,7 @@ export function getGenericHints({
|
||||
hasMultipleInputItems &&
|
||||
LIST_LIKE_NODE_OPERATIONS.includes((workflowNode.parameters.operation as string) || '')
|
||||
) {
|
||||
const executeOnce = workflow.getNode(node.name)?.executeOnce;
|
||||
const executeOnce = workflowUtils.getNodeByName(nodes, node.name)?.executeOnce;
|
||||
if (!executeOnce) {
|
||||
nodeHints.push({
|
||||
message:
|
||||
@@ -429,7 +432,7 @@ export function getGenericHints({
|
||||
|
||||
// add sendAndWait hint
|
||||
if (hasMultipleInputItems && workflowNode.parameters.operation === SEND_AND_WAIT_OPERATION) {
|
||||
const executeOnce = workflow.getNode(node.name)?.executeOnce;
|
||||
const executeOnce = workflowUtils.getNodeByName(nodes, node.name)?.executeOnce;
|
||||
if (!executeOnce) {
|
||||
nodeHints.push({
|
||||
message: 'This action will run only once, for the first input item',
|
||||
@@ -470,9 +473,8 @@ export function getGenericHints({
|
||||
|
||||
// Split In Batches setup hints
|
||||
if (node.type === SPLIT_IN_BATCHES_NODE_TYPE) {
|
||||
const { connectionsBySourceNode } = workflow;
|
||||
|
||||
const firstNodesInLoop = connectionsBySourceNode[node.name]?.main[1] || [];
|
||||
const firstNodesInLoop =
|
||||
workflowUtils.mapConnectionsByDestination(connections)[node.name]?.main[1] || [];
|
||||
|
||||
if (!firstNodesInLoop.length) {
|
||||
nodeHints.push({
|
||||
@@ -482,7 +484,7 @@ export function getGenericHints({
|
||||
});
|
||||
} else {
|
||||
for (const nodeInConnection of firstNodesInLoop || []) {
|
||||
const nodeChilds = workflow.getChildNodes(nodeInConnection.node) || [];
|
||||
const nodeChilds = workflowUtils.getChildNodes(connections, nodeInConnection.node) || [];
|
||||
if (!nodeChilds.includes(node.name)) {
|
||||
nodeHints.push({
|
||||
message:
|
||||
|
||||
Reference in New Issue
Block a user