diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts index c7b1cf3e13..9d94af1911 100644 --- a/packages/core/src/WorkflowExecute.ts +++ b/packages/core/src/WorkflowExecute.ts @@ -46,36 +46,36 @@ export class WorkflowExecute { * @returns {(Promise)} * @memberof WorkflowExecute */ - async run(workflow: Workflow, startNodes?: INode[], destinationNode?: string): Promise { + async run(workflow: Workflow, startNode?: INode, destinationNode?: string): Promise { // Get the nodes to start workflow execution from - startNodes = startNodes || workflow.getStartNodes(destinationNode); + startNode = startNode || workflow.getStartNode(destinationNode); + + if (startNode === undefined) { + throw new Error('No node to start the workflow from could be found!'); + } // If a destination node is given we only run the direct parent nodes and no others let runNodeFilter: string[] | undefined = undefined; if (destinationNode) { - // TODO: Combine that later with getStartNodes which does more or less the same tree iteration runNodeFilter = workflow.getParentNodes(destinationNode); runNodeFilter.push(destinationNode); } // Initialize the data of the start nodes - const nodeExecutionStack: IExecuteData[] = []; - startNodes.forEach((node) => { - nodeExecutionStack.push( - { - node, - data: { - main: [ - [ - { - json: {}, - }, - ], + const nodeExecutionStack: IExecuteData[] = [ + { + node: startNode, + data: { + main: [ + [ + { + json: {}, + }, ], - }, + ], }, - ); - }); + } + ]; const runExecutionData: IRunExecutionData = { startData: { diff --git a/packages/workflow/src/Workflow.ts b/packages/workflow/src/Workflow.ts index 8d02b97684..bd3c7ad467 100644 --- a/packages/workflow/src/Workflow.ts +++ b/packages/workflow/src/Workflow.ts @@ -707,40 +707,62 @@ export class Workflow { /** - * Return all the start nodes which can be found in the workflow. + * Returns the start node to start the worfklow from * - * @param {(string | undefined)} [destinationNode] - * @returns {INode[]} + * @param {string} [destinationNode] + * @returns {(INode | undefined)} * @memberof Workflow */ - getStartNodes(destinationNode?: string): INode[] { - const returnData: INode[] = []; + getStartNode(destinationNode?: string): INode | undefined { + const startNodeType = 'n8n-nodes-base.start'; if (destinationNode) { // Find the highest parent nodes of the given one const nodeNames = this.getHighestNode(destinationNode); + if (nodeNames.length === 0) { // If no parent nodes have been found then only the destination-node // is in the tree so add that one nodeNames.push(destinationNode); } - nodeNames.forEach((nodeName) => { - returnData.push(this.nodes[nodeName]); - }); - } else { - // No node given so find all the nodes which do not have any input - let nodeType: INodeType | undefined; - for (const nodeName of Object.keys(this.nodes)) { - nodeType = this.nodeTypes.getByName(this.nodes[nodeName].type); + // Check which node to return as start node - if (nodeType !== undefined && nodeType.description.inputs.length === 0 && this.nodes[nodeName].disabled !== true) { - returnData.push(this.nodes[nodeName]); + // Check if there are any trigger nodes and then return the first one + let node: INode; + let nodeType: INodeType; + for (const nodeName of nodeNames) { + node = this.nodes[nodeName]; + nodeType = this.nodeTypes.getByName(node.type) as INodeType; + + if (nodeType.trigger !== undefined) { + return node; + } + } + + // Check if there is the actual "start" node + for (const nodeName of nodeNames) { + node = this.nodes[nodeName]; + if (node.type === startNodeType) { + return node; + } + } + + // If none of the above did find anything simply return the + // first parent node in the list + return this.nodes[nodeNames[0]]; + } else { + // No node given so start from "start" node + let node: INode; + for (const nodeName of Object.keys(this.nodes)) { + node = this.nodes[nodeName]; + if (node.type === startNodeType) { + return node; } } } - return returnData; + return undefined; }