feat(core): Add special @tool displayOption (#14318)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Charlie Kolb
2025-04-04 09:22:13 +02:00
committed by GitHub
parent 9104743a5f
commit 73748e300e
24 changed files with 589 additions and 48 deletions

View File

@@ -16,6 +16,7 @@ import {
getParameterIssues,
isTriggerNode,
isExecutable,
displayParameter,
} from '@/NodeHelpers';
import type { Workflow } from '@/Workflow';
@@ -3420,6 +3421,7 @@ describe('NodeHelpers', () => {
false,
false,
null,
null,
);
expect(result).toEqual(testData.output.noneDisplayedFalse.defaultsFalse);
@@ -3430,6 +3432,7 @@ describe('NodeHelpers', () => {
true,
false,
null,
null,
);
expect(result).toEqual(testData.output.noneDisplayedFalse.defaultsTrue);
@@ -3440,6 +3443,7 @@ describe('NodeHelpers', () => {
false,
true,
null,
null,
);
expect(result).toEqual(testData.output.noneDisplayedTrue.defaultsFalse);
@@ -3450,6 +3454,7 @@ describe('NodeHelpers', () => {
true,
true,
null,
null,
);
expect(result).toEqual(testData.output.noneDisplayedTrue.defaultsTrue);
});
@@ -4193,6 +4198,7 @@ describe('NodeHelpers', () => {
testData.input.nodeValues,
testData.input.path,
testData.input.node,
null,
);
expect(result).toEqual(testData.output);
});
@@ -4209,6 +4215,18 @@ describe('NodeHelpers', () => {
parameters: {},
};
const testNodeType: INodeTypeDescription = {
name: 'Test Node',
version: 0,
defaults: {},
inputs: [],
outputs: [],
properties: [],
displayName: '',
group: [],
description: '',
};
it('Should validate required dateTime parameters if empty string', () => {
const nodeProperties: INodeProperties = {
displayName: 'Date Time',
@@ -4221,7 +4239,7 @@ describe('NodeHelpers', () => {
testDateTime: '',
};
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode);
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode, null);
expect(result).toEqual({
parameters: {
@@ -4242,7 +4260,7 @@ describe('NodeHelpers', () => {
testDateTime: undefined,
};
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode);
const result = getParameterIssues(nodeProperties, nodeValues, '', testNode, testNodeType);
expect(result).toEqual({
parameters: {
@@ -4513,4 +4531,393 @@ describe('NodeHelpers', () => {
});
}
});
describe('displayParameter', () => {
const testNode: INode = {
id: '12345',
name: 'Test Node',
typeVersion: 1,
type: 'n8n-nodes-base.testNode',
position: [1, 1],
parameters: {},
};
const testNodeType: INodeTypeDescription = {
name: 'Test Node',
version: 0,
defaults: {},
inputs: [],
outputs: [],
properties: [],
displayName: '',
group: [],
description: '',
};
const defaultTestInput = {
nodeValues: {},
parameter: {
displayName: 'Test Parameter',
name: 'testParameter',
type: 'string',
default: '',
} as INodeProperties,
node: testNode,
nodeTypeDescription: testNodeType,
nodeValuesRoot: undefined as undefined | INodeParameters,
displayKey: 'displayOptions' as 'displayOptions' | 'disabledOptions',
};
const tests: Array<[string, typeof defaultTestInput, boolean]> = [
['Should return true if no displayOptions are defined', { ...defaultTestInput }, true],
[
'Should return true if displayOptions.show conditions are met',
{
...defaultTestInput,
nodeValues: { condition: 'value1' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
condition: ['value1'],
},
},
},
},
true,
],
[
'Should return false if displayOptions.show conditions are not met',
{
...defaultTestInput,
nodeValues: { condition: 'value2' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
condition: ['value1'],
},
},
},
},
false,
],
[
'Should return false if displayOptions.hide conditions are met',
{
...defaultTestInput,
nodeValues: { condition: 'value1' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
hide: {
condition: ['value1'],
},
},
},
},
false,
],
[
'Should return true if displayOptions.hide conditions are not met',
{
...defaultTestInput,
nodeValues: { condition: 'value2' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
hide: {
condition: ['value1'],
},
},
},
},
true,
],
[
'Should return true if displayOptions.show and hide conditions are both met',
{
...defaultTestInput,
nodeValues: { condition: 'value1' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
condition: ['value1'],
},
hide: {
condition: ['value1'],
},
},
},
},
false, // Hide takes precedence over show
],
[
'Should return true if displayOptions.show conditions are met with multiple values',
{
...defaultTestInput,
nodeValues: { condition: 'value2' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
condition: ['value1', 'value2'],
},
},
},
},
true,
],
[
'Should return false if displayOptions.hide conditions are met with multiple values',
{
...defaultTestInput,
nodeValues: { condition: 'value2' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
hide: {
condition: ['value1', 'value2'],
},
},
},
},
false,
],
[
'Should return true if @tool is true in nodeTypeDescription of tool',
{
...defaultTestInput,
nodeTypeDescription: {
...testNodeType,
name: testNodeType.name + 'Tool',
},
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'@tool': [true],
},
},
},
},
true,
],
[
'Should return false if @tool is true in nodeTypeDescription of non-tool',
{
...defaultTestInput,
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'@tool': [true],
},
},
},
},
false,
],
[
'Should return true if @version condition is met',
{
...defaultTestInput,
node: {
...testNode,
typeVersion: 2,
},
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'@version': [
{
_cnd: {
gte: 2,
},
},
],
},
},
},
},
true,
],
[
'Should return false if @version condition is not met',
{
...defaultTestInput,
node: {
...testNode,
typeVersion: 1,
},
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'@version': [
{
_cnd: {
gte: 2,
},
},
],
},
},
},
},
false,
],
[
'Should return true if @tool and @version conditions are both met',
{
...defaultTestInput,
node: {
...testNode,
typeVersion: 2,
},
nodeTypeDescription: {
...testNodeType,
name: testNodeType.name + 'Tool',
},
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'@tool': [true],
'@version': [
{
_cnd: {
gte: 2,
},
},
],
},
},
},
},
true,
],
[
'Should return false if @tool is true but @version condition is not met',
{
...defaultTestInput,
node: {
...testNode,
typeVersion: 1,
},
nodeTypeDescription: {
...testNodeType,
name: testNodeType.name + 'Tool',
},
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'@tool': [true],
'@version': [
{
_cnd: {
gte: 2,
},
},
],
},
},
},
},
false,
],
[
'Should return true if no disabledOptions are defined',
{
...defaultTestInput,
displayKey: 'disabledOptions',
},
true,
],
[
'Should return false if disabledOptions.hide conditions are met',
{
...defaultTestInput,
nodeValues: { condition: 'value1' },
parameter: {
...defaultTestInput.parameter,
disabledOptions: {
hide: {
condition: ['value1'],
},
},
},
displayKey: 'disabledOptions',
},
false,
],
[
'Should return true if disabledOptions.hide conditions are not met',
{
...defaultTestInput,
nodeValues: { condition: 'value2' },
parameter: {
...defaultTestInput.parameter,
disabledOptions: {
hide: {
condition: ['value1'],
},
},
},
displayKey: 'disabledOptions',
},
true,
],
[
'Should return true if nodeValuesRoot contains a matching value for displayOptions.show',
{
...defaultTestInput,
nodeValues: {},
nodeValuesRoot: { condition: 'value1' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'/condition': ['value1'],
},
},
},
},
true,
],
[
'Should return false if nodeValuesRoot does not contain a matching value for displayOptions.show',
{
...defaultTestInput,
nodeValues: { condition: 'value1' },
nodeValuesRoot: { anotherKey: 'value1' },
parameter: {
...defaultTestInput.parameter,
displayOptions: {
show: {
'/condition': ['value1'],
},
},
},
},
false,
],
];
for (const [description, input, expected] of tests) {
test(description, () => {
const result = displayParameter(
input.nodeValues,
input.parameter,
input.node,
input.nodeTypeDescription,
input.nodeValuesRoot,
input.displayKey,
);
expect(result).toEqual(expected);
});
}
});
});