diff --git a/packages/cli/src/services/dynamic-node-parameters.service.ts b/packages/cli/src/services/dynamic-node-parameters.service.ts index 98ed48e2ac..d3575f5bc9 100644 --- a/packages/cli/src/services/dynamic-node-parameters.service.ts +++ b/packages/cli/src/services/dynamic-node-parameters.service.ts @@ -300,6 +300,11 @@ export class DynamicNodeParametersService { } private getLocalLoadOptionsContext(path: string, additionalData: IWorkflowExecuteAdditionalData) { - return new LocalLoadOptionsContext(additionalData, path, this.workflowLoaderService); + return new LocalLoadOptionsContext( + this.nodeTypes, + additionalData, + path, + this.workflowLoaderService, + ); } } diff --git a/packages/core/src/node-execution-context/local-load-options-context.ts b/packages/core/src/node-execution-context/local-load-options-context.ts index 4e88fddbb5..284539c1f6 100644 --- a/packages/core/src/node-execution-context/local-load-options-context.ts +++ b/packages/core/src/node-execution-context/local-load-options-context.ts @@ -1,22 +1,27 @@ import { get } from 'lodash'; -import { ApplicationError } from 'n8n-workflow'; +import { ApplicationError, deepCopy, Workflow } from 'n8n-workflow'; import type { INodeParameterResourceLocator, IWorkflowExecuteAdditionalData, NodeParameterValueType, ILocalLoadOptionsFunctions, IWorkflowLoader, + IWorkflowNodeContext, INode, + INodeTypes, } from 'n8n-workflow'; +import { LoadWorkflowNodeContext } from './workflow-node-context'; + export class LocalLoadOptionsContext implements ILocalLoadOptionsFunctions { constructor( + private nodeTypes: INodeTypes, private additionalData: IWorkflowExecuteAdditionalData, private path: string, private workflowLoader: IWorkflowLoader, ) {} - async getExecuteWorkflowTriggerNode(): Promise { + async getWorkflowNodeContext(nodeType: string): Promise { const { value } = this.getCurrentNodeParameter('workflowId') as INodeParameterResourceLocator; const workflowId = value as string; @@ -24,9 +29,25 @@ export class LocalLoadOptionsContext implements ILocalLoadOptionsFunctions { throw new ApplicationError('No workflowId parameter defined on node!'); } - const workflow = await this.workflowLoader.get(workflowId); + const dbWorkflow = await this.workflowLoader.get(workflowId); - return workflow.nodes.find((node) => node.type === 'n8n-nodes-base.executeWorkflowTrigger'); + const workflowNode = dbWorkflow.nodes.find((node) => node.type === nodeType) as INode; + + if (workflowNode) { + const workflow = new Workflow({ + nodes: [workflowNode], + connections: {}, + active: false, + nodeTypes: this.nodeTypes, + }); + + const workflowAdditionalData = deepCopy(this.additionalData); + workflowAdditionalData.currentNodeParameters = workflowNode.parameters; + + return new LoadWorkflowNodeContext(workflow, workflowNode, workflowAdditionalData); + } + + return null; } getCurrentNodeParameter(parameterPath: string): NodeParameterValueType | object | undefined { diff --git a/packages/core/src/node-execution-context/workflow-node-context.ts b/packages/core/src/node-execution-context/workflow-node-context.ts new file mode 100644 index 0000000000..7a8c730ae6 --- /dev/null +++ b/packages/core/src/node-execution-context/workflow-node-context.ts @@ -0,0 +1,32 @@ +import type { + IGetNodeParameterOptions, + INode, + IWorkflowExecuteAdditionalData, + Workflow, + IWorkflowNodeContext, +} from 'n8n-workflow'; + +import { NodeExecutionContext } from './node-execution-context'; + +export class LoadWorkflowNodeContext extends NodeExecutionContext implements IWorkflowNodeContext { + readonly getNodeParameter: IWorkflowNodeContext['getNodeParameter']; + + constructor(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData) { + super(workflow, node, additionalData, 'internal'); + { + this.getNodeParameter = (( + parameterName: string, + itemIndex: number, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fallbackValue?: any, + options?: IGetNodeParameterOptions, + ) => + this._getNodeParameter( + parameterName, + itemIndex, + fallbackValue, + options, + )) as IWorkflowNodeContext['getNodeParameter']; + } + } +} diff --git a/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow/methods/resourceMapping.ts b/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow/methods/resourceMapping.ts index 6c9cfa99c2..4b83f891ea 100644 --- a/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow/methods/resourceMapping.ts +++ b/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow/methods/resourceMapping.ts @@ -1,39 +1,37 @@ -import type { - ILocalLoadOptionsFunctions, - INode, - ResourceMapperField, - ResourceMapperFields, +import { + EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE, + type ILocalLoadOptionsFunctions, + type ResourceMapperField, + type ResourceMapperFields, } from 'n8n-workflow'; +import { getFieldEntries } from '../../GenericFunctions'; + export async function getWorkflowInputs( this: ILocalLoadOptionsFunctions, ): Promise { - const executeWorkflowTriggerNode = (await this.getExecuteWorkflowTriggerNode()) as INode; + const nodeLoadContext = await this.getWorkflowNodeContext(EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE); + let fields: ResourceMapperField[] = []; - // const fieldValues = getFieldEntries(executeWorkflowTriggerNode); + if (nodeLoadContext) { + const fieldValues = getFieldEntries(nodeLoadContext); - const workflowInputFields = [ - { name: 'field1', type: 'string' as const }, - { name: 'field2', type: 'number' as const }, - { name: 'field3', type: 'boolean' as const }, - { name: 'field4', type: 'any' as const }, - ]; + fields = fieldValues.map((currentWorkflowInput) => { + const field: ResourceMapperField = { + id: currentWorkflowInput.name, + displayName: currentWorkflowInput.name, + required: false, + defaultMatch: true, + display: true, + canBeUsedToMatch: true, + }; - const fields: ResourceMapperField[] = workflowInputFields.map((currentWorkflowInput) => { - const field: ResourceMapperField = { - id: currentWorkflowInput.name, - displayName: currentWorkflowInput.name, - required: false, - defaultMatch: true, - display: true, - canBeUsedToMatch: true, - }; + if (currentWorkflowInput.type !== 'any') { + field.type = currentWorkflowInput.type; + } - if (currentWorkflowInput.type !== 'any') { - field.type = currentWorkflowInput.type; - } - - return field; - }); + return field; + }); + } return { fields }; } diff --git a/packages/nodes-base/nodes/ExecuteWorkflow/GenericFunctions.ts b/packages/nodes-base/nodes/ExecuteWorkflow/GenericFunctions.ts index 0f03f364fb..4ab4a6350c 100644 --- a/packages/nodes-base/nodes/ExecuteWorkflow/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ExecuteWorkflow/GenericFunctions.ts @@ -1,6 +1,6 @@ import { json as generateSchemaFromExample, type SchemaObject } from 'generate-schema'; import type { JSONSchema7 } from 'json-schema'; -import type { FieldValueOption, FieldType, IExecuteFunctions } from 'n8n-workflow'; +import type { FieldValueOption, FieldType, IWorkflowNodeContext } from 'n8n-workflow'; import { jsonParse, NodeOperationError } from 'n8n-workflow'; import { JSON_EXAMPLE, INPUT_SOURCE, WORKFLOW_INPUTS, VALUES, TYPE_OPTIONS } from './constants'; @@ -40,14 +40,14 @@ function parseJsonSchema(schema: JSONSchema7): FieldValueOption[] | string { return result; } -function parseJsonExample(context: IExecuteFunctions): JSONSchema7 { +function parseJsonExample(context: IWorkflowNodeContext): JSONSchema7 { const jsonString = context.getNodeParameter(JSON_EXAMPLE, 0, '') as string; const json = jsonParse(jsonString); return generateSchemaFromExample(json) as JSONSchema7; } -export function getFieldEntries(context: IExecuteFunctions): FieldValueOption[] { +export function getFieldEntries(context: IWorkflowNodeContext): FieldValueOption[] { const inputSource = context.getNodeParameter(INPUT_SOURCE, 0); let result: FieldValueOption[] | string = 'Internal Error: Invalid input source'; try { diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index d9719ccf40..f4b2d92407 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1067,13 +1067,17 @@ export interface ILoadOptionsFunctions extends FunctionsBase { options?: IGetNodeParameterOptions, ): NodeParameterValueType | object | undefined; getCurrentNodeParameters(): INodeParameters | undefined; + helpers: RequestHelperFunctions & SSHTunnelFunctions; } export type FieldValueOption = { name: string; type: FieldType | 'any' }; +export type IWorkflowNodeContext = ExecuteFunctions.GetNodeParameterFn & + Pick; + export interface ILocalLoadOptionsFunctions { - getExecuteWorkflowTriggerNode(): Promise; + getWorkflowNodeContext(nodeType: string): Promise; } export interface IWorkflowLoader {