Add 'catch uncaught only' mode to Catch node

Closes #1747

This was inspired by a PR from @mauriciom75 but implemented in a different way
due to some of the internal reworking done to Flow and Subflow in the dev branch
This commit is contained in:
Nick O'Leary
2019-02-05 14:28:20 +00:00
parent aab0f2dcd5
commit 79f3669fac
6 changed files with 78 additions and 11 deletions

View File

@@ -7,6 +7,10 @@
<option value="target" data-i18n="catch.scope.selected"></options>
</select>
</div>
<div class="form-row node-input-uncaught-row">
<input type="checkbox" id="node-input-uncaught" style="display: inline-block; width: auto; vertical-align: top; margin-left: 30px; margin-right: 5px;">
<label for="node-input-uncaught" style="width: auto" data-i18n="catch.label.uncaught"></label>
</div>
<div class="form-row node-input-target-row" style="display: none;">
<div id="node-input-catch-target-container-div" style="min-height: 100px;position: relative; box-sizing: border-box; border-radius: 2px; height: 180px; border: 1px solid #ccc;overflow:hidden; ">
<div style="box-sizing: border-box; line-height: 20px; font-size: 0.8em; border-bottom: 1px solid #ddd; height: 20px;">
@@ -64,13 +68,20 @@
color:"#e49191",
defaults: {
name: {value:""},
scope: {value:null}
scope: {value:null},
uncaught: {value:false}
},
inputs:0,
outputs:1,
icon: "alert.png",
label: function() {
return this.name||(this.scope?this._("catch.catchNodes",{number:this.scope.length}):this._("catch.catch"));
if (this.name) {
return this.name;
}
if (this.scope) {
return this._("catch.catchNodes",{number:this.scope.length});
}
return this.uncaught?this._("catch.catchUncaught"):this._("catch.catch")
},
labelStyle: function() {
return this.name?"node_label_italic":"";
@@ -210,8 +221,10 @@
if (scope === "target") {
createNodeList();
$(".node-input-target-row").show();
$(".node-input-uncaught-row").hide();
} else {
$(".node-input-target-row").hide();
$(".node-input-uncaught-row").show();
}
node.resize();
});
@@ -227,6 +240,7 @@
if (scope === 'all') {
this.scope = null;
} else {
$("#node-input-uncaught").prop("checked",false);
var node = this;
node.scope = [];
$(".node-input-target-node-checkbox").each(function(n) {

View File

@@ -21,6 +21,7 @@ module.exports = function(RED) {
RED.nodes.createNode(this,n);
var node = this;
this.scope = n.scope;
this.uncaught = n.uncaught;
this.on("input",function(msg) {
this.send(msg);
});

View File

@@ -32,7 +32,8 @@
halt. This node can be used to catch those errors and handle them with a
dedicated flow.</p>
<p>By default, the node will catch errors thrown by any node on the same tab. Alternatively
it can be targetted at specific nodes.</p>
it can be targetted at specific nodes, or configured to only catch errors that
have not already been caught by a 'targeted' catch node.</p>
<p>When an error is thrown, all matching catch nodes will receive the message.</p>
<p>If an error is thrown within a subflow, the error will get handled by any
catch nodes within the subflow. If none exists, the error will be propagated

View File

@@ -72,13 +72,15 @@
"catch": {
"catch": "catch: all",
"catchNodes": "catch: __number__",
"catchUncaught": "catch: uncaught",
"label": {
"source": "Catch errors from",
"node": "node",
"type": "type",
"selectAll": "select all",
"sortByLabel": "sort by label",
"sortByType": "sort by type"
"sortByType": "sort by type",
"uncaught": "Ignore errors handled by other Catch nodes"
},
"scope": {
"all": "all nodes",

View File

@@ -212,6 +212,21 @@ class Flow {
}
}
}
this.catchNodes.sort(function(A,B) {
if (A.scope && !B.scope) {
return -1;
} else if (!A.scope && B.scope) {
return 1;
} else if (A.scope && B.scope) {
return 0;
} else if (A.uncaught && !B.uncaught) {
return 1;
} else if (!A.uncaught && B.uncaught) {
return -1;
}
return 0;
});
if (activeCount > 0) {
this.trace("------------------|--------------|-----------------");
}
@@ -419,10 +434,20 @@ class Flow {
}
handled = true;
} else {
var handledByUncaught = false;
this.catchNodes.forEach(function(targetCatchNode) {
if (targetCatchNode.scope && targetCatchNode.scope.indexOf(reportingNode.id) === -1) {
return;
}
if (!targetCatchNode.scope && targetCatchNode.uncaught && !handledByUncaught) {
if (handled) {
// This has been handled by a !uncaught catch node
return;
}
// This is an uncaught error
handledByUncaught = true;
}
var errorMessage;
if (msg) {
errorMessage = redUtil.cloneMessage(msg);