From 908ad2ed0a3835def85ec3440f14c2dd1dede36a Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Fri, 7 Jun 2024 14:25:51 +0200 Subject: [PATCH 1/3] Preserve binary data by default in Set node --- packages/nodes-base/nodes/Set/Set.node.ts | 3 +- .../nodes/Set/test/v2/utils.test.ts | 120 +++++++++++++++++- .../nodes-base/nodes/Set/v2/SetV2.node.ts | 21 ++- .../nodes/Set/v2/helpers/interfaces.ts | 1 + .../nodes-base/nodes/Set/v2/helpers/utils.ts | 6 +- .../nodes-base/nodes/Set/v2/manual.mode.ts | 4 +- packages/nodes-base/nodes/Set/v2/raw.mode.ts | 2 +- 7 files changed, 149 insertions(+), 8 deletions(-) diff --git a/packages/nodes-base/nodes/Set/Set.node.ts b/packages/nodes-base/nodes/Set/Set.node.ts index 1a74e8a42cd79..f2c71e2db6b35 100644 --- a/packages/nodes-base/nodes/Set/Set.node.ts +++ b/packages/nodes-base/nodes/Set/Set.node.ts @@ -12,7 +12,7 @@ export class Set extends VersionedNodeType { icon: 'fa:pen', group: ['input'], description: 'Add or edit fields on an input item and optionally remove other fields', - defaultVersion: 3.3, + defaultVersion: 3.4, }; const nodeVersions: IVersionedNodeType['nodeVersions'] = { @@ -22,6 +22,7 @@ export class Set extends VersionedNodeType { 3.1: new SetV2(baseDescription), 3.2: new SetV2(baseDescription), 3.3: new SetV2(baseDescription), + 3.4: new SetV2(baseDescription), }; super(nodeVersions, baseDescription); diff --git a/packages/nodes-base/nodes/Set/test/v2/utils.test.ts b/packages/nodes-base/nodes/Set/test/v2/utils.test.ts index 06d8d10aa50a3..fc84d08129607 100644 --- a/packages/nodes-base/nodes/Set/test/v2/utils.test.ts +++ b/packages/nodes-base/nodes/Set/test/v2/utils.test.ts @@ -69,7 +69,7 @@ describe('test Set2, composeReturnItem', () => { include: 'none', }; - const result = composeReturnItem.call(fakeExecuteFunction, 0, inputItem, newData, options); + const result = composeReturnItem.call(fakeExecuteFunction, 0, inputItem, newData, options, 3.4); expect(result).toEqual({ json: { @@ -114,7 +114,7 @@ describe('test Set2, composeReturnItem', () => { include: 'selected', }; - const result = composeReturnItem.call(fakeExecuteFunction, 0, inputItem, newData, options); + const result = composeReturnItem.call(fakeExecuteFunction, 0, inputItem, newData, options, 3.4); expect(result).toEqual({ json: { @@ -132,6 +132,122 @@ describe('test Set2, composeReturnItem', () => { }, }); }); + + it('should include binary when expected in version <3.4', () => { + const fakeExecuteFunction = createMockExecuteFunction({}); + + const inputItem = { + json: { + input1: 'value1', + input2: 2, + input3: [1, 2, 3], + }, + pairedItem: { + item: 0, + input: undefined, + }, + binary: { + data: { + data: 'content', + mimeType: 'image/jpg', + }, + }, + }; + + const newData = { + num1: 55, + str1: '42', + arr1: ['foo', 'bar'], + obj: { + key: 'value', + }, + }; + + const resultWithIncludeBinary = composeReturnItem.call( + fakeExecuteFunction, + 0, + inputItem, + newData, + { + include: 'all', + includeBinary: true, + }, + 3.3, + ); + + expect(resultWithIncludeBinary.binary).toEqual(inputItem.binary); + + const resultWithoutIncludeBinary = composeReturnItem.call( + fakeExecuteFunction, + 0, + inputItem, + newData, + { + include: 'all', + }, + 3.3, + ); + + expect(resultWithoutIncludeBinary.binary).toBeUndefined(); + }); + + it('should include binary when expected in version >=3.4', () => { + const fakeExecuteFunction = createMockExecuteFunction({}); + + const inputItem = { + json: { + input1: 'value1', + input2: 2, + input3: [1, 2, 3], + }, + pairedItem: { + item: 0, + input: undefined, + }, + binary: { + data: { + data: 'content', + mimeType: 'image/jpg', + }, + }, + }; + + const newData = { + num1: 55, + str1: '42', + arr1: ['foo', 'bar'], + obj: { + key: 'value', + }, + }; + + const resultWithStripBinary = composeReturnItem.call( + fakeExecuteFunction, + 0, + inputItem, + newData, + { + include: 'all', + stripBinary: true, + }, + 3.4, + ); + + expect(resultWithStripBinary.binary).toBeUndefined(); + + const resultWithoutStripBinary = composeReturnItem.call( + fakeExecuteFunction, + 0, + inputItem, + newData, + { + include: 'all', + }, + 3.4, + ); + + expect(resultWithoutStripBinary.binary).toEqual(inputItem.binary); + }); }); describe('test Set2, parseJsonParameter', () => { diff --git a/packages/nodes-base/nodes/Set/v2/SetV2.node.ts b/packages/nodes-base/nodes/Set/v2/SetV2.node.ts index 89ace04c7d9cb..fa5e6c4e1685f 100644 --- a/packages/nodes-base/nodes/Set/v2/SetV2.node.ts +++ b/packages/nodes-base/nodes/Set/v2/SetV2.node.ts @@ -21,7 +21,7 @@ const versionDescription: INodeTypeDescription = { name: 'set', iconColor: 'blue', group: ['input'], - version: [3, 3.1, 3.2, 3.3], + version: [3, 3.1, 3.2, 3.3, 3.4], description: 'Modify, add, or remove item fields', subtitle: '={{$parameter["mode"]}}', defaults: { @@ -208,8 +208,27 @@ const versionDescription: INodeTypeDescription = { name: 'includeBinary', type: 'boolean', default: true, + displayOptions: { + hide: { + '@version': [{ _cnd: { gte: 3.4 } }], + }, + }, description: 'Whether binary data should be included if present in the input item', }, + { + displayName: 'Strip Binary Data', + name: 'stripBinary', + type: 'boolean', + default: true, + description: + 'Whether binary data should be stripped from the input item. Only applies when "Include Other Input Fields" is enabled.', + displayOptions: { + show: { + '@version': [{ _cnd: { gte: 3.4 } }], + '/includeOtherFields': [true], + }, + }, + }, { displayName: 'Ignore Type Conversion Errors', name: 'ignoreConversionErrors', diff --git a/packages/nodes-base/nodes/Set/v2/helpers/interfaces.ts b/packages/nodes-base/nodes/Set/v2/helpers/interfaces.ts index 67ae19383544a..ec6fe7e416c93 100644 --- a/packages/nodes-base/nodes/Set/v2/helpers/interfaces.ts +++ b/packages/nodes-base/nodes/Set/v2/helpers/interfaces.ts @@ -5,6 +5,7 @@ export type SetNodeOptions = { ignoreConversionErrors?: boolean; include?: IncludeMods; includeBinary?: boolean; + stripBinary?: boolean; }; export type SetField = { diff --git a/packages/nodes-base/nodes/Set/v2/helpers/utils.ts b/packages/nodes-base/nodes/Set/v2/helpers/utils.ts index 7b4fbf5e33c67..a0f0eddb3836a 100644 --- a/packages/nodes-base/nodes/Set/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/Set/v2/helpers/utils.ts @@ -56,13 +56,17 @@ export function composeReturnItem( inputItem: INodeExecutionData, newFields: IDataObject, options: SetNodeOptions, + nodeVersion: number, ) { const newItem: INodeExecutionData = { json: {}, pairedItem: { item: itemIndex }, }; - if (options.includeBinary && inputItem.binary !== undefined) { + const includeBinary = + (nodeVersion >= 3.4 && !options.stripBinary && options.include !== 'none') || + (nodeVersion < 3.4 && !!options.includeBinary); + if (includeBinary && inputItem.binary !== undefined) { // Create a shallow copy of the binary data so that the old // data references which do not get changed still stay behind // but the incoming data does not get changed. diff --git a/packages/nodes-base/nodes/Set/v2/manual.mode.ts b/packages/nodes-base/nodes/Set/v2/manual.mode.ts index a02d5b5cb3b5c..282730bbf0487 100644 --- a/packages/nodes-base/nodes/Set/v2/manual.mode.ts +++ b/packages/nodes-base/nodes/Set/v2/manual.mode.ts @@ -225,7 +225,7 @@ export async function execute( newData[name] = value; } - return composeReturnItem.call(this, i, item, newData, options); + return composeReturnItem.call(this, i, item, newData, options, node.typeVersion); } const assignmentCollection = this.getNodeParameter( @@ -247,7 +247,7 @@ export async function execute( return [name, value]; }), ); - return composeReturnItem.call(this, i, item, newData, options); + return composeReturnItem.call(this, i, item, newData, options, node.typeVersion); } catch (error) { if (this.continueOnFail()) { return { json: { error: (error as Error).message, pairedItem: { item: i } } }; diff --git a/packages/nodes-base/nodes/Set/v2/raw.mode.ts b/packages/nodes-base/nodes/Set/v2/raw.mode.ts index 1ffc1f2b877e6..b24a5e2dd5f2d 100644 --- a/packages/nodes-base/nodes/Set/v2/raw.mode.ts +++ b/packages/nodes-base/nodes/Set/v2/raw.mode.ts @@ -54,7 +54,7 @@ export async function execute( ); } - return composeReturnItem.call(this, i, item, newData, options); + return composeReturnItem.call(this, i, item, newData, options, node.typeVersion); } catch (error) { if (this.continueOnFail()) { return { json: { error: (error as Error).message }, pairedItem: { item: i } }; From 522071f6ec2c6f9e3c056be6f53239c93e8c48b3 Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Mon, 10 Jun 2024 09:52:07 +0200 Subject: [PATCH 2/3] Remove console.log --- packages/editor-ui/src/components/NodeIcon.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/editor-ui/src/components/NodeIcon.vue b/packages/editor-ui/src/components/NodeIcon.vue index 47dba118c2bd4..f625856279855 100644 --- a/packages/editor-ui/src/components/NodeIcon.vue +++ b/packages/editor-ui/src/components/NodeIcon.vue @@ -104,7 +104,6 @@ const iconSource = computed(() => { // Otherwise, extract it from icon prop if (nodeType.icon) { const icon = getNodeIcon(nodeType, uiStore.appliedTheme); - console.log(nodeType.icon, icon); if (icon) { const [type, path] = icon.split(':'); From b0428b662dcf9eb924ab39ea0e5bb456219b9c2a Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Wed, 12 Jun 2024 14:36:52 +0200 Subject: [PATCH 3/3] Update e2e test --- cypress/e2e/5-ndv.cy.ts | 6 +++--- cypress/fixtures/Test_workflow_ndv_version.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/5-ndv.cy.ts b/cypress/e2e/5-ndv.cy.ts index 35021e733309d..fbb025eef646b 100644 --- a/cypress/e2e/5-ndv.cy.ts +++ b/cypress/e2e/5-ndv.cy.ts @@ -578,17 +578,17 @@ describe('NDV', () => { workflowPage.actions.openNode('Edit Fields (old)'); ndv.actions.openSettings(); - ndv.getters.nodeVersion().should('have.text', 'Set node version 2 (Latest version: 3.3)'); + ndv.getters.nodeVersion().should('have.text', 'Set node version 2 (Latest version: 3.4)'); ndv.actions.close(); workflowPage.actions.openNode('Edit Fields (latest)'); ndv.actions.openSettings(); - ndv.getters.nodeVersion().should('have.text', 'Edit Fields (Set) node version 3.3 (Latest)'); + ndv.getters.nodeVersion().should('have.text', 'Edit Fields (Set) node version 3.4 (Latest)'); ndv.actions.close(); workflowPage.actions.openNode('Edit Fields (no typeVersion)'); ndv.actions.openSettings(); - ndv.getters.nodeVersion().should('have.text', 'Edit Fields (Set) node version 3.3 (Latest)'); + ndv.getters.nodeVersion().should('have.text', 'Edit Fields (Set) node version 3.4 (Latest)'); ndv.actions.close(); workflowPage.actions.openNode('Function'); diff --git a/cypress/fixtures/Test_workflow_ndv_version.json b/cypress/fixtures/Test_workflow_ndv_version.json index d682708eb8cc5..80de6e0fdc707 100644 --- a/cypress/fixtures/Test_workflow_ndv_version.json +++ b/cypress/fixtures/Test_workflow_ndv_version.json @@ -32,7 +32,7 @@ "id": "273f60c9-08e7-457e-b01d-31e16c565171", "name": "Edit Fields (latest)", "type": "n8n-nodes-base.set", - "typeVersion": 3.3, + "typeVersion": 3.4, "position": [640, 460] } ],