mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 21:07:28 -08:00
feat(Execute Workflow Trigger Node): Add MVP for explicit input parameters (#11874)
This commit is contained in:
parent
ae08d70ac0
commit
7012d9bb9c
|
@ -1,17 +1,22 @@
|
|||
import {
|
||||
type INodeExecutionData,
|
||||
NodeConnectionType,
|
||||
NodeOperationError,
|
||||
type IExecuteFunctions,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const WORKFLOW_INPUTS = 'workflowInputs';
|
||||
const VALUES = 'values';
|
||||
|
||||
export class ExecuteWorkflowTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Execute Workflow Trigger',
|
||||
name: 'executeWorkflowTrigger',
|
||||
icon: 'fa:sign-out-alt',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
version: [1, 1.1],
|
||||
description:
|
||||
'Helpers for calling other n8n workflows. Used for designing modular, microservice-like workflows.',
|
||||
eventTriggerDescription: '',
|
||||
|
@ -46,10 +51,131 @@ export class ExecuteWorkflowTrigger implements INodeType {
|
|||
],
|
||||
default: 'worklfow_call',
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow Inputs',
|
||||
name: WORKFLOW_INPUTS,
|
||||
placeholder: 'Add Field',
|
||||
type: 'fixedCollection',
|
||||
description:
|
||||
'Define expected input fields. If no inputs are provided, all data from the calling workflow will be passed through.',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
sortable: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: { '@version': [{ _cnd: { gte: 1.1 } }] },
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
name: VALUES,
|
||||
displayName: 'Values',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. fieldName',
|
||||
description: 'Name of the field',
|
||||
},
|
||||
// {
|
||||
// displayName: 'Type',
|
||||
// name: 'type',
|
||||
// type: 'options',
|
||||
// description: 'The field value type',
|
||||
// // eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
|
||||
// options: [
|
||||
// {
|
||||
// name: 'String',
|
||||
// value: 'stringValue',
|
||||
// },
|
||||
// {
|
||||
// name: 'Number',
|
||||
// value: 'numberValue',
|
||||
// },
|
||||
// {
|
||||
// name: 'Boolean',
|
||||
// value: 'booleanValue',
|
||||
// },
|
||||
// {
|
||||
// name: 'Array',
|
||||
// value: 'arrayValue',
|
||||
// },
|
||||
// {
|
||||
// name: 'Object',
|
||||
// value: 'objectValue',
|
||||
// },
|
||||
// ],
|
||||
// default: 'stringValue',
|
||||
// },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions) {
|
||||
return [this.getInputData()];
|
||||
const inputData = this.getInputData();
|
||||
|
||||
if (this.getNode().typeVersion < 1.1) {
|
||||
return [inputData];
|
||||
} else {
|
||||
// Need to mask type due to bad `getNodeParameter` typing
|
||||
const marker = Symbol() as unknown as object;
|
||||
const hasFields =
|
||||
inputData.length >= 0 &&
|
||||
inputData.some(
|
||||
(_x, i) => this.getNodeParameter(`${WORKFLOW_INPUTS}.${VALUES}`, i, marker) !== marker,
|
||||
);
|
||||
|
||||
if (!hasFields) {
|
||||
return [inputData];
|
||||
}
|
||||
|
||||
const items: INodeExecutionData[] = [];
|
||||
|
||||
for (const [itemIndex, item] of inputData.entries()) {
|
||||
// Fields listed here will explicitly overwrite original fields
|
||||
const newItem: INodeExecutionData = {
|
||||
json: {},
|
||||
// TODO: Ensure we handle sub-execution jumps correctly.
|
||||
// metadata: {
|
||||
// subExecution: {
|
||||
// executionId: 'uhh',
|
||||
// workflowId: 'maybe?',
|
||||
// },
|
||||
// },
|
||||
pairedItem: { item: itemIndex },
|
||||
};
|
||||
try {
|
||||
const newParams = this.getNodeParameter(
|
||||
`${WORKFLOW_INPUTS}.${VALUES}`,
|
||||
itemIndex,
|
||||
[],
|
||||
) as Array<{
|
||||
name: string;
|
||||
}>;
|
||||
for (const { name } of newParams) {
|
||||
/** TODO type check goes here */
|
||||
newItem.json[name] = name in item.json ? item.json[name] : /* TODO default */ null;
|
||||
}
|
||||
|
||||
// TODO Do we want to copy non-json data (e.g. binary) as well?
|
||||
items.push(Object.assign({}, item, newItem));
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
/** todo error case? */
|
||||
} else {
|
||||
throw new NodeOperationError(this.getNode(), error, {
|
||||
itemIndex,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [items];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { mock } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
||||
import type { IExecuteFunctions, INode, INodeExecutionData } from 'n8n-workflow';
|
||||
|
||||
import { ExecuteWorkflowTrigger } from '../ExecuteWorkflowTrigger.node';
|
||||
|
||||
|
@ -9,8 +9,10 @@ describe('ExecuteWorkflowTrigger', () => {
|
|||
{ json: { item: 0, foo: 'bar' } },
|
||||
{ json: { item: 1, foo: 'quz' } },
|
||||
];
|
||||
const mockNode = { typeVersion: 1 } as INode;
|
||||
const executeFns = mock<IExecuteFunctions>({
|
||||
getInputData: () => mockInputData,
|
||||
getNode: () => mockNode,
|
||||
});
|
||||
const result = await new ExecuteWorkflowTrigger().execute.call(executeFns);
|
||||
|
||||
|
|
Loading…
Reference in a new issue