From 00f00f9cbe88f34a418c15561920c9e5d185629f Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 27 Jun 2019 16:46:26 +0200 Subject: [PATCH] :bug: Fix issue that expressions always read from output with index 0 even when the nodes with the expression were connected to a different one --- .../src/components/VariableSelector.vue | 19 ++++- packages/workflow/src/Workflow.ts | 72 +++++++++++++++++-- packages/workflow/src/WorkflowDataProxy.ts | 17 ++++- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/packages/editor-ui/src/components/VariableSelector.vue b/packages/editor-ui/src/components/VariableSelector.vue index 0c94f22bb0..9ced2f33bb 100644 --- a/packages/editor-ui/src/components/VariableSelector.vue +++ b/packages/editor-ui/src/components/VariableSelector.vue @@ -15,9 +15,9 @@ import Vue from 'vue'; import { + GenericValue, IContextObject, IDataObject, - GenericValue, IRun, IRunData, IRunExecutionData, @@ -28,6 +28,7 @@ import { import VariableSelectorItem from '@/components/VariableSelectorItem.vue'; import { IExecutionResponse, + INodeUi, IVariableItemSelected, IVariableSelectorOption, } from '@/Interface'; @@ -417,7 +418,12 @@ export default mixins( getFilterResults (filterText: string, itemIndex: number): IVariableSelectorOption[] { const inputName = 'main'; - const activeNode = this.$store.getters.activeNode; + const activeNode: INodeUi | null = this.$store.getters.activeNode; + + if (activeNode === null) { + return []; + } + const executionData = this.$store.getters.getWorkflowExecution as IExecutionResponse | null; let parentNode = this.workflow.getParentNodes(activeNode.name, inputName, 1); let runData = this.$store.getters.getWorkflowRunData as IRunData | null; @@ -453,7 +459,14 @@ export default mixins( if (parentNode.length) { // If the node has an input node add the input data - tempOutputData = this.getNodeOutputData(runData, parentNode[0], filterText, itemIndex) as IVariableSelectorOption[]; + + // Check from which output to read the data. + // Depends on how the nodes are connected. + // (example "IF" node. If node is connected to "true" or to "false" output) + const outputIndex = this.workflow.getNodeConnectionOutputIndex(activeNode.name, parentNode[0], 'main'); + + tempOutputData = this.getNodeOutputData(runData, parentNode[0], filterText, itemIndex, 0, 'main', outputIndex) as IVariableSelectorOption[]; + if (tempOutputData) { currentNodeData.push( { diff --git a/packages/workflow/src/Workflow.ts b/packages/workflow/src/Workflow.ts index 8dce218432..d3a89c7352 100644 --- a/packages/workflow/src/Workflow.ts +++ b/packages/workflow/src/Workflow.ts @@ -456,9 +456,7 @@ export class Workflow { return currentHighest; } - if (checkedNodes === undefined) { - checkedNodes = []; - } + checkedNodes = checkedNodes || []; if (checkedNodes!.includes(nodeName)) { // Node got checked already before @@ -537,9 +535,7 @@ export class Workflow { return []; } - if (checkedNodes === undefined) { - checkedNodes = []; - } + checkedNodes = checkedNodes || []; if (checkedNodes!.includes(nodeName)) { // Node got checked already before @@ -587,6 +583,70 @@ export class Workflow { + /** + * Returns via which output of the parent-node the node + * is connected to. + * + * @param {string} nodeName The node to check how it is connected with parent node + * @param {string} parentNodeName The parent node to get the output index of + * @param {string} [type='main'] + * @param {*} [depth=-1] + * @param {string[]} [checkedNodes] + * @returns {(number | undefined)} + * @memberof Workflow + */ + getNodeConnectionOutputIndex(nodeName: string, parentNodeName: string, type = 'main', depth = -1, checkedNodes?: string[]): number | undefined { + depth = depth === -1 ? -1 : depth; + const newDepth = depth === -1 ? depth : depth - 1; + if (depth === 0) { + // Reached max depth + return undefined; + } + + if (!this.connectionsByDestinationNode.hasOwnProperty(nodeName)) { + // Node does not have incoming connections + return undefined; + } + + if (!this.connectionsByDestinationNode[nodeName].hasOwnProperty(type)) { + // Node does not have incoming connections of given type + return undefined; + } + + checkedNodes = checkedNodes || []; + + if (checkedNodes!.includes(nodeName)) { + // Node got checked already before + return undefined; + } + + checkedNodes!.push(nodeName); + + let outputIndex: number | undefined; + for (const connectionsByIndex of this.connectionsByDestinationNode[nodeName][type]) { + for (const connection of connectionsByIndex) { + if (parentNodeName === connection.node) { + return connection.index; + } + + if (checkedNodes!.includes(connection.node)) { + // Node got checked already before + return; + } + + outputIndex = this.getNodeConnectionOutputIndex(connection.node, parentNodeName, type, newDepth, checkedNodes); + + if (outputIndex !== undefined) { + return outputIndex; + } + } + } + + return undefined; + } + + + /** * Resolves parameter value of parameter in webhook description * diff --git a/packages/workflow/src/WorkflowDataProxy.ts b/packages/workflow/src/WorkflowDataProxy.ts index a2e8b564b6..390fb1d549 100644 --- a/packages/workflow/src/WorkflowDataProxy.ts +++ b/packages/workflow/src/WorkflowDataProxy.ts @@ -150,9 +150,20 @@ export class WorkflowDataProxy { throw new Error(`No data found from "main" input.`); } - // Currently it is only possible to reference data from the first input - // so we hardcode it. - executionData = taskData.main[0] as INodeExecutionData[]; + // Check from which output to read the data. + // Depends on how the nodes are connected. + // (example "IF" node. If node is connected to "true" or to "false" output) + const outputIndex = that.workflow.getNodeConnectionOutputIndex(that.activeNodeName, nodeName, 'main'); + + if (outputIndex === undefined) { + throw new Error(`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`); + } + + if (taskData.main.length < outputIndex) { + throw new Error(`No data found from "main" input with index "${outputIndex}" via which node is connected with.`); + } + + executionData = taskData.main[outputIndex] as INodeExecutionData[]; } else { // Short syntax got used to return data from active node