From f5274302f843c34f0a8a0b3eb51e7f9262fe0ea4 Mon Sep 17 00:00:00 2001 From: oleg Date: Wed, 14 Feb 2024 10:42:55 +0100 Subject: [PATCH] fix: Fix resolving of expressions of deeply nested sub-nodes (#8612) --- .../src/components/VariableSelector.vue | 5 +-- .../src/composables/useWorkflowHelpers.ts | 38 +--------------- packages/workflow/src/Workflow.ts | 44 ++++++++++++++++++- packages/workflow/src/WorkflowDataProxy.ts | 8 +++- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/packages/editor-ui/src/components/VariableSelector.vue b/packages/editor-ui/src/components/VariableSelector.vue index 9862a42b86c0a..30b2f49d9239d 100644 --- a/packages/editor-ui/src/components/VariableSelector.vue +++ b/packages/editor-ui/src/components/VariableSelector.vue @@ -81,10 +81,7 @@ export default defineComponent({ if (!activeNode) { return null; } - return this.workflowHelpers.getParentMainInputNode( - this.workflowHelpers.getCurrentWorkflow(), - activeNode, - ); + return this.workflow.getParentMainInputNode(activeNode); }, extendAll(): boolean { if (this.variableFilter) { diff --git a/packages/editor-ui/src/composables/useWorkflowHelpers.ts b/packages/editor-ui/src/composables/useWorkflowHelpers.ts index fcb226d8c25bf..4f6582ad9ab0c 100644 --- a/packages/editor-ui/src/composables/useWorkflowHelpers.ts +++ b/packages/editor-ui/src/composables/useWorkflowHelpers.ts @@ -73,41 +73,6 @@ import { useI18n } from '@/composables/useI18n'; import type { Router } from 'vue-router'; import { useTelemetry } from '@/composables/useTelemetry'; -export function getParentMainInputNode(workflow: Workflow, node: INode): INode { - const nodeType = useNodeTypesStore().getNodeType(node.type); - if (nodeType) { - const outputs = NodeHelpers.getNodeOutputs(workflow, node, nodeType); - - if (!!outputs.find((output) => output !== NodeConnectionType.Main)) { - // Get the first node which is connected to a non-main output - const nonMainNodesConnected = outputs?.reduce((acc, outputName) => { - const parentNodes = workflow.getChildNodes(node.name, outputName); - if (parentNodes.length > 0) { - acc.push(...parentNodes); - } - return acc; - }, [] as string[]); - - if (nonMainNodesConnected.length) { - const returnNode = workflow.getNode(nonMainNodesConnected[0]); - if (returnNode === null) { - // This should theoretically never happen as the node is connected - // but who knows and it makes TS happy - throw new Error( - `The node "${nonMainNodesConnected[0]}" which is a connection of "${node.name}" could not be found!`, - ); - } - - // The chain of non-main nodes is potentially not finished yet so - // keep on going - return getParentMainInputNode(workflow, returnNode); - } - } - } - - return node; -} - export function resolveParameter( parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[], opts: { @@ -127,7 +92,7 @@ export function resolveParameter( const workflow = getCurrentWorkflow(); if (activeNode) { - contextNode = getParentMainInputNode(workflow, activeNode); + contextNode = workflow.getParentMainInputNode(activeNode); } const workflowRunData = useWorkflowsStore().getWorkflowRunData; @@ -1187,7 +1152,6 @@ export function useWorkflowHelpers(router: Router) { getCurrentWorkflow, getConnectedNodes, getNodes, - getParentMainInputNode, getWorkflow, getNodeTypes, connectionInputData, diff --git a/packages/workflow/src/Workflow.ts b/packages/workflow/src/Workflow.ts index 0411db82b782e..5a05195c8d704 100644 --- a/packages/workflow/src/Workflow.ts +++ b/packages/workflow/src/Workflow.ts @@ -43,8 +43,9 @@ import type { NodeParameterValueType, ConnectionTypes, CloseFunction, + INodeOutputConfiguration, } from './Interfaces'; -import { Node } from './Interfaces'; +import { Node, NodeConnectionType } from './Interfaces'; import type { IDeferredPromise } from './DeferredPromise'; import * as NodeHelpers from './NodeHelpers'; @@ -845,6 +846,47 @@ export class Workflow { return returnConns; } + getParentMainInputNode(node: INode): INode { + if (node) { + const nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); + const outputs = NodeHelpers.getNodeOutputs(this, node, nodeType.description); + + if ( + !!outputs.find( + (output) => + ((output as INodeOutputConfiguration)?.type ?? output) !== NodeConnectionType.Main, + ) + ) { + // Get the first node which is connected to a non-main output + const nonMainNodesConnected = outputs?.reduce((acc, outputName) => { + const parentNodes = this.getChildNodes( + node.name, + (outputName as INodeOutputConfiguration)?.type ?? outputName, + ); + if (parentNodes.length > 0) { + acc.push(...parentNodes); + } + return acc; + }, [] as string[]); + + if (nonMainNodesConnected.length) { + const returnNode = this.getNode(nonMainNodesConnected[0]); + if (returnNode === null) { + // This should theoretically never happen as the node is connected + // but who knows and it makes TS happy + throw new ApplicationError(`Node "${nonMainNodesConnected[0]}" not found`); + } + + // The chain of non-main nodes is potentially not finished yet so + // keep on going + return this.getParentMainInputNode(returnNode); + } + } + } + + return node; + } + /** * Returns via which output of the parent-node and index the current node * they are connected diff --git a/packages/workflow/src/WorkflowDataProxy.ts b/packages/workflow/src/WorkflowDataProxy.ts index 4e8de2a5a6b0d..a6b19310e9fd7 100644 --- a/packages/workflow/src/WorkflowDataProxy.ts +++ b/packages/workflow/src/WorkflowDataProxy.ts @@ -993,7 +993,13 @@ export class WorkflowDataProxy { // Before resolving the pairedItem make sure that the requested node comes in the // graph before the current one - const parentNodes = that.workflow.getParentNodes(that.contextNodeName); + const activeNode = that.workflow.getNode(that.activeNodeName); + let contextNode = that.contextNodeName; + if (activeNode) { + const parentMainInputNode = that.workflow.getParentMainInputNode(activeNode); + contextNode = parentMainInputNode.name ?? contextNode; + } + const parentNodes = that.workflow.getParentNodes(contextNode); if (!parentNodes.includes(nodeName)) { throw createExpressionError('Invalid expression', { messageTemplate: 'Invalid expression under ‘%%PARAMETER%%’',