From 2c38ea9c783201abc9aa575d9fa7b0aa497103cd Mon Sep 17 00:00:00 2001 From: Oleg Ivaniv Date: Tue, 16 Jul 2024 16:31:53 +0200 Subject: [PATCH] Add `exists` dispalyCondition --- .../llms/LMChatOpenAi/LmChatOpenAi.node.ts | 24 +- .../nodes/llms/LMOpenAi/LmOpenAi.node.ts | 12 + packages/workflow/src/Interfaces.ts | 3 +- packages/workflow/src/NodeHelpers.ts | 7 +- .../test/NodeHelpers.conditions.test.ts | 268 ++++++++++++++++++ 5 files changed, 297 insertions(+), 17 deletions(-) diff --git a/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/LmChatOpenAi.node.ts b/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/LmChatOpenAi.node.ts index 6de6cfbe4b158..eaaf4b6315374 100644 --- a/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/LmChatOpenAi.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/llms/LMChatOpenAi/LmChatOpenAi.node.ts @@ -54,18 +54,6 @@ export class LmChatOpenAi implements INodeType { }, properties: [ getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]), - { - displayName: - 'When using non OpenAI models, not all models might be chat-compatible or support other features, like tools calling or JSON response format.', - name: 'notice', - type: 'notice', - default: '', - displayOptions: { - hide: { - '/options.baseURL': [{ _cnd: { eq: undefined } }], - }, - }, - }, { displayName: 'If using JSON response format, you must include word "json" in the prompt in your chain or agent. Also, make sure to select latest models released post November 2023.', @@ -135,6 +123,18 @@ export class LmChatOpenAi implements INodeType { }, default: 'gpt-3.5-turbo', }, + { + displayName: + 'When using non-OpenAI models via "Base URL" override, not all models might be chat-compatible or support other features, like tools calling or JSON response format', + name: 'notice', + type: 'notice', + default: '', + displayOptions: { + show: { + '/options.baseURL': [{ _cnd: { exists: true } }], + }, + }, + }, { displayName: 'Options', name: 'options', diff --git a/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts b/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts index 7f56267fbd2ab..5408fc4da90ac 100644 --- a/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts +++ b/packages/@n8n/nodes-langchain/nodes/llms/LMOpenAi/LmOpenAi.node.ts @@ -97,6 +97,18 @@ export class LmOpenAi implements INodeType { }, }, }, + { + displayName: + 'When using non OpenAI models via Base URL override, not all models might be chat-compatible or support other features, like tools calling or JSON response format.', + name: 'notice', + type: 'notice', + default: '', + displayOptions: { + show: { + '/options.baseURL': [{ _cnd: { exists: true } }], + }, + }, + }, { displayName: 'Options', name: 'options', diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 68dd5bea06d81..7dd082385a813 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1284,7 +1284,8 @@ export type DisplayCondition = | { _cnd: { startsWith: string } } | { _cnd: { endsWith: string } } | { _cnd: { includes: string } } - | { _cnd: { regex: string } }; + | { _cnd: { regex: string } } + | { _cnd: { exists: true } }; export interface IDisplayOptions { hide?: { diff --git a/packages/workflow/src/NodeHelpers.ts b/packages/workflow/src/NodeHelpers.ts index 05e4ad27a74e0..1f27bacee9a39 100644 --- a/packages/workflow/src/NodeHelpers.ts +++ b/packages/workflow/src/NodeHelpers.ts @@ -488,13 +488,9 @@ const checkConditions = ( return actualValues.every((propertyValue) => { if (key === 'eq') { - if (targetValue === null) return isEqual(propertyValue, undefined); - return isEqual(propertyValue, targetValue); } if (key === 'not') { - if (targetValue === null) return !isEqual(propertyValue, undefined); - return !isEqual(propertyValue, targetValue); } if (key === 'gte') { @@ -525,6 +521,9 @@ const checkConditions = ( if (key === 'regex') { return new RegExp(targetValue as string).test(propertyValue as string); } + if (key === 'exists') { + return propertyValue !== null && propertyValue !== undefined && propertyValue !== ''; + } return false; }); } diff --git a/packages/workflow/test/NodeHelpers.conditions.test.ts b/packages/workflow/test/NodeHelpers.conditions.test.ts index 9e1bcec5f0f8c..05355d4a2ec74 100644 --- a/packages/workflow/test/NodeHelpers.conditions.test.ts +++ b/packages/workflow/test/NodeHelpers.conditions.test.ts @@ -1887,6 +1887,274 @@ describe('NodeHelpers', () => { }, }, }, + { + description: + 'simple values with displayOptions "show" using exists condition. No values set.', + input: { + nodePropertiesArray: [ + { + name: 'field1', + displayName: 'Field 1', + type: 'string', + default: '', + }, + { + name: 'field2', + displayName: 'Field 2', + displayOptions: { + show: { + field1: [{ _cnd: { exists: true } }], + }, + }, + type: 'string', + default: 'default field2', + }, + ], + nodeValues: {}, + }, + output: { + noneDisplayedFalse: { + defaultsFalse: {}, + defaultsTrue: { + field1: '', + }, + }, + noneDisplayedTrue: { + defaultsFalse: {}, + defaultsTrue: { + field1: '', + field2: 'default field2', + }, + }, + }, + }, + { + description: + 'simple values with displayOptions "show" using exists condition. Field1 has a value.', + input: { + nodePropertiesArray: [ + { + name: 'field1', + displayName: 'Field 1', + type: 'string', + default: '', + }, + { + name: 'field2', + displayName: 'Field 2', + displayOptions: { + show: { + field1: [{ _cnd: { exists: true } }], + }, + }, + type: 'string', + default: 'default field2', + }, + ], + nodeValues: { + field1: 'some value', + }, + }, + output: { + noneDisplayedFalse: { + defaultsFalse: { + field1: 'some value', + }, + defaultsTrue: { + field1: 'some value', + field2: 'default field2', + }, + }, + noneDisplayedTrue: { + defaultsFalse: { + field1: 'some value', + }, + defaultsTrue: { + field1: 'some value', + field2: 'default field2', + }, + }, + }, + }, + { + description: + 'complex type "fixedCollection" with "multipleValues: false" and with displayOptions "show" using exists condition.', + input: { + nodePropertiesArray: [ + { + name: 'values', + displayName: 'Values', + type: 'fixedCollection', + default: {}, + options: [ + { + name: 'data', + displayName: 'Data', + values: [ + { + name: 'field1', + displayName: 'Field 1', + type: 'string', + default: '', + }, + { + name: 'field2', + displayName: 'Field 2', + type: 'string', + displayOptions: { + show: { + field1: [{ _cnd: { exists: true } }], + }, + }, + default: 'default field2', + }, + ], + }, + ], + }, + ], + nodeValues: { + values: { + data: { + field1: 'some value', + }, + }, + }, + }, + output: { + noneDisplayedFalse: { + defaultsFalse: { + values: { + data: { + field1: 'some value', + }, + }, + }, + defaultsTrue: { + values: { + data: { + field1: 'some value', + field2: 'default field2', + }, + }, + }, + }, + noneDisplayedTrue: { + defaultsFalse: { + values: { + data: { + field1: 'some value', + }, + }, + }, + defaultsTrue: { + values: { + data: { + field1: 'some value', + field2: 'default field2', + }, + }, + }, + }, + }, + }, + { + description: + 'complex type "collection" with "multipleValues: true" and with displayOptions "show" using exists condition.', + input: { + nodePropertiesArray: [ + { + name: 'values', + displayName: 'Values', + type: 'collection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'field1', + displayName: 'Field 1', + type: 'string', + default: '', + }, + { + name: 'field2', + displayName: 'Field 2', + type: 'string', + displayOptions: { + show: { + field1: [{ _cnd: { exists: true } }], + }, + }, + default: 'default field2', + }, + ], + }, + ], + nodeValues: { + values: [ + { + field1: 'value1', + }, + { + field1: '', + }, + {}, + ], + }, + }, + output: { + noneDisplayedFalse: { + defaultsFalse: { + values: [ + { + field1: 'value1', + }, + { + field1: '', + }, + {}, + ], + }, + defaultsTrue: { + values: [ + { + field1: 'value1', + }, + { + field1: '', + }, + {}, + ], + }, + }, + noneDisplayedTrue: { + defaultsFalse: { + values: [ + { + field1: 'value1', + }, + { + field1: '', + }, + {}, + ], + }, + defaultsTrue: { + values: [ + { + field1: 'value1', + }, + { + field1: '', + }, + {}, + ], + }, + }, + }, + }, ]; for (const testData of tests) {