feat(core): Change node execution order (most top-left one first) (#6246)

* feat(core): Change node execution order (most top-left one first)

*  Fix issue with multi-output-nodes

*  Remove not needed meta-entry in test

* fix the e2e test

---------

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Jan Oberhauser 2023-06-19 19:32:11 +02:00 committed by कारतोफ्फेलस्क्रिप्ट™
parent 0fe415add2
commit 0287d5becd
7 changed files with 607 additions and 59 deletions

View file

@ -285,7 +285,11 @@ describe('NDV', () => {
.should('equal', 'hovering-item');
ndv.actions.close();
workflowPage.actions.openNode('Set5');
ndv.actions.switchInputBranch('True Branch');
ndv.actions.changeOutputRunSelector('1 of 2 (2 items)')
ndv.getters.outputTableRow(1)
.should('have.text', '8888')
.realHover();
@ -296,16 +300,18 @@ describe('NDV', () => {
.realHover();
ndv.getters.outputHoveringItem().should('not.exist');
ndv.actions.switchIntputBranch('False Branch');
ndv.actions.switchInputBranch('False Branch');
ndv.getters.inputTableRow(1)
.should('have.text', '8888')
.realHover();
ndv.getters.outputHoveringItem().should('have.text', '8888');
ndv.actions.changeOutputRunSelector('1 of 2 (4 items)')
ndv.actions.changeOutputRunSelector('2 of 2 (4 items)')
ndv.getters.outputTableRow(1)
.should('have.text', '1111')
.realHover();
ndv.actions.changeOutputRunSelector('1 of 2 (2 items)')
ndv.getters.outputHoveringItem().should('have.text', '8888');
// todo there's a bug here need to fix ADO-534
// ndv.getters.outputHoveringItem().should('not.exist');
});

View file

@ -154,7 +154,7 @@ export class NDV extends BasePage {
switchOutputBranch: (name: string) => {
this.getters.outputBranches().get('span').contains(name).click();
},
switchIntputBranch: (name: string) => {
switchInputBranch: (name: string) => {
this.getters.inputBranches().get('span').contains(name).click();
},
setRLCValue: (paramName: string, value: string) => {

View file

@ -72,7 +72,7 @@
"@types/convict": "^6.1.1",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.6",
"@types/json-diff": "^0.5.1",
"@types/json-diff": "^1.0.0",
"@types/jsonwebtoken": "^9.0.1",
"@types/localtunnel": "^1.9.0",
"@types/lodash": "^4.14.195",
@ -137,7 +137,7 @@
"handlebars": "4.7.7",
"inquirer": "^7.0.1",
"ioredis": "^5.2.4",
"json-diff": "^0.5.4",
"json-diff": "^1.0.6",
"jsonschema": "^1.4.1",
"jsonwebtoken": "^9.0.0",
"jwks-rsa": "^3.0.1",

View file

@ -46,10 +46,3 @@ interface INodeSpecialCase {
capResults?: number;
keepOnlyProperties?: string[];
}
declare module 'json-diff' {
interface IDiffOptions {
keysOnly?: boolean;
}
export function diff(obj1: unknown, obj2: unknown, diffOptions: IDiffOptions): string;
}

View file

@ -451,7 +451,7 @@ export class WorkflowExecute {
];
}
this.runExecutionData.executionData!.nodeExecutionStack.push(executionStackItem);
this.runExecutionData.executionData!.nodeExecutionStack.unshift(executionStackItem);
// Remove the data from waiting
delete this.runExecutionData.executionData!.waitingExecution[connectionData.node][runIndex];
@ -609,7 +609,7 @@ export class WorkflowExecute {
if (addEmptyItem) {
// Add only node if it does not have any inputs because else it will
// be added by its input node later anyway.
this.runExecutionData.executionData!.nodeExecutionStack.push({
this.runExecutionData.executionData!.nodeExecutionStack.unshift({
node: workflow.getNode(nodeToAdd) as INode,
data: {
main: [
@ -661,7 +661,7 @@ export class WorkflowExecute {
};
} else {
// All data is there so add it directly to stack
this.runExecutionData.executionData!.nodeExecutionStack.push({
this.runExecutionData.executionData!.nodeExecutionStack.unshift({
node: workflow.nodes[connectionData.node],
data: {
main: connectionDataArray,
@ -1180,6 +1180,12 @@ export class WorkflowExecute {
let connectionData: IConnection;
// Iterate over all the outputs
const nodesToAdd: Array<{
position: [number, number];
connection: IConnection;
outputIndex: number;
}> = [];
// Add the nodes to be executed
// eslint-disable-next-line @typescript-eslint/no-for-in-array
for (outputIndex in workflow.connectionsBySourceNode[executionNode.name].main) {
@ -1206,17 +1212,42 @@ export class WorkflowExecute {
(nodeSuccessData![outputIndex].length !== 0 || connectionData.index > 0)
) {
// Add the node only if it did execute or if connected to second "optional" input
this.addNodeToBeExecuted(
workflow,
connectionData,
parseInt(outputIndex, 10),
executionNode.name,
nodeSuccessData!,
runIndex,
);
const nodeToAdd = workflow.getNode(connectionData.node);
nodesToAdd.push({
position: nodeToAdd?.position || [0, 0],
connection: connectionData,
outputIndex: parseInt(outputIndex, 10),
});
}
}
}
// Always execute the node that is more to the top-left first
nodesToAdd.sort((a, b) => {
if (a.position[1] < b.position[1]) {
return 1;
}
if (a.position[1] > b.position[1]) {
return -1;
}
if (a.position[0] > b.position[0]) {
return -1;
}
return 0;
});
for (const nodeData of nodesToAdd) {
this.addNodeToBeExecuted(
workflow,
nodeData.connection,
nodeData.outputIndex,
executionNode.name,
nodeSuccessData!,
runIndex,
);
}
}
}

View file

@ -899,12 +899,12 @@ export const predefinedWorkflowExecuteTests: WorkflowTestData[] = [
Set2: [
[
{
value1: 1,
value2: 2,
},
],
[
{
value1: 1,
value2: 2,
},
],
@ -1159,10 +1159,10 @@ export const predefinedWorkflowExecuteTests: WorkflowTestData[] = [
nodeExecutionOrder: [
'Start',
'Set1',
'Set2',
'Set3',
'Merge1',
'Set4',
'Set2',
'Merge1',
'Merge2',
'Merge3',
'Merge4',
@ -1920,7 +1920,6 @@ export const predefinedWorkflowExecuteTests: WorkflowTestData[] = [
},
},
},
{
description:
'should display the correct parameters and so correct data when simplified node-versioning is used',
@ -2064,4 +2063,530 @@ export const predefinedWorkflowExecuteTests: WorkflowTestData[] = [
},
},
},
{
description: 'should execute nodes in the correct order, the most top-left one first',
input: {
workflowData: {
nodes: [
{
parameters: {},
id: '3e4ab8bb-2e22-45d9-9287-0265f2ee9c4b',
name: 'Start',
type: 'n8n-nodes-base.start',
typeVersion: 1,
position: [300, 620],
},
{
parameters: {
options: {},
},
id: '444650ce-464a-4630-9e24-109056105167',
name: 'Wait',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [740, 420],
webhookId: '1f4118f8-591a-48fe-a68d-6fec3c99b7a8',
},
{
parameters: {
values: {
number: [
{
name: 'wait',
},
],
},
options: {},
},
id: '7a74a097-6563-4f1e-a327-97e5a43b8acb',
name: 'Set',
type: 'n8n-nodes-base.set',
typeVersion: 2,
position: [480, 620],
},
{
parameters: {
options: {},
},
id: '9039eebf-6c11-4ce0-b8ad-0812774019d4',
name: 'Wait1',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [740, 800],
webhookId: '35ceb27a-3fb1-47a9-8678-2df16dcecbcb',
},
{
parameters: {
options: {},
},
id: '7f130b16-8fac-4d93-a0ef-56dfe575f952',
name: 'Wait2',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [940, 420],
webhookId: 'cc8e2fd2-afc8-4a17-afda-fda943f4bd83',
},
{
parameters: {
options: {},
},
id: '063e2097-b27a-4775-923c-5b839c434640',
name: 'Wait3',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1300, 420],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: 'ec908b56-8829-4566-a0b7-ced4bd16c550',
name: 'Wait4',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [940, 800],
webhookId: 'cc8e2fd2-afc8-4a17-afda-fda943f4bd83',
},
{
parameters: {
options: {},
},
id: 'a7d279bd-7241-4744-8ef6-41468131dfa7',
name: 'Wait5',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1140, 800],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: 'f620aff1-7d9c-453f-a2c1-6e3b9a1664d3',
name: 'Wait6',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [760, 200],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: '1d9bac9b-8197-4ad9-9189-f947068f1a46',
name: 'Wait7',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1060, 200],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: '9ad0cc8c-4922-440e-913c-39c8570ddcbc',
name: 'Wait8',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [740, 600],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: 'af0ca700-b6ed-40c1-8c62-bbadb6fd81f7',
name: 'Wait9',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1040, 580],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: 'f2553f9f-670f-4b54-8b89-84dd5a27a244',
name: 'Wait10',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1660, 340],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: '0f4475cb-87db-4ed7-a7a0-8a67043c320b',
name: 'Wait11',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1660, 540],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: '815f7b2a-1789-48a3-be61-931e643e6d89',
name: 'Wait12',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1920, 340],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: 'be1e11af-b8e4-40cb-af36-03613e384b5e',
name: 'Wait13',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1240, 580],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {},
id: 'cf72f99c-612f-4b76-bc8e-d77612e4faa9',
name: 'Merge',
type: 'n8n-nodes-base.merge',
typeVersion: 2.1,
position: [1300, 220],
},
{
parameters: {
options: {},
},
id: 'bfe1dfca-a060-4c37-94d0-058739e7cfca',
name: 'Wait14',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [1520, 220],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
conditions: {
number: [
{
value1: '={{ $itemIndex }}',
operation: 'equal',
value2: 1,
},
],
},
},
id: 'bf7d7e54-db5f-4f20-bf3e-b07224096872',
name: 'IF',
type: 'n8n-nodes-base.if',
typeVersion: 1,
position: [1780, -220],
},
{
parameters: {
options: {},
},
id: 'd340f2ad-3a6a-4412-bd15-9a7dde1fcb8c',
name: 'Wait15',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [2020, -300],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: '913a3c9c-1704-433d-9790-21ad0922e5e1',
name: 'Wait16',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [2020, -140],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
conditions: {
number: [
{
value1: '={{ $itemIndex }}',
operation: 'equal',
value2: 1,
},
],
},
},
id: 'df1fba53-92af-4351-b471-114dda12bef9',
name: 'IF1',
type: 'n8n-nodes-base.if',
typeVersion: 1,
position: [1780, 120],
},
{
parameters: {
options: {},
},
id: '8b3c7e63-8cd8-469d-b6d4-bf5c1953af11',
name: 'Wait17',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [2020, 200],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
{
parameters: {
options: {},
},
id: 'e74c4b7c-fc76-4e48-9a0e-3195b19ce1a0',
name: 'Wait18',
type: 'n8n-nodes-base.set',
typeVersion: 1,
position: [2020, 40],
webhookId: '35400ecf-3e53-4b2d-9fd7-2663bbfd830f',
},
],
connections: {
Start: {
main: [
[
{
node: 'Set',
type: 'main',
index: 0,
},
],
],
},
Wait: {
main: [
[
{
node: 'Wait2',
type: 'main',
index: 0,
},
],
],
},
Set: {
main: [
[
{
node: 'Wait',
type: 'main',
index: 0,
},
{
node: 'Wait1',
type: 'main',
index: 0,
},
{
node: 'Wait6',
type: 'main',
index: 0,
},
{
node: 'Wait7',
type: 'main',
index: 0,
},
{
node: 'Wait8',
type: 'main',
index: 0,
},
{
node: 'Wait9',
type: 'main',
index: 0,
},
],
],
},
Wait1: {
main: [
[
{
node: 'Wait4',
type: 'main',
index: 0,
},
],
],
},
Wait2: {
main: [
[
{
node: 'Wait3',
type: 'main',
index: 0,
},
{
node: 'Merge',
type: 'main',
index: 1,
},
],
],
},
Wait3: {
main: [
[
{
node: 'Wait10',
type: 'main',
index: 0,
},
{
node: 'Wait11',
type: 'main',
index: 0,
},
],
],
},
Wait4: {
main: [
[
{
node: 'Wait5',
type: 'main',
index: 0,
},
],
],
},
Wait7: {
main: [
[
{
node: 'Merge',
type: 'main',
index: 0,
},
],
],
},
Wait9: {
main: [
[
{
node: 'Wait13',
type: 'main',
index: 0,
},
],
],
},
Wait10: {
main: [
[
{
node: 'Wait12',
type: 'main',
index: 0,
},
],
],
},
Merge: {
main: [
[
{
node: 'Wait14',
type: 'main',
index: 0,
},
],
],
},
Wait14: {
main: [
[
{
node: 'IF',
type: 'main',
index: 0,
},
{
node: 'IF1',
type: 'main',
index: 0,
},
],
],
},
IF: {
main: [
[
{
node: 'Wait15',
type: 'main',
index: 0,
},
],
[
{
node: 'Wait16',
type: 'main',
index: 0,
},
],
],
},
IF1: {
main: [
[
{
node: 'Wait17',
type: 'main',
index: 0,
},
],
[
{
node: 'Wait18',
type: 'main',
index: 0,
},
],
],
},
},
},
},
output: {
nodeExecutionOrder: [
'Start',
'Set',
'Wait6',
'Wait7',
'Wait',
'Wait2',
'Merge',
'Wait14',
'IF',
'Wait15',
'Wait16',
'IF1',
'Wait18',
'Wait17',
'Wait3',
'Wait10',
'Wait12',
'Wait11',
'Wait9',
'Wait13',
'Wait8',
'Wait1',
'Wait4',
'Wait5',
],
nodeData: {},
},
},
];

View file

@ -315,8 +315,8 @@ importers:
specifier: ^5.2.4
version: 5.2.4
json-diff:
specifier: ^0.5.4
version: 0.5.5
specifier: ^1.0.6
version: 1.0.6
jsonschema:
specifier: ^1.4.1
version: 1.4.1
@ -493,8 +493,8 @@ importers:
specifier: ^4.17.6
version: 4.17.14
'@types/json-diff':
specifier: ^0.5.1
version: 0.5.2
specifier: ^1.0.0
version: 1.0.0
'@types/jsonwebtoken':
specifier: ^9.0.1
version: 9.0.1
@ -4618,6 +4618,12 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@ewoudenberg/difflib@0.1.0:
resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==}
dependencies:
heap: 0.2.7
dev: false
/@faker-js/faker@7.6.0:
resolution: {integrity: sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==}
engines: {node: '>=14.0.0', npm: '>=6.0.0'}
@ -7270,8 +7276,8 @@ packages:
parse5: 7.1.1
dev: true
/@types/json-diff@0.5.2:
resolution: {integrity: sha512-2oqXStJYYLDHCciNAClY277Ti3kXT+JLvPD7lLm/490i+B7g0GR6M4qiW+bd2V5vpB+yMKY8IelbsHMAYX1D0A==}
/@types/json-diff@1.0.0:
resolution: {integrity: sha512-dCXC1F73Sqriz2d8Wt/sP/DztE+rlfIRPxW9WSYheHp/l3gvkeSvM6l4vhm7t4Dgn8AJAxNKajx/eobbPdP6Wg==}
dev: true
/@types/json-schema@7.0.11:
@ -10059,13 +10065,6 @@ packages:
engines: {node: '>=6'}
dev: true
/cli-color@0.1.7:
resolution: {integrity: sha512-xNaQxWYgI6DD4xIJLn8GY2zDZVbrN0vsU1fEbDNAHZRyceWhpj7A08mYcG1AY92q1Aw0geYkVfiAcEYIZtuTSg==}
engines: {node: '>=0.1.103'}
dependencies:
es5-ext: 0.8.2
dev: false
/cli-cursor@3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
@ -10330,6 +10329,11 @@ packages:
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
dev: true
/colors@1.4.0:
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
engines: {node: '>=0.1.90'}
dev: false
/colorspace@1.1.4:
resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
dependencies:
@ -11378,12 +11382,6 @@ packages:
engines: {node: '>=0.3.1'}
dev: true
/difflib@0.2.4:
resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==}
dependencies:
heap: 0.2.7
dev: false
/digest-header@0.0.1:
resolution: {integrity: sha512-Qi0KOZgRnkQJuvMWbs1ZRRajEnbsMU8xlJI4rHIbPC+skHQ30heO5cIHpUFT4jAvAe+zPtdavLSAxASqoyZ3cg==}
engines: {node: '>= 0.10.0'}
@ -11507,8 +11505,8 @@ packages:
engines: {node: '>=10'}
dev: false
/dreamopt@0.6.0:
resolution: {integrity: sha512-KRJa47iBEK0y6ZtgCgy2ykuvMT8c9gj3ua9Dv7vCkclFJJeH2FjhGY2xO5qBoWGahsjCGMlk4Cq9wJYeWxuYhQ==}
/dreamopt@0.8.0:
resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==}
engines: {node: '>=0.4.0'}
dependencies:
wordwrap: 1.0.0
@ -11798,11 +11796,6 @@ packages:
next-tick: 1.1.0
dev: true
/es5-ext@0.8.2:
resolution: {integrity: sha512-H19ompyhnKiBdjHR1DPHvf5RHgHPmJaY9JNzFGbMbPgdsUkvnUCN1Ke8J4Y0IMyTwFM2M9l4h2GoHwzwpSmXbA==}
engines: {node: '>=0.4'}
dev: false
/es6-iterator@2.0.3:
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
dependencies:
@ -15577,13 +15570,13 @@ packages:
bignumber.js: 9.1.1
dev: false
/json-diff@0.5.5:
resolution: {integrity: sha512-B2RSfPv8Y5iqm6/9aKC3cOhXPzjYupKDpGuqT5py9NRulL8J0UoB/zKXUo70xBsuxPcIFgtsGgEdXLrNp0GL7w==}
/json-diff@1.0.6:
resolution: {integrity: sha512-tcFIPRdlc35YkYdGxcamJjllUhXWv4n2rK9oJ2RsAzV4FBkuV4ojKEDgcZ+kpKxDmJKv+PFK65+1tVVOnSeEqA==}
hasBin: true
dependencies:
cli-color: 0.1.7
difflib: 0.2.4
dreamopt: 0.6.0
'@ewoudenberg/difflib': 0.1.0
colors: 1.4.0
dreamopt: 0.8.0
dev: false
/json-parse-better-errors@1.0.2: