feat(core): Add support for pairedItem (beta) (#3012)
* ✨ Add pairedItem support * 👕 Fix lint issue * 🐛 Fix resolution in frontend * 🐛 Fix resolution issue * 🐛 Fix resolution in frontend * 🐛 Fix another resolution issue in frontend * ⚡ Try to automatically add pairedItem data if possible * ⚡ Cleanup * ⚡ Display expression errors in editor UI * 🐛 Fix issue that it did not display errors in production * 🐛 Fix auto-fix of missing pairedItem data * 🐛 Fix frontend resolution for not executed nodes * ⚡ Fail execution on pairedItem resolve issue and display information about itemIndex and runIndex * ⚡ Allow that pairedItem is only set to number if runIndex is 0 * ✨ Improve Expression Errors * ⚡ Remove no longer needed code * ⚡ Make errors more helpful * ⚡ Add additional errors * 👕 Fix lint issue * ⚡ Add pairedItem support to core nodes * ⚡ Improve support in Merge-Node * ⚡ Fix issue with not correctly converted incoming pairedItem data * 🐛 Fix frontend resolve issue * 🐛 Fix frontend parameter name display issue * ⚡ Improve errors * 👕 Fix lint issue * ⚡ Improve errors * ⚡ Make it possible to display parameter name in error messages * ⚡ Improve error messages * ⚡ Fix error message * ⚡ Improve error messages * ⚡ Add another error message * ⚡ Simplify
This commit is contained in:
@@ -257,6 +257,9 @@ export class Compression implements INodeType {
|
||||
returnData.push({
|
||||
json: items[i].json,
|
||||
binary: binaryObject,
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -314,6 +317,9 @@ export class Compression implements INodeType {
|
||||
binary: {
|
||||
[binaryPropertyOutput]: data,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -321,13 +327,23 @@ export class Compression implements INodeType {
|
||||
returnData.push({
|
||||
json: items[i].json,
|
||||
binary: binaryObject,
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: error.message } });
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -493,11 +493,17 @@ export class Crypto implements INodeType {
|
||||
// Uses dot notation so copy all data
|
||||
newItem = {
|
||||
json: JSON.parse(JSON.stringify(item.json)),
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Does not use dot notation so shallow copy is enough
|
||||
newItem = {
|
||||
json: { ...item.json },
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -511,7 +517,14 @@ export class Crypto implements INodeType {
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: (error as JsonObject).message } });
|
||||
returnData.push({
|
||||
json: {
|
||||
error: (error as JsonObject).message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -446,11 +446,17 @@ export class DateTime implements INodeType {
|
||||
// Uses dot notation so copy all data
|
||||
newItem = {
|
||||
json: JSON.parse(JSON.stringify(item.json)),
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Does not use dot notation so shallow copy is enough
|
||||
newItem = {
|
||||
json: { ...item.json },
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -485,11 +491,17 @@ export class DateTime implements INodeType {
|
||||
// Uses dot notation so copy all data
|
||||
newItem = {
|
||||
json: JSON.parse(JSON.stringify(item.json)),
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Does not use dot notation so shallow copy is enough
|
||||
newItem = {
|
||||
json: { ...item.json },
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -504,7 +516,14 @@ export class DateTime implements INodeType {
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({json:{ error: error.message }});
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -1211,6 +1211,9 @@ export class EditImage implements INodeType {
|
||||
const newItem: INodeExecutionData = {
|
||||
json: item.json,
|
||||
binary: {},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
if (operation === 'information') {
|
||||
@@ -1394,7 +1397,14 @@ export class EditImage implements INodeType {
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({json:{ error: error.message }});
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -204,11 +204,23 @@ export class EmailSend implements INodeType {
|
||||
// Send the email
|
||||
const info = await transporter.sendMail(mailOptions);
|
||||
|
||||
returnData.push({ json: info as unknown as IDataObject });
|
||||
returnData.push({
|
||||
json: info as unknown as IDataObject,
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
}catch (error) {
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({json:{ error: error.message }});
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -119,12 +119,22 @@ export class ExecuteCommand implements INodeType {
|
||||
stderr,
|
||||
stdout,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnItems.push({json:{ error: error.message }});
|
||||
returnItems.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -163,6 +163,9 @@ return item;`,
|
||||
|
||||
const returnItem: INodeExecutionData = {
|
||||
json: cleanupData(jsonData),
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
if (item.binary) {
|
||||
@@ -172,7 +175,14 @@ return item;`,
|
||||
returnData.push(returnItem);
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({json:{ error: error.message }});
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -259,7 +259,14 @@ export class Git implements INodeType {
|
||||
|
||||
await git.add(pathsToAdd.split(','));
|
||||
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'addConfig') {
|
||||
// ----------------------------------
|
||||
@@ -275,7 +282,14 @@ export class Git implements INodeType {
|
||||
}
|
||||
|
||||
await git.addConfig(key, value, append);
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'clone') {
|
||||
// ----------------------------------
|
||||
@@ -287,7 +301,14 @@ export class Git implements INodeType {
|
||||
|
||||
await git.clone(sourceRepository, '.');
|
||||
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'commit') {
|
||||
// ----------------------------------
|
||||
@@ -303,7 +324,14 @@ export class Git implements INodeType {
|
||||
|
||||
await git.commit(message, pathsToAdd);
|
||||
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'fetch') {
|
||||
// ----------------------------------
|
||||
@@ -311,7 +339,14 @@ export class Git implements INodeType {
|
||||
// ----------------------------------
|
||||
|
||||
await git.fetch();
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'log') {
|
||||
// ----------------------------------
|
||||
@@ -331,7 +366,12 @@ export class Git implements INodeType {
|
||||
const log = await git.log(logOptions);
|
||||
|
||||
// @ts-ignore
|
||||
returnItems.push(...this.helpers.returnJsonArray(log.all));
|
||||
returnItems.push(...this.helpers.returnJsonArray(log.all).map(item => {
|
||||
return {
|
||||
...item,
|
||||
pairedItem: { item: itemIndex },
|
||||
};
|
||||
}));
|
||||
|
||||
} else if (operation === 'pull') {
|
||||
// ----------------------------------
|
||||
@@ -339,7 +379,14 @@ export class Git implements INodeType {
|
||||
// ----------------------------------
|
||||
|
||||
await git.pull();
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'push') {
|
||||
// ----------------------------------
|
||||
@@ -370,7 +417,14 @@ export class Git implements INodeType {
|
||||
}
|
||||
}
|
||||
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'pushTags') {
|
||||
// ----------------------------------
|
||||
@@ -378,7 +432,14 @@ export class Git implements INodeType {
|
||||
// ----------------------------------
|
||||
|
||||
await git.pushTags();
|
||||
returnItems.push({ json: { success: true } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
|
||||
} else if (operation === 'listConfig') {
|
||||
// ----------------------------------
|
||||
@@ -396,7 +457,12 @@ export class Git implements INodeType {
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
returnItems.push(...this.helpers.returnJsonArray(data));
|
||||
returnItems.push(...this.helpers.returnJsonArray(data).map(item => {
|
||||
return {
|
||||
...item,
|
||||
pairedItem: { item: itemIndex },
|
||||
};
|
||||
}));
|
||||
|
||||
} else if (operation === 'status') {
|
||||
// ----------------------------------
|
||||
@@ -406,7 +472,12 @@ export class Git implements INodeType {
|
||||
const status = await git.status();
|
||||
|
||||
// @ts-ignore
|
||||
returnItems.push(...this.helpers.returnJsonArray([status]));
|
||||
returnItems.push(...this.helpers.returnJsonArray([status]).map(item => {
|
||||
return {
|
||||
...item,
|
||||
pairedItem: { item: itemIndex },
|
||||
};
|
||||
}));
|
||||
|
||||
} else if (operation === 'tag') {
|
||||
// ----------------------------------
|
||||
@@ -416,14 +487,27 @@ export class Git implements INodeType {
|
||||
const name = this.getNodeParameter('name', itemIndex, '') as string;
|
||||
|
||||
await git.addTag(name);
|
||||
returnItems.push({ json: { success: true } });
|
||||
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
if (this.continueOnFail()) {
|
||||
returnItems.push({ json: { error: error.toString() } });
|
||||
returnItems.push({
|
||||
json: {
|
||||
error: error.toString(),
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -254,6 +254,9 @@ export class HtmlExtract implements INodeType {
|
||||
|
||||
const newItem: INodeExecutionData = {
|
||||
json: {},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
// Itterate over all the defined values which should be extracted
|
||||
@@ -277,7 +280,14 @@ export class HtmlExtract implements INodeType {
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: error.message } });
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -1232,6 +1232,9 @@ export class HttpRequest implements INodeType {
|
||||
json: {
|
||||
error: response.reason,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
},
|
||||
);
|
||||
continue;
|
||||
@@ -1251,6 +1254,9 @@ export class HttpRequest implements INodeType {
|
||||
const newItem: INodeExecutionData = {
|
||||
json: {},
|
||||
binary: {},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
if (items[itemIndex].binary !== undefined) {
|
||||
@@ -1295,12 +1301,20 @@ export class HttpRequest implements INodeType {
|
||||
|
||||
returnItem[property] = response![property];
|
||||
}
|
||||
returnItems.push({ json: returnItem });
|
||||
returnItems.push({
|
||||
json: returnItem,
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
returnItems.push({
|
||||
json: {
|
||||
[dataPropertyName]: response,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -1319,7 +1333,12 @@ export class HttpRequest implements INodeType {
|
||||
}
|
||||
}
|
||||
|
||||
returnItems.push({ json: returnItem });
|
||||
returnItems.push({
|
||||
json: returnItem,
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if (responseFormat === 'json' && typeof response === 'string') {
|
||||
try {
|
||||
@@ -1330,9 +1349,19 @@ export class HttpRequest implements INodeType {
|
||||
}
|
||||
|
||||
if (options.splitIntoItems === true && Array.isArray(response)) {
|
||||
response.forEach(item => returnItems.push({ json: item }));
|
||||
response.forEach(item => returnItems.push({
|
||||
json: item,
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
returnItems.push({ json: response });
|
||||
returnItems.push({
|
||||
json: response,
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,6 +355,9 @@ export class ICalendar implements INodeType {
|
||||
binary: {
|
||||
[binaryPropertyName]: binaryData,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -752,7 +752,12 @@ return 0;`,
|
||||
newItem = { ...newItem, [destinationFieldName as string || fieldToSplitOut as string]: element };
|
||||
}
|
||||
|
||||
returnData.push({ json: newItem });
|
||||
returnData.push({
|
||||
json: newItem,
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -790,8 +795,17 @@ return 0;`,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let newItem: INodeExecutionData;
|
||||
newItem = { json: {} };
|
||||
newItem = {
|
||||
json: {},
|
||||
pairedItem: Array.from({length}, (_, i) => i).map(index => {
|
||||
return {
|
||||
item: index,
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
// tslint:disable-next-line: no-any
|
||||
const values: { [key: string]: any } = {};
|
||||
const outputFields: string[] = [];
|
||||
@@ -899,9 +913,10 @@ return 0;`,
|
||||
}
|
||||
keys = fieldsToCompare.map(key => (key.trim()));
|
||||
}
|
||||
|
||||
// This solution is O(nlogn)
|
||||
// add original index to the items
|
||||
const newItems = items.map((item, index) => ({ json: { ...item['json'], __INDEX: index, }, } as INodeExecutionData));
|
||||
const newItems = items.map((item, index) => ({ json: { ...item['json'], __INDEX: index, }, pairedItem: { item: index, } } as INodeExecutionData));
|
||||
//sort items using the compare keys
|
||||
newItems.sort((a, b) => {
|
||||
let result = 0;
|
||||
@@ -962,7 +977,7 @@ return 0;`,
|
||||
let data = items.filter((_, index) => !removedIndexes.includes(index));
|
||||
|
||||
if (removeOtherFields) {
|
||||
data = data.map(item => ({ json: pick(item.json, ...keys) }));
|
||||
data = data.map((item, index) => ({ json: pick(item.json, ...keys), pairedItem: { item: index, } }));
|
||||
}
|
||||
|
||||
// return the filtered items
|
||||
|
||||
@@ -44,6 +44,7 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat
|
||||
if (this.continueOnFail()) {
|
||||
operationResult.push({json: this.getInputData(i)[0].json, error: err});
|
||||
} else {
|
||||
if (err.context) err.context.itemIndex = i;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IPairedItemData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
||||
@@ -261,6 +262,10 @@ export class Merge implements INodeType {
|
||||
|
||||
newItem = {
|
||||
json: {},
|
||||
pairedItem: [
|
||||
dataInput1[i].pairedItem as IPairedItemData,
|
||||
dataInput2[i].pairedItem as IPairedItemData,
|
||||
],
|
||||
};
|
||||
|
||||
if (dataInput1[i].binary !== undefined) {
|
||||
@@ -305,7 +310,15 @@ export class Merge implements INodeType {
|
||||
|
||||
for (entry1 of dataInput1) {
|
||||
for (entry2 of dataInput2) {
|
||||
returnData.push({json: {...(entry1.json), ...(entry2.json)}});
|
||||
returnData.push({
|
||||
json: {
|
||||
...(entry1.json), ...(entry2.json),
|
||||
},
|
||||
pairedItem: [
|
||||
entry1.pairedItem as IPairedItemData,
|
||||
entry2.pairedItem as IPairedItemData,
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
return [returnData];
|
||||
|
||||
@@ -380,6 +380,9 @@ export class MoveBinaryData implements INodeType {
|
||||
// Copy the whole JSON data as data on any level can be renamed
|
||||
newItem = {
|
||||
json: {},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
if (mode === 'binaryToJson') {
|
||||
|
||||
@@ -76,6 +76,9 @@ export class ReadBinaryFile implements INodeType {
|
||||
const newItem: INodeExecutionData = {
|
||||
json: item.json,
|
||||
binary: {},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
if (item.binary !== undefined) {
|
||||
@@ -90,7 +93,14 @@ export class ReadBinaryFile implements INodeType {
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({json:{ error: error.message }});
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -65,6 +65,9 @@ export class ReadBinaryFiles implements INodeType {
|
||||
[dataPropertyName]: await this.helpers.prepareBinaryData(data, filePath),
|
||||
},
|
||||
json: {},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
|
||||
@@ -60,7 +60,14 @@ export class ReadPdf implements INodeType {
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({json:{ error: error.message }});
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -88,6 +88,9 @@ export class RenameKeys implements INodeType {
|
||||
// Copy the whole JSON data as data on any level can be renamed
|
||||
newItem = {
|
||||
json: JSON.parse(JSON.stringify(item.json)),
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
|
||||
if (item.binary !== undefined) {
|
||||
|
||||
@@ -145,6 +145,7 @@ export class Set implements INodeType {
|
||||
|
||||
const newItem: INodeExecutionData = {
|
||||
json: {},
|
||||
pairedItem: item.pairedItem,
|
||||
};
|
||||
|
||||
if (keepOnlySet !== true) {
|
||||
|
||||
@@ -94,6 +94,12 @@ export class SplitInBatches implements INodeType {
|
||||
return null;
|
||||
}
|
||||
|
||||
returnItems.map((item, index) => {
|
||||
item.pairedItem = {
|
||||
item: index,
|
||||
};
|
||||
});
|
||||
|
||||
return this.prepareOutputData(returnItems);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,17 +391,36 @@ export class SpreadsheetFile implements INodeType {
|
||||
if (options.headerRow === false) {
|
||||
// Data was returned as an array - https://github.com/SheetJS/sheetjs#json
|
||||
for (const rowData of sheetJson) {
|
||||
newItems.push({ json: { row: rowData } } as INodeExecutionData);
|
||||
newItems.push({
|
||||
json: {
|
||||
row: rowData,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
} as INodeExecutionData);
|
||||
}
|
||||
} else {
|
||||
for (const rowData of sheetJson) {
|
||||
newItems.push({ json: rowData } as INodeExecutionData);
|
||||
newItems.push({
|
||||
json: rowData,
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
} as INodeExecutionData);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
newItems.push({json:{ error: error.message }});
|
||||
newItems.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
@@ -466,6 +485,9 @@ export class SpreadsheetFile implements INodeType {
|
||||
const newItem: INodeExecutionData = {
|
||||
json: {},
|
||||
binary: {},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
};
|
||||
|
||||
let fileName = `spreadsheet.${fileFormat}`;
|
||||
@@ -478,7 +500,14 @@ export class SpreadsheetFile implements INodeType {
|
||||
newItems.push(newItem);
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
newItems.push({json:{ error: error.message }});
|
||||
newItems.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: 0,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ export class Ssh implements INodeType {
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
const returnItems: INodeExecutionData[] = [];
|
||||
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
@@ -333,7 +333,12 @@ export class Ssh implements INodeType {
|
||||
|
||||
const command = this.getNodeParameter('command', i) as string;
|
||||
const cwd = this.getNodeParameter('cwd', i) as string;
|
||||
returnData.push(await ssh.execCommand(command, { cwd, }));
|
||||
returnItems.push({
|
||||
json: await ssh.execCommand(command, { cwd, }),
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,6 +357,9 @@ export class Ssh implements INodeType {
|
||||
const newItem: INodeExecutionData = {
|
||||
json: items[i].json,
|
||||
binary: {},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
};
|
||||
|
||||
if (items[i].binary !== undefined) {
|
||||
@@ -395,7 +403,14 @@ export class Ssh implements INodeType {
|
||||
|
||||
await ssh.putFile(path, `${parameterPath}${(parameterPath.charAt(parameterPath.length - 1) === '/') ? '' : '/'}${fileName || binaryData.fileName}`);
|
||||
|
||||
returnData.push({ success: true });
|
||||
returnItems.push({
|
||||
json: {
|
||||
success: true,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -407,7 +422,14 @@ export class Ssh implements INodeType {
|
||||
},
|
||||
};
|
||||
} else {
|
||||
returnData.push({ error: error.message });
|
||||
returnItems.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -428,7 +450,7 @@ export class Ssh implements INodeType {
|
||||
// For file downloads the files get attached to the existing items
|
||||
return this.prepareOutputData(items);
|
||||
} else {
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
return this.prepareOutputData(returnItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,9 @@ export class WriteBinaryFile implements INodeType {
|
||||
|
||||
const newItem: INodeExecutionData = {
|
||||
json: {},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
};
|
||||
Object.assign(newItem.json, item.json);
|
||||
|
||||
@@ -100,7 +103,14 @@ export class WriteBinaryFile implements INodeType {
|
||||
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: error.message } });
|
||||
returnData.push({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -262,13 +262,23 @@ export class Xml implements INodeType {
|
||||
json: {
|
||||
[dataPropertyName]: builder.buildObject(items[itemIndex].json),
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw new NodeOperationError(this.getNode(), `The operation "${mode}" is not known!`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
items[itemIndex] = ({json:{ error: error.message }});
|
||||
items[itemIndex] = ({
|
||||
json: {
|
||||
error: error.message,
|
||||
},
|
||||
pairedItem: {
|
||||
item: itemIndex,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
|
||||
Reference in New Issue
Block a user