Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix resolving of expressions of deeply nested sub-nodes #8612

Merged
merged 2 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions packages/editor-ui/src/components/VariableSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
38 changes: 1 addition & 37 deletions packages/editor-ui/src/composables/useWorkflowHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -127,7 +92,7 @@ export function resolveParameter(
const workflow = getCurrentWorkflow();

if (activeNode) {
contextNode = getParentMainInputNode(workflow, activeNode);
contextNode = workflow.getParentMainInputNode(activeNode);
}

const workflowRunData = useWorkflowsStore().getWorkflowRunData;
Expand Down Expand Up @@ -1187,7 +1152,6 @@ export function useWorkflowHelpers(router: Router) {
getCurrentWorkflow,
getConnectedNodes,
getNodes,
getParentMainInputNode,
getWorkflow,
getNodeTypes,
connectionInputData,
Expand Down
44 changes: 43 additions & 1 deletion packages/workflow/src/Workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion packages/workflow/src/WorkflowDataProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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%%’',
Expand Down
Loading