Skip to content

Commit

Permalink
feat(Set Node): Preserve binary data by default (#9668)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Kret <michael.k@radency.com>
  • Loading branch information
elsmr and michael-radency authored Jun 18, 2024
1 parent 0524f58 commit d116353
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 12 deletions.
6 changes: 3 additions & 3 deletions cypress/e2e/5-ndv.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,17 +577,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');
Expand Down
2 changes: 1 addition & 1 deletion cypress/fixtures/Test_workflow_ndv_version.json
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
],
Expand Down
1 change: 1 addition & 0 deletions packages/editor-ui/src/components/NodeIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const iconSource = computed<NodeIconSource>(() => {
// Otherwise, extract it from icon prop
if (nodeType.icon) {
const icon = getNodeIcon(nodeType, uiStore.appliedTheme);
if (icon) {
const [type, path] = icon.split(':');
if (type === 'file') {
Expand Down
3 changes: 2 additions & 1 deletion packages/nodes-base/nodes/Set/Set.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'] = {
Expand All @@ -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);
Expand Down
120 changes: 118 additions & 2 deletions packages/nodes-base/nodes/Set/test/v2/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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: {
Expand All @@ -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', () => {
Expand Down
21 changes: 20 additions & 1 deletion packages/nodes-base/nodes/Set/v2/SetV2.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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',
Expand Down
1 change: 1 addition & 0 deletions packages/nodes-base/nodes/Set/v2/helpers/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type SetNodeOptions = {
ignoreConversionErrors?: boolean;
include?: IncludeMods;
includeBinary?: boolean;
stripBinary?: boolean;
};

export type SetField = {
Expand Down
6 changes: 5 additions & 1 deletion packages/nodes-base/nodes/Set/v2/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions packages/nodes-base/nodes/Set/v2/manual.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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 } } };
Expand Down
2 changes: 1 addition & 1 deletion packages/nodes-base/nodes/Set/v2/raw.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } };
Expand Down

0 comments on commit d116353

Please sign in to comment.