feat(core): Add optional Error-Output (#7460)

Add an additional optional error output to which all items get sent that
could not be processed.
![Screenshot from 2023-10-18
17-29-15](https://github.com/n8n-io/n8n/assets/6249596/e9732807-ab2b-4662-a5f6-bdff24f7ad55)

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:
Jan Oberhauser
2023-10-30 18:42:47 +01:00
committed by GitHub
parent 442c73e63b
commit 655efeaf66
20 changed files with 1090 additions and 61 deletions

View File

@@ -1297,6 +1297,15 @@ export default defineComponent({
stroke: var(--color-foreground-xdark);
}
&.error {
path {
fill: var(--node-error-output-color);
}
rect {
stroke: var(--node-error-output-color);
}
}
&.small {
margin-left: calc((var(--stalk-size) + var(--plus-endpoint-box-size-small) / 2));
g {
@@ -1427,6 +1436,10 @@ export default defineComponent({
}
}
.node-output-endpoint-label.node-connection-category-error {
color: var(--node-error-output-color);
}
.node-output-endpoint-label {
margin-left: calc(var(--endpoint-size-small) + var(--spacing-2xs));
@@ -1436,9 +1449,9 @@ export default defineComponent({
margin-left: 0;
}
// Switch node allows for dynamic connection labels
// Some nodes allow for dynamic connection labels
// so we need to make sure the label does not overflow
&[data-endpoint-node-type='n8n-nodes-base.switch'] {
&[data-endpoint-label-length='medium'] {
max-width: calc(var(--stalk-size) - (var(--endpoint-size-small)));
overflow: hidden;
text-overflow: ellipsis;
@@ -1495,7 +1508,8 @@ export default defineComponent({
.ep-success--without-label {
--stalk-size: var(--stalk-success-size-without-label);
}
[data-endpoint-node-type='n8n-nodes-base.switch'] {
[data-endpoint-label-length='medium'] {
--stalk-size: var(--stalk-switch-size);
}
</style>

View File

@@ -106,6 +106,7 @@
@valueChanged="valueChanged"
@execute="onNodeExecute"
@stopExecution="onStopExecution"
@redrawRequired="redrawRequired = true"
@activate="onWorkflowActivate"
/>
<a
@@ -199,6 +200,7 @@ export default defineComponent({
data() {
return {
settingsEventBus: createEventBus(),
redrawRequired: false,
runInputIndex: -1,
runOutputIndex: -1,
isLinkingEnabled: true,
@@ -633,7 +635,8 @@ export default defineComponent({
if (
typeof this.activeNodeType?.outputs === 'string' ||
typeof this.activeNodeType?.inputs === 'string'
typeof this.activeNodeType?.inputs === 'string' ||
this.redrawRequired
) {
// TODO: We should keep track of if it actually changed and only do if required
// Whenever a node with custom inputs and outputs gets closed redraw it in case

View File

@@ -371,7 +371,7 @@ export default defineComponent({
alwaysOutputData: false,
executeOnce: false,
notesInFlow: false,
continueOnFail: false,
onError: 'stopWorkflow',
retryOnFail: false,
maxTries: 3,
waitBetweenTries: 1000,
@@ -440,12 +440,39 @@ export default defineComponent({
description: this.$locale.baseText('nodeSettings.waitBetweenTries.description'),
},
{
displayName: this.$locale.baseText('nodeSettings.continueOnFail.displayName'),
name: 'continueOnFail',
type: 'boolean',
default: false,
displayName: this.$locale.baseText('nodeSettings.onError.displayName'),
name: 'onError',
type: 'options',
options: [
{
name: this.$locale.baseText('nodeSettings.onError.options.stopWorkflow.displayName'),
value: 'stopWorkflow',
description: this.$locale.baseText(
'nodeSettings.onError.options.stopWorkflow.description',
),
},
{
name: this.$locale.baseText(
'nodeSettings.onError.options.continueRegularOutput.displayName',
),
value: 'continueRegularOutput',
description: this.$locale.baseText(
'nodeSettings.onError.options.continueRegularOutput.description',
),
},
{
name: this.$locale.baseText(
'nodeSettings.onError.options.continueErrorOutput.displayName',
),
value: 'continueErrorOutput',
description: this.$locale.baseText(
'nodeSettings.onError.options.continueErrorOutput.description',
),
},
],
default: 'stopWorkflow',
noDataExpression: true,
description: this.$locale.baseText('nodeSettings.continueOnFail.description'),
description: this.$locale.baseText('nodeSettings.onError.description'),
},
{
displayName: this.$locale.baseText('nodeSettings.notes.displayName'),
@@ -633,6 +660,11 @@ export default defineComponent({
return;
}
if (parameterData.name === 'onError') {
// If that parameter changes, we need to redraw the connections, as the error output may need to be added or removed
this.$emit('redrawRequired');
}
if (parameterData.name === 'name') {
// Name of node changed so we have to set also the new node name as active
@@ -880,10 +912,18 @@ export default defineComponent({
}
if (this.node.continueOnFail) {
foundNodeSettings.push('continueOnFail');
foundNodeSettings.push('onError');
this.nodeValues = {
...this.nodeValues,
continueOnFail: this.node.continueOnFail,
onError: 'continueRegularOutput',
};
}
if (this.node.onError) {
foundNodeSettings.push('onError');
this.nodeValues = {
...this.nodeValues,
onError: this.node.onError,
};
}