mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
feat(Set Node): Preserve binary data by default (#9668)
Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
parent
0524f588f6
commit
d1163533a6
|
@ -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');
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -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') {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -5,6 +5,7 @@ export type SetNodeOptions = {
|
|||
ignoreConversionErrors?: boolean;
|
||||
include?: IncludeMods;
|
||||
includeBinary?: boolean;
|
||||
stripBinary?: boolean;
|
||||
};
|
||||
|
||||
export type SetField = {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 } } };
|
||||
|
|
|
@ -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 } };
|
||||
|
|
Loading…
Reference in a new issue