Merge branch 'feature-sub-workflow-inputs' of github.com:n8n-io/n8n into ado-2898-execute-workflow-node-add-workflow-inputs-parameter

This commit is contained in:
Ivan Atanasov 2024-12-02 18:08:55 +01:00
commit 8c38bf2d0a
No known key found for this signature in database

View file

@ -17,7 +17,6 @@ const WORKFLOW_INPUTS = 'workflowInputs';
const INPUT_OPTIONS = 'inputOptions';
const VALUES = 'values';
const JSON_EXAMPLE = 'jsonExample';
const JSON_SCHEMA = 'jsonSchema';
const TYPE_OPTIONS: Array<{ name: string; value: FieldType | 'any' }> = [
{
name: 'Allow Any Type',
@ -100,9 +99,6 @@ function getFieldEntries(context: IExecuteFunctions): ValueOptions[] {
name: string;
type: FieldType;
}>;
} else if (inputSource === JSON_SCHEMA) {
const schema = context.getNodeParameter(JSON_SCHEMA, 0, '{}') as string;
result = parseJsonSchema(jsonParse<JSONSchema7>(schema));
} else if (inputSource === JSON_EXAMPLE) {
const schema = parseJsonExample(context);
result = parseJsonSchema(schema);
@ -120,14 +116,6 @@ function getFieldEntries(context: IExecuteFunctions): ValueOptions[] {
throw new NodeOperationError(context.getNode(), result);
}
// This intentionally doesn't catch any potential errors, e.g. an invalid json example
// This way they correctly end up exposed to the user.
// Otherwise we'd have to return true on error here as we short-circuit on false
function hasFields(context: IExecuteFunctions): boolean {
const entries = getFieldEntries(context);
return entries.length > 0;
}
export class ExecuteWorkflowTrigger implements INodeType {
description: INodeTypeDescription = {
displayName: 'Execute Workflow Trigger',
@ -148,37 +136,18 @@ export class ExecuteWorkflowTrigger implements INodeType {
hints: [
{
message:
'We strongly recommend defining your input fields explicitly.<br>If no inputs are provided, all data from the calling workflow will be available, and issues will be more difficult to debug later on.',
'You need to define your input fields explicitly. Otherwise the parent cannot provide data and you will not receive input data.',
// This condition checks if we have no input fields, which gets a bit awkward:
// For WORKFLOW_INPUTS: keys() only contains `VALUES` if at least one value is provided
// For JSON_EXAMPLE: We remove all whitespace and check if we're left with an empty object. Note that we already error if the example is not valid JSON
// For JSON_SCHEMA: We check if we have '"properties":{}' after removing all whitespace. Otherwise the schema is invalid anyway and we'll error out elsewhere
displayCondition:
`={{$parameter['${INPUT_SOURCE}'] === '${WORKFLOW_INPUTS}' && !$parameter['${WORKFLOW_INPUTS}'].keys().length ` +
`|| $parameter['${INPUT_SOURCE}'] === '${JSON_EXAMPLE}' && $parameter['${JSON_EXAMPLE}'].toString().replaceAll(' ', '').replaceAll('\\n', '') === '{}' ` +
`|| $parameter['${INPUT_SOURCE}'] === '${JSON_SCHEMA}' && $parameter['${JSON_SCHEMA}'].toString().replaceAll(' ', '').replaceAll('\\n', '').includes('"properties":{}') }}`,
whenToDisplay: 'always',
location: 'ndv',
},
{
message:
'n8n does not support items types on Array fields. These entries will have no effect.',
// This is only best effort, but few natural use cases should trigger false positives here
displayCondition: `={{$parameter["${INPUT_SOURCE}"] === '${JSON_SCHEMA}' && $parameter["${JSON_SCHEMA}"].toString().includes('"items":') && $parameter["${JSON_SCHEMA}"].toString().includes('"array"') }}`,
`|| $parameter['${INPUT_SOURCE}'] === '${JSON_EXAMPLE}' && $parameter['${JSON_EXAMPLE}'].toString().replaceAll(' ', '').replaceAll('\\n', '') === '{}' }}`,
whenToDisplay: 'always',
location: 'ndv',
},
],
properties: [
{
displayName: `When an Execute Workflow node calls this workflow, the execution starts here.<br><br>
Specified fields below will be output by this node with values provided by the calling workflow.<br><br>
If you don't provide fields, all data passed into the 'Execute Workflow' node will be passed through instead.`,
name: 'notice',
type: 'notice',
default: '',
},
{
displayName: 'Events',
name: 'events',
@ -209,14 +178,12 @@ If you don't provide fields, all data passed into the 'Execute Workflow' node wi
value: JSON_EXAMPLE,
description: 'Infer JSON schema via JSON example output',
},
{
name: 'Using JSON Schema',
value: JSON_SCHEMA,
description: 'Provide JSON Schema',
},
],
default: WORKFLOW_INPUTS,
noDataExpression: true,
displayOptions: {
show: { '@version': [{ _cnd: { gte: 1.1 } }] },
},
},
{
displayName:
@ -247,26 +214,6 @@ If you don't provide fields, all data passed into the 'Execute Workflow' node wi
show: { '@version': [{ _cnd: { gte: 1.1 } }], inputSource: [JSON_EXAMPLE] },
},
},
{
displayName: 'JSON Schema',
name: JSON_SCHEMA,
type: 'json',
default: JSON.stringify(
{
properties: {
aField: { type: 'number' },
anotherField: { type: 'array' },
thisFieldAcceptsAnyType: { type: 'any' },
},
},
null,
2,
),
noDataExpression: true,
displayOptions: {
show: { '@version': [{ _cnd: { gte: 1.1 } }], inputSource: [JSON_SCHEMA] },
},
},
{
displayName: 'Workflow Inputs',
name: WORKFLOW_INPUTS,
@ -337,20 +284,8 @@ If you don't provide fields, all data passed into the 'Execute Workflow' node wi
name: 'ignoreTypeErrors',
type: 'boolean',
default: true,
description: 'Whether type mismatches should be ignored rather than returning an Error',
noDataExpression: true,
},
// REVIEW: Note that by having this here we commit to passing the binary data
// to the sub-workflow in the first place, otherwise we'd need this on the parent
// or at least for the parent to read this from this node.
// Is there significant cost to switching to the sub-workflow or is it all one big workflow under the hood?
{
displayName: 'Include Binary Data',
name: 'includeBinaryData',
type: 'boolean',
default: true,
description:
'Whether binary data should be included from the parent. If set to false, binary data will be removed.',
'Whether type mismatches should be ignored, rather than returning an Error',
noDataExpression: true,
},
],
@ -364,10 +299,6 @@ If you don't provide fields, all data passed into the 'Execute Workflow' node wi
if (this.getNode().typeVersion < 1.1) {
return [inputData];
} else {
if (!hasFields(this)) {
return [inputData];
}
const items: INodeExecutionData[] = [];
for (const [itemIndex, item] of inputData.entries()) {
@ -381,11 +312,6 @@ If you don't provide fields, all data passed into the 'Execute Workflow' node wi
itemIndex,
false,
);
const includeBinaryData = this.getNodeParameter(
`${INPUT_OPTIONS}.includeBinaryData`,
itemIndex,
false,
);
// Fields listed here will explicitly overwrite original fields
const newItem: INodeExecutionData = {
@ -437,12 +363,7 @@ If you don't provide fields, all data passed into the 'Execute Workflow' node wi
}
}
if (includeBinaryData) {
// Important not to assign directly to avoid modifying upstream data
items.push(Object.assign({}, item, newItem));
} else {
items.push(newItem);
}
items.push(newItem);
} catch (error) {
if (this.continueOnFail()) {
/** todo error case? */