mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 13:27:31 -08:00
fix: Fix resolving of expressions of deeply nested sub-nodes (#8612)
This commit is contained in:
parent
d18cba37a4
commit
f5274302f8
|
@ -81,10 +81,7 @@ export default defineComponent({
|
||||||
if (!activeNode) {
|
if (!activeNode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.workflowHelpers.getParentMainInputNode(
|
return this.workflow.getParentMainInputNode(activeNode);
|
||||||
this.workflowHelpers.getCurrentWorkflow(),
|
|
||||||
activeNode,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
extendAll(): boolean {
|
extendAll(): boolean {
|
||||||
if (this.variableFilter) {
|
if (this.variableFilter) {
|
||||||
|
|
|
@ -73,41 +73,6 @@ import { useI18n } from '@/composables/useI18n';
|
||||||
import type { Router } from 'vue-router';
|
import type { Router } from 'vue-router';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
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(
|
export function resolveParameter(
|
||||||
parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||||
opts: {
|
opts: {
|
||||||
|
@ -127,7 +92,7 @@ export function resolveParameter(
|
||||||
const workflow = getCurrentWorkflow();
|
const workflow = getCurrentWorkflow();
|
||||||
|
|
||||||
if (activeNode) {
|
if (activeNode) {
|
||||||
contextNode = getParentMainInputNode(workflow, activeNode);
|
contextNode = workflow.getParentMainInputNode(activeNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflowRunData = useWorkflowsStore().getWorkflowRunData;
|
const workflowRunData = useWorkflowsStore().getWorkflowRunData;
|
||||||
|
@ -1187,7 +1152,6 @@ export function useWorkflowHelpers(router: Router) {
|
||||||
getCurrentWorkflow,
|
getCurrentWorkflow,
|
||||||
getConnectedNodes,
|
getConnectedNodes,
|
||||||
getNodes,
|
getNodes,
|
||||||
getParentMainInputNode,
|
|
||||||
getWorkflow,
|
getWorkflow,
|
||||||
getNodeTypes,
|
getNodeTypes,
|
||||||
connectionInputData,
|
connectionInputData,
|
||||||
|
|
|
@ -43,8 +43,9 @@ import type {
|
||||||
NodeParameterValueType,
|
NodeParameterValueType,
|
||||||
ConnectionTypes,
|
ConnectionTypes,
|
||||||
CloseFunction,
|
CloseFunction,
|
||||||
|
INodeOutputConfiguration,
|
||||||
} from './Interfaces';
|
} from './Interfaces';
|
||||||
import { Node } from './Interfaces';
|
import { Node, NodeConnectionType } from './Interfaces';
|
||||||
import type { IDeferredPromise } from './DeferredPromise';
|
import type { IDeferredPromise } from './DeferredPromise';
|
||||||
|
|
||||||
import * as NodeHelpers from './NodeHelpers';
|
import * as NodeHelpers from './NodeHelpers';
|
||||||
|
@ -845,6 +846,47 @@ export class Workflow {
|
||||||
return returnConns;
|
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
|
* Returns via which output of the parent-node and index the current node
|
||||||
* they are connected
|
* they are connected
|
||||||
|
|
|
@ -993,7 +993,13 @@ export class WorkflowDataProxy {
|
||||||
|
|
||||||
// Before resolving the pairedItem make sure that the requested node comes in the
|
// Before resolving the pairedItem make sure that the requested node comes in the
|
||||||
// graph before the current one
|
// 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)) {
|
if (!parentNodes.includes(nodeName)) {
|
||||||
throw createExpressionError('Invalid expression', {
|
throw createExpressionError('Invalid expression', {
|
||||||
messageTemplate: 'Invalid expression under ‘%%PARAMETER%%’',
|
messageTemplate: 'Invalid expression under ‘%%PARAMETER%%’',
|
||||||
|
|
Loading…
Reference in a new issue