mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 11:49:59 +00:00
feat(core): Add optional Error-Output (#7460)
Add an additional optional error output to which all items get sent that could not be processed.  Github issue / Community forum post (link here to close automatically): https://community.n8n.io/t/error-connector-for-nodes/3094 https://community.n8n.io/t/error-handling-at-node-level-detect-node-execution-status/26791 --------- Co-authored-by: OlegIvaniv <me@olegivaniv.com>
This commit is contained in:
@@ -920,6 +920,7 @@ export interface INodeCredentials {
|
||||
[key: string]: INodeCredentialsDetails;
|
||||
}
|
||||
|
||||
export type OnError = 'continueErrorOutput' | 'continueRegularOutput' | 'stopWorkflow';
|
||||
export interface INode {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -934,6 +935,7 @@ export interface INode {
|
||||
waitBetweenTries?: number;
|
||||
alwaysOutputData?: boolean;
|
||||
executeOnce?: boolean;
|
||||
onError?: OnError;
|
||||
continueOnFail?: boolean;
|
||||
parameters: INodeParameters;
|
||||
credentials?: INodeCredentials;
|
||||
@@ -1546,6 +1548,7 @@ export interface INodeInputConfiguration {
|
||||
}
|
||||
|
||||
export interface INodeOutputConfiguration {
|
||||
category?: string;
|
||||
displayName?: string;
|
||||
required?: boolean;
|
||||
type: ConnectionTypes;
|
||||
@@ -1653,6 +1656,11 @@ export interface IWorkflowDataProxyData {
|
||||
$thisItemIndex: number;
|
||||
$now: any;
|
||||
$today: any;
|
||||
$getPairedItem: (
|
||||
destinationNodeName: string,
|
||||
incomingSourceData: ISourceData | null,
|
||||
pairedItem: IPairedItemData,
|
||||
) => INodeExecutionData | null;
|
||||
constructor: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -1045,21 +1045,48 @@ export function getNodeOutputs(
|
||||
node: INode,
|
||||
nodeTypeData: INodeTypeDescription,
|
||||
): Array<ConnectionTypes | INodeOutputConfiguration> {
|
||||
let outputs: Array<ConnectionTypes | INodeOutputConfiguration> = [];
|
||||
|
||||
if (Array.isArray(nodeTypeData.outputs)) {
|
||||
return nodeTypeData.outputs;
|
||||
outputs = nodeTypeData.outputs;
|
||||
} else {
|
||||
// Calculate the outputs dynamically
|
||||
try {
|
||||
outputs = (workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
nodeTypeData.outputs,
|
||||
'internal',
|
||||
{},
|
||||
) || []) as ConnectionTypes[];
|
||||
} catch (e) {
|
||||
throw new Error(`Could not calculate outputs dynamically for node "${node.name}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the outputs dynamically
|
||||
try {
|
||||
return (workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
nodeTypeData.outputs,
|
||||
'internal',
|
||||
{},
|
||||
) || []) as ConnectionTypes[];
|
||||
} catch (e) {
|
||||
throw new Error(`Could not calculate outputs dynamically for node "${node.name}"`);
|
||||
if (node.onError === 'continueErrorOutput') {
|
||||
// Copy the data to make sure that we do not change the data of the
|
||||
// node type and so change the displayNames for all nodes in the flow
|
||||
outputs = deepCopy(outputs);
|
||||
if (outputs.length === 1) {
|
||||
// Set the displayName to "Success"
|
||||
if (typeof outputs[0] === 'string') {
|
||||
outputs[0] = {
|
||||
type: outputs[0],
|
||||
};
|
||||
}
|
||||
outputs[0].displayName = 'Success';
|
||||
}
|
||||
return [
|
||||
...outputs,
|
||||
{
|
||||
category: 'error',
|
||||
type: 'main',
|
||||
displayName: 'Error',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,8 +121,9 @@ export class RoutingNode {
|
||||
|
||||
// TODO: Think about how batching could be handled for REST APIs which support it
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let thisArgs: IExecuteSingleFunctions | undefined;
|
||||
try {
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteSingleFunctions(
|
||||
thisArgs = nodeExecuteFunctions.getExecuteSingleFunctions(
|
||||
this.workflow,
|
||||
this.runExecutionData,
|
||||
runIndex,
|
||||
@@ -209,7 +210,7 @@ export class RoutingNode {
|
||||
|
||||
returnData.push(...responseData);
|
||||
} catch (error) {
|
||||
if (get(this.node, 'continueOnFail', false)) {
|
||||
if (thisArgs !== undefined && thisArgs.continueOnFail()) {
|
||||
returnData.push({ json: {}, error: error.message });
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1211,6 +1211,7 @@ export class WorkflowDataProxy {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
Duration,
|
||||
...that.additionalKeys,
|
||||
$getPairedItem: getPairedItem,
|
||||
|
||||
// deprecated
|
||||
$jmespath: jmespathWrapper,
|
||||
|
||||
Reference in New Issue
Block a user