mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
feat(editor): Relocate workflow ID expression notice (no-changelog) (#12942)
This commit is contained in:
committed by
GitHub
parent
1ca6a9799a
commit
066908060f
@@ -164,8 +164,9 @@ export class WorkflowDataProxy {
|
||||
*
|
||||
* @private
|
||||
* @param {string} nodeName The name of the node to query data from
|
||||
* @param {boolean} [resolveValue=true] If the expression value should get resolved
|
||||
*/
|
||||
private nodeParameterGetter(nodeName: string) {
|
||||
private nodeParameterGetter(nodeName: string, resolveValue = true) {
|
||||
const that = this;
|
||||
const node = this.workflow.nodes[nodeName];
|
||||
|
||||
@@ -223,7 +224,7 @@ export class WorkflowDataProxy {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof returnValue === 'string' && returnValue.charAt(0) === '=') {
|
||||
if (resolveValue && typeof returnValue === 'string' && returnValue.charAt(0) === '=') {
|
||||
// The found value is an expression so resolve it
|
||||
return that.workflow.expression.getParameterValue(
|
||||
returnValue,
|
||||
@@ -1359,6 +1360,7 @@ export class WorkflowDataProxy {
|
||||
$node: this.nodeGetter(),
|
||||
$self: this.selfGetter(),
|
||||
$parameter: this.nodeParameterGetter(this.activeNodeName),
|
||||
$rawParameter: this.nodeParameterGetter(this.activeNodeName, false),
|
||||
$prevNode: this.prevNodeGetter(),
|
||||
$runIndex: this.runIndex,
|
||||
$mode: this.mode,
|
||||
|
||||
@@ -604,12 +604,237 @@ const manualTriggerNode: LoadedClass<INodeType> = {
|
||||
},
|
||||
};
|
||||
|
||||
const executeWorkflowNode: LoadedClass<INodeType> = {
|
||||
type: {
|
||||
description: {
|
||||
name: 'n8n-nodes-base.executeWorkflow',
|
||||
displayName: 'Execute Sub-workflow',
|
||||
icon: 'fa:sign-in-alt',
|
||||
iconColor: 'orange-red',
|
||||
group: ['transform'],
|
||||
version: [1, 1.1, 1.2],
|
||||
subtitle: '={{"Workflow: " + $parameter["workflowId"]}}',
|
||||
description: 'Execute another workflow',
|
||||
defaults: { name: 'Execute Workflow', color: '#ff6d5a' },
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'hidden',
|
||||
noDataExpression: true,
|
||||
default: 'call_workflow',
|
||||
options: [{ name: 'Execute a Sub-Workflow', value: 'call_workflow' }],
|
||||
},
|
||||
{
|
||||
displayName:
|
||||
'This node is out of date. Please upgrade by removing it and adding a new one',
|
||||
name: 'outdatedVersionWarning',
|
||||
type: 'notice',
|
||||
displayOptions: { show: { '@version': [{ _cnd: { lte: 1.1 } }] } },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Source',
|
||||
name: 'source',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Database',
|
||||
value: 'database',
|
||||
description: 'Load the workflow from the database by ID',
|
||||
},
|
||||
{
|
||||
name: 'Local File',
|
||||
value: 'localFile',
|
||||
description: 'Load the workflow from a locally saved file',
|
||||
},
|
||||
{
|
||||
name: 'Parameter',
|
||||
value: 'parameter',
|
||||
description: 'Load the workflow from a parameter',
|
||||
},
|
||||
{ name: 'URL', value: 'url', description: 'Load the workflow from an URL' },
|
||||
],
|
||||
default: 'database',
|
||||
description: 'Where to get the workflow to execute from',
|
||||
displayOptions: { show: { '@version': [{ _cnd: { lte: 1.1 } }] } },
|
||||
},
|
||||
{
|
||||
displayName: 'Source',
|
||||
name: 'source',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Database',
|
||||
value: 'database',
|
||||
description: 'Load the workflow from the database by ID',
|
||||
},
|
||||
{
|
||||
name: 'Define Below',
|
||||
value: 'parameter',
|
||||
description: 'Pass the JSON code of a workflow',
|
||||
},
|
||||
],
|
||||
default: 'database',
|
||||
description: 'Where to get the workflow to execute from',
|
||||
displayOptions: { show: { '@version': [{ _cnd: { gte: 1.2 } }] } },
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow ID',
|
||||
name: 'workflowId',
|
||||
type: 'string',
|
||||
displayOptions: { show: { source: ['database'], '@version': [1] } },
|
||||
default: '',
|
||||
required: true,
|
||||
hint: 'Can be found in the URL of the workflow',
|
||||
description:
|
||||
"Note on using an expression here: if this node is set to run once with all items, they will all be sent to the <em>same</em> workflow. That workflow's ID will be calculated by evaluating the expression for the <strong>first input item</strong>.",
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow',
|
||||
name: 'workflowId',
|
||||
type: 'workflowSelector',
|
||||
displayOptions: { show: { source: ['database'], '@version': [{ _cnd: { gte: 1.1 } }] } },
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow Path',
|
||||
name: 'workflowPath',
|
||||
type: 'string',
|
||||
displayOptions: { show: { source: ['localFile'] } },
|
||||
default: '',
|
||||
placeholder: '/data/workflow.json',
|
||||
required: true,
|
||||
description: 'The path to local JSON workflow file to execute',
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow JSON',
|
||||
name: 'workflowJson',
|
||||
type: 'json',
|
||||
typeOptions: { rows: 10 },
|
||||
displayOptions: { show: { source: ['parameter'] } },
|
||||
default: '\n\n\n',
|
||||
required: true,
|
||||
description: 'The workflow JSON code to execute',
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow URL',
|
||||
name: 'workflowUrl',
|
||||
type: 'string',
|
||||
displayOptions: { show: { source: ['url'] } },
|
||||
default: '',
|
||||
placeholder: 'https://example.com/workflow.json',
|
||||
required: true,
|
||||
description: 'The URL from which to load the workflow from',
|
||||
},
|
||||
{
|
||||
displayName:
|
||||
'Any data you pass into this node will be output by the Execute Workflow Trigger. <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow/" target="_blank">More info</a>',
|
||||
name: 'executeWorkflowNotice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
displayOptions: { show: { '@version': [{ _cnd: { lte: 1.1 } }] } },
|
||||
},
|
||||
{
|
||||
displayName: 'Workflow Inputs',
|
||||
name: 'workflowInputs',
|
||||
type: 'resourceMapper',
|
||||
noDataExpression: true,
|
||||
default: { mappingMode: 'defineBelow', value: null },
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsDependsOn: ['workflowId.value'],
|
||||
resourceMapper: {
|
||||
localResourceMapperMethod: 'loadSubWorkflowInputs',
|
||||
valuesLabel: 'Workflow Inputs',
|
||||
mode: 'map',
|
||||
fieldWords: { singular: 'input', plural: 'inputs' },
|
||||
addAllFields: true,
|
||||
multiKeyMatch: false,
|
||||
supportAutoMap: false,
|
||||
showTypeConversionOptions: true,
|
||||
},
|
||||
},
|
||||
displayOptions: {
|
||||
show: { source: ['database'], '@version': [{ _cnd: { gte: 1.2 } }] },
|
||||
hide: { workflowId: [''] },
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Mode',
|
||||
name: 'mode',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Run once with all items',
|
||||
value: 'once',
|
||||
description: 'Pass all items into a single execution of the sub-workflow',
|
||||
},
|
||||
{
|
||||
name: 'Run once for each item',
|
||||
value: 'each',
|
||||
description: 'Call the sub-workflow individually for each item',
|
||||
},
|
||||
],
|
||||
default: 'once',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
default: {},
|
||||
placeholder: 'Add option',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Wait For Sub-Workflow Completion',
|
||||
name: 'waitForSubWorkflow',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description:
|
||||
'Whether the main workflow should wait for the sub-workflow to complete its execution before proceeding',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
hints: [
|
||||
{
|
||||
type: 'info',
|
||||
message:
|
||||
"Note on using an expression for workflow ID: if this node is set to run once with all items, they will all be sent to the <em>same</em> workflow. That workflow's ID will be calculated by evaluating the expression for the <strong>first input item</strong>.",
|
||||
displayCondition:
|
||||
'={{ $rawParameter.workflowId.startsWith("=") && $nodeVersion >= 1.2 }}',
|
||||
whenToDisplay: 'always',
|
||||
location: 'outputPane',
|
||||
},
|
||||
],
|
||||
codex: {
|
||||
categories: ['Core Nodes'],
|
||||
subcategories: { 'Core Nodes': ['Helpers', 'Flow'] },
|
||||
alias: ['n8n', 'call', 'sub', 'workflow', 'sub-workflow', 'subworkflow'],
|
||||
resources: {
|
||||
primaryDocumentation: [
|
||||
{
|
||||
url: 'https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow/',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
sourcePath: '',
|
||||
};
|
||||
|
||||
export class NodeTypes implements INodeTypes {
|
||||
nodeTypes: INodeTypeData = {
|
||||
'n8n-nodes-base.stickyNote': stickyNode,
|
||||
'n8n-nodes-base.set': setNode,
|
||||
'test.googleSheets': googleSheetsNode,
|
||||
'test.set': setNode,
|
||||
'n8n-nodes-base.executeWorkflow': executeWorkflowNode,
|
||||
'test.setMulti': {
|
||||
sourcePath: '',
|
||||
type: {
|
||||
|
||||
@@ -549,4 +549,45 @@ describe('WorkflowDataProxy', () => {
|
||||
expect(() => getFromAIProxy().$fromAI('invalid!')).toThrow(ExpressionError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('$rawParameter', () => {
|
||||
const fixture = loadFixture('rawParameter');
|
||||
const proxy = getProxyFromFixture(fixture.workflow, fixture.run, 'Execute Workflow', 'manual', {
|
||||
connectionType: NodeConnectionType.Main,
|
||||
throwOnMissingExecutionData: false,
|
||||
runIndex: 0,
|
||||
});
|
||||
|
||||
test('returns simple raw parameter value', () => {
|
||||
expect(proxy.$rawParameter.options).toEqual({
|
||||
waitForSubWorkflow: '={{ true }}',
|
||||
});
|
||||
});
|
||||
|
||||
test('returns raw parameter value for resource locator values', () => {
|
||||
expect(proxy.$rawParameter.workflowId).toEqual('={{ $json.foo }}');
|
||||
});
|
||||
|
||||
test('returns raw parameter value when there is no run data', () => {
|
||||
const noRunDataProxy = getProxyFromFixture(
|
||||
fixture.workflow,
|
||||
{
|
||||
data: { resultData: { runData: {} } },
|
||||
mode: 'manual',
|
||||
startedAt: new Date(),
|
||||
status: 'success',
|
||||
},
|
||||
'Execute Workflow',
|
||||
'manual',
|
||||
{
|
||||
connectionType: NodeConnectionType.Main,
|
||||
throwOnMissingExecutionData: false,
|
||||
runIndex: 0,
|
||||
},
|
||||
);
|
||||
expect(noRunDataProxy.$rawParameter.options).toEqual({
|
||||
waitForSubWorkflow: '={{ true }}',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
117
packages/workflow/test/fixtures/WorkflowDataProxy/rawParameter_run.json
vendored
Normal file
117
packages/workflow/test/fixtures/WorkflowDataProxy/rawParameter_run.json
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"data": {
|
||||
"startData": {},
|
||||
"resultData": {
|
||||
"runData": {
|
||||
"_custom": {
|
||||
"type": "reactive",
|
||||
"stateTypeName": "Reactive",
|
||||
"value": {
|
||||
"Manual trigger": [
|
||||
{
|
||||
"_custom": {
|
||||
"type": "reactive",
|
||||
"stateTypeName": "Reactive",
|
||||
"value": {
|
||||
"hints": [],
|
||||
"startTime": 1738314562475,
|
||||
"executionTime": 1,
|
||||
"source": [],
|
||||
"executionStatus": "success",
|
||||
"data": { "main": [[{ "json": {}, "pairedItem": { "item": 0 } }]] }
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Edit Fields": [
|
||||
{
|
||||
"_custom": {
|
||||
"type": "reactive",
|
||||
"stateTypeName": "Reactive",
|
||||
"value": {
|
||||
"hints": [],
|
||||
"startTime": 1738314562477,
|
||||
"executionTime": 0,
|
||||
"source": [{ "previousNode": "Manual trigger" }],
|
||||
"executionStatus": "success",
|
||||
"data": {
|
||||
"main": [[{ "json": { "foo": "test" }, "pairedItem": { "item": 0 } }]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Execute Workflow": [
|
||||
{
|
||||
"hints": [],
|
||||
"startTime": 1738314562478,
|
||||
"executionTime": 2,
|
||||
"source": [{ "previousNode": "Edit Fields" }],
|
||||
"executionStatus": "error",
|
||||
"error": {
|
||||
"level": "error",
|
||||
"tags": { "packageName": "cli" },
|
||||
"extra": { "workflowId": "1.2" },
|
||||
"message": "Workflow does not exist.",
|
||||
"stack": "Error: Workflow does not exist.\n at getWorkflowData (/Users/miloradfilipovic/workspace/n8n/packages/cli/src/workflow-execute-additional-data.ts:124:10)\n at Object.executeWorkflow (/Users/miloradfilipovic/workspace/n8n/packages/cli/src/workflow-execute-additional-data.ts:155:4)\n at ExecuteContext.executeWorkflow (/Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/node-execution-context/base-execute-context.ts:120:18)\n at ExecuteContext.execute (/Users/miloradfilipovic/workspace/n8n/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow/ExecuteWorkflow.node.ts:397:50)\n at WorkflowExecute.runNode (/Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/workflow-execute.ts:1097:8)\n at /Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/workflow-execute.ts:1503:27\n at /Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/workflow-execute.ts:2064:11"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pinData": {},
|
||||
"lastNodeExecuted": "Execute Workflow",
|
||||
"error": {
|
||||
"level": "error",
|
||||
"tags": { "packageName": "cli" },
|
||||
"extra": { "workflowId": "1.2" },
|
||||
"message": "Workflow does not exist.",
|
||||
"stack": "Error: Workflow does not exist.\n at getWorkflowData (/Users/miloradfilipovic/workspace/n8n/packages/cli/src/workflow-execute-additional-data.ts:124:10)\n at Object.executeWorkflow (/Users/miloradfilipovic/workspace/n8n/packages/cli/src/workflow-execute-additional-data.ts:155:4)\n at ExecuteContext.executeWorkflow (/Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/node-execution-context/base-execute-context.ts:120:18)\n at ExecuteContext.execute (/Users/miloradfilipovic/workspace/n8n/packages/nodes-base/nodes/ExecuteWorkflow/ExecuteWorkflow/ExecuteWorkflow.node.ts:397:50)\n at WorkflowExecute.runNode (/Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/workflow-execute.ts:1097:8)\n at /Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/workflow-execute.ts:1503:27\n at /Users/miloradfilipovic/workspace/n8n/packages/core/src/execution-engine/workflow-execute.ts:2064:11"
|
||||
}
|
||||
},
|
||||
"executionData": {
|
||||
"contextData": {},
|
||||
"nodeExecutionStack": [
|
||||
{
|
||||
"node": {
|
||||
"parameters": {
|
||||
"operation": "call_workflow",
|
||||
"source": "database",
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "=1.2",
|
||||
"cachedResultName": "=1.2"
|
||||
},
|
||||
"workflowInputs": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {},
|
||||
"matchingColumns": [],
|
||||
"schema": [],
|
||||
"attemptToConvertTypes": false,
|
||||
"convertFieldsToString": true
|
||||
},
|
||||
"mode": "once",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.executeWorkflow",
|
||||
"typeVersion": 1.2,
|
||||
"position": [120, -100],
|
||||
"id": "62717ac7-614d-4e3f-b2ec-1e28688068c4",
|
||||
"name": "Execute Workflow"
|
||||
},
|
||||
"data": { "main": [[{ "json": { "foo": "test" }, "pairedItem": { "item": 0 } }]] },
|
||||
"source": { "main": [{ "previousNode": "Edit Fields" }] }
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"waitingExecution": {},
|
||||
"waitingExecutionSource": {}
|
||||
},
|
||||
"mode": "manual",
|
||||
"startedAt": "2024-02-08T15:45:18.848Z",
|
||||
"stoppedAt": "2024-02-08T15:45:18.862Z",
|
||||
"status": "success"
|
||||
}
|
||||
}
|
||||
80
packages/workflow/test/fixtures/WorkflowDataProxy/rawParameter_workflow.json
vendored
Normal file
80
packages/workflow/test/fixtures/WorkflowDataProxy/rawParameter_workflow.json
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "804e5ba7-4b1d-48c2-abfa-a36717a9fa66",
|
||||
"name": "Manual trigger",
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [-320, -100],
|
||||
"parameters": {}
|
||||
},
|
||||
{
|
||||
"id": "f995b1a2-8a49-4f0c-ae0d-8fb4c600cdef",
|
||||
"name": "Edit Fields",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [-100, -100],
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "f4d80089-a3d7-470f-8c07-dec07e37f339",
|
||||
"name": "foo",
|
||||
"value": "={{ test }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "62717ac7-614d-4e3f-b2ec-1e28688068c4",
|
||||
"name": "Execute Workflow",
|
||||
"type": "n8n-nodes-base.executeWorkflow",
|
||||
"typeVersion": 1.2,
|
||||
"position": [120, -100],
|
||||
"parameters": {
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"value": "={{ $json.foo }}",
|
||||
"mode": "id"
|
||||
},
|
||||
"workflowInputs": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {},
|
||||
"matchingColumns": [],
|
||||
"schema": [],
|
||||
"attemptToConvertTypes": false,
|
||||
"convertFieldsToString": true
|
||||
},
|
||||
"options": { "waitForSubWorkflow": "={{ true }}" }
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Manual trigger": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Edit Fields",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Edit Fields": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Execute Workflow",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"pinData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user