1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add bulk-activate actions for debug node

Adds the actions:

 - core:activate-all-debug-nodes
 - core:activate-all-flow-debug-nodes

to match the deactivate* actions.

Also adds:

 - core:activate-selected-debug-nodes
 - core:deactivate-selected-debug-nodes

Adds a new httpAdmin route - /debug/(enable/disable) - that can be
use to bulk enable/disable nodes via HTTP Post.
This commit is contained in:
Nick O'Leary 2020-05-27 12:20:23 +01:00
parent 95d1b7bc36
commit 876a7a4646
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
4 changed files with 151 additions and 60 deletions

View File

@ -104,7 +104,7 @@
"minami": "1.2.3",
"mocha": "^5.2.0",
"mosca": "^2.8.3",
"node-red-node-test-helper": "^0.2.3",
"node-red-node-test-helper": "^0.2.5",
"node-sass": "^4.13.1",
"should": "^8.4.0",
"sinon": "1.17.7",

View File

@ -43,9 +43,20 @@
var subWindow = null;
function activateAjaxCall(node, active, successCallback) {
var url;
var body;
if (Array.isArray(node)) {
url = "debug/"+(active?"enable":"disable");
body = {nodes: node.map(function(n) { return n.id})}
node = node[0];
} else {
url = "debug/"+node.id+"/"+(active?"enable":"disable");
}
$.ajax({
url: "debug/"+node.id+"/"+(active?"enable":"disable"),
url: url,
type: "POST",
data: body,
success: successCallback,
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status == 404) {
@ -126,7 +137,6 @@
}
},
onpaletteadd: function() {
console.log(RED);
var options = {
messageMouseEnter: function(sourceId) {
if (sourceId) {
@ -283,44 +293,76 @@
RED.events.on("project:change", this.clearMessageList);
RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) });
RED.actions.add("core:activate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(true), true); });
RED.actions.add("core:activate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, true),true); });
RED.actions.add("core:activate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, false),true); });
RED.actions.add("core:deactivate-all-debug-nodes", function() { deactivateAllDebugNodes(true); });
RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { deactivateAllDebugNodes(false); });
RED.actions.add("core:deactivate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(false), false); });
RED.actions.add("core:deactivate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, true),false); });
RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, false),false); });
function deactivateAllDebugNodes(globally) {
var historyEvents = [];
RED.nodes.eachNode(function(n) {
if (n.type === "debug" && n.active === true) {
if (globally === true || n.z == RED.workspaces.active()) {
if(RED.nodes.subflow(n.z) === undefined) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
active: n.active
},
callback: function() {
activateAjaxCall(n, n.active);
}
});
n.active = false;
n.changed = true;
n.dirty = true;
activateAjaxCall(n, n.active);
}
function getSelectedDebugNodes(state) {
var nodes = [];
var selection = RED.view.selection();
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (RED.nodes.subflow(n.z)) {
return;
}
if (n.type === 'debug' && n.active !== state) {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true).filter(function(n) {
return n.type === 'debug' && n.active !== state
}));
}
}
});
if (historyEvents.length > 0) {
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty()
});
RED.nodes.dirty(true);
}
RED.view.redraw();
return nodes;
}
function getMatchingDebugNodes(state,globally) {
var nodes = [];
var filter = {type:"debug"};
if (!globally) {
filter.z = RED.workspaces.active();
}
var candidateNodes = RED.nodes.filterNodes(filter);
nodes = candidateNodes.filter(function(n) {
return n.active !== state && !RED.nodes.subflow(n.z)
})
return nodes;
}
function setDebugNodeState(nodes,state) {
var historyEvents = [];
if (nodes.length > 0) {
activateAjaxCall(nodes,false, function(resp, textStatus, xhr) {
nodes.forEach(function(n) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
active: n.active
}
});
n.active = state;
n.changed = true;
n.dirty = true;
})
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty(),
callback: function() {
activateAjaxCall(nodes,nodes[0].active);
}
});
RED.nodes.dirty(true);
RED.view.redraw();
});
}
}
$("#red-ui-sidebar-debug-open").on("click", function(e) {

View File

@ -52,7 +52,7 @@ module.exports = function(RED) {
// Either apply the jsonata expression or...
if (preparedEditExpression) {
RED.util.evaluateJSONataExpression(preparedEditExpression, msg, (err, value) => {
if (err) { done(RED._("debug.invalid-exp", {error: editExpression})); }
if (err) { done(RED._("debug.invalid-exp", {error: editExpression})); }
else { done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value}); }
});
} else {
@ -61,7 +61,7 @@ module.exports = function(RED) {
var output = msg[property];
if (node.complete !== "false" && typeof node.complete !== "undefined") {
property = node.complete;
try { output = RED.util.getMessageProperty(msg,node.complete); }
try { output = RED.util.getMessageProperty(msg,node.complete); }
catch(err) { output = undefined; }
}
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, property:property, msg:output});
@ -84,10 +84,10 @@ module.exports = function(RED) {
// Either apply the jsonata expression or...
if (preparedStatExpression) {
RED.util.evaluateJSONataExpression(preparedStatExpression, msg, (err, value) => {
if (err) { done(RED._("debug.invalid-exp", {error:editExpression})); }
if (err) { done(RED._("debug.invalid-exp", {error:editExpression})); }
else { done(null,{msg:value}); }
});
}
}
else {
// Extract the required message property
var output;
@ -107,8 +107,8 @@ module.exports = function(RED) {
var fill = "grey";
var shape = "dot";
if (node.statusType === "auto") {
if (msg.hasOwnProperty("error")) {
fill = "red";
if (msg.hasOwnProperty("error")) {
fill = "red";
st = msg.error.message;
}
if (msg.hasOwnProperty("status")) {
@ -131,7 +131,7 @@ module.exports = function(RED) {
sendDebug({id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:msg});
}
done();
}
}
else {
prepareValue(msg,function(err,debugMsg) {
if (err) {
@ -185,24 +185,49 @@ module.exports = function(RED) {
});
RED.log.addHandler(DebugNode.logHandler);
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var node = RED.nodes.getNode(req.params.id);
var state = req.params.state;
if (node !== null && typeof node !== "undefined" ) {
if (state === "enable") {
node.active = true;
res.sendStatus(200);
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
} else if (state === "disable") {
node.active = false;
res.sendStatus(201);
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "dot";
node.status(node.oldStatus);
}
} else {
res.sendStatus(404);
function setNodeState(node,state) {
if (state) {
node.active = true;
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
} else {
node.active = false;
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "dot";
node.status(node.oldStatus);
}
}
}
RED.httpAdmin.post("/debug/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var state = req.params.state;
if (state !== 'enable' && state !== 'disable') {
res.sendStatus(404);
return;
}
var nodes = req.body && req.body.nodes;
if (Array.isArray(nodes)) {
nodes.forEach(function(id) {
var node = RED.nodes.getNode(id);
if (node !== null && typeof node !== "undefined" ) {
setNodeState(node, state === "enable");
}
})
res.sendStatus(state === "enable" ? 200 : 201);
} else {
res.sendStatus(400);
}
})
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var state = req.params.state;
if (state !== 'enable' && state !== 'disable') {
res.sendStatus(404);
return;
}
var node = RED.nodes.getNode(req.params.id);
if (node !== null && typeof node !== "undefined" ) {
setNodeState(node,state === "enable");
res.sendStatus(state === "enable" ? 200 : 201);
} else {
res.sendStatus(404);
}

View File

@ -603,6 +603,30 @@ describe('debug node', function() {
.post('/debug/n99/enable')
.expect(404).end(done);
});
it('should return 400 for invalid bulk disable', function(done) {
var flow = [{id:"n1", type:"debug", active: true }];
helper.load(debugNode, flow, function() {
helper.request()
.post('/debug/disable')
.send({})
.set('Content-type', 'application/json')
.expect(400).end(done);
});
})
it('should return success for bulk disable', function(done) {
var flow = [{id:"n1", type:"debug", active: true }];
helper.load(debugNode, flow, function() {
helper.request()
.post('/debug/disable')
.send({nodes:['n1']})
.set('Content-type', 'application/json')
.expect(201).end(done);
});
})
});
describe('get', function() {