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

Merge branch 'master' into dev

This commit is contained in:
Nick O'Leary 2021-06-02 15:40:56 +01:00
commit 7c02e4d66a
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
9 changed files with 95 additions and 17 deletions

View File

@ -1,3 +1,35 @@
### 1.3.5 Maintenance Release
Editor
- Open subflow tab next to active tab rather than at the end
- Shrink default notification box
- Support mousewheel scroll in tab bar
- Revert some of #2967 to fix treeList gutter width calculation
- Prevent unknown node from breaking editor
- Stop module with missing types from preventing editor load
- Handle sidebar tab that no longer exists when setting first active
- Fix plugin loading when browser sends unrecognised lang
- Prevent error whilst drag/drop importing from leaving dropTarget visible Fixes #2982
- Fix scaling issues when dragging nodes into scaled workspace
- Fix incorrect shortcut keys in info tips (#2980) @kazuhitoyokoi
- Reduce code duplication around node/label generation
- Fix theme handling when no editorTheme.page setting
- Fix jshint error in treeList
Runtime
- Fix error handling in runtime/lib/api/nodes
- Add Node 16 with sass fixed
- Migrate from node-sass to sass (#2984)
- Fix "installRetry" was declared a constant and changed (#2974) @aheissenberger
Nodes
- Function: Fix 'SyntaxError' in Function node when last line of on-stop is a comment
- Function: Fix Function tab label names in the node help text Closes #2978
- Function: Update Japanese info text of function node (#2985) @HiroyasuNishiyama
### 1.3.4 Maintenance Release
Editor

View File

@ -26,6 +26,8 @@
}
],
"dependencies": {
"acorn": "8.3.0",
"acorn-walk": "8.1.0",
"ajv": "8.2.0",
"async-mutex": "0.3.1",
"basic-auth": "2.0.1",
@ -71,7 +73,7 @@
"semver": "7.3.5",
"tar": "6.1.0",
"uglify-js": "3.13.3",
"ws": "6.2.1",
"ws": "6.2.2",
"xml2js": "0.4.23"
},
"optionalDependencies": {

View File

@ -32,7 +32,7 @@
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"passport": "0.4.1",
"ws": "6.2.1"
"ws": "6.2.2"
},
"optionalDependencies": {
"bcrypt": "5.0.1"

View File

@ -66,12 +66,14 @@ RED.history = (function() {
var importedResult = RED.nodes.import(ev.config,{importMap: importMap})
inverseEv = {
t: 'replace',
config: importedResult.removedNodes
config: importedResult.removedNodes,
dirty: RED.nodes.dirty()
}
}
} else if (ev.t == 'add') {
inverseEv = {
t: "delete",
dirty: RED.nodes.dirty()
};
if (ev.nodes) {
inverseEv.nodes = [];
@ -158,7 +160,8 @@ RED.history = (function() {
} else if (ev.t == "delete") {
inverseEv = {
t: "add"
t: "add",
dirty: RED.nodes.dirty()
};
if (ev.workspaces) {
inverseEv.workspaces = [];
@ -300,11 +303,12 @@ RED.history = (function() {
} else if (ev.t == "move") {
inverseEv = {
t: 'move',
nodes: []
nodes: [],
dirty: RED.nodes.dirty()
};
for (i=0;i<ev.nodes.length;i++) {
var n = ev.nodes[i];
var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.moved};
var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.n.moved};
inverseEv.nodes.push(rn);
n.n.x = n.ox;
n.n.y = n.oy;
@ -336,7 +340,9 @@ RED.history = (function() {
} else if (ev.t == "edit") {
inverseEv = {
t: "edit",
changes: {}
changes: {},
changed: ev.node.changed,
dirty: RED.nodes.dirty()
};
inverseEv.node = ev.node;
for (i in ev.changes) {
@ -552,7 +558,8 @@ RED.history = (function() {
} else if (ev.t == "reorder") {
inverseEv = {
t: 'reorder',
order: RED.nodes.getWorkspaceOrder()
order: RED.nodes.getWorkspaceOrder(),
dirty: RED.nodes.dirty()
};
if (ev.order) {
RED.workspaces.order(ev.order);

View File

@ -19,6 +19,8 @@ module.exports = function(RED) {
var util = require("util");
var vm = require("vm");
var acorn = require("acorn");
var acornWalk = require("acorn-walk");
function sendResults(node,send,_msgid,msgs,cloneFirstMessage) {
if (msgs == null) {
@ -102,14 +104,7 @@ module.exports = function(RED) {
throw new Error(RED._("function.error.externalModuleNotAllowed"));
}
var handleNodeDoneCall = true;
// Check to see if the Function appears to call `node.done()`. If so,
// we will assume it is well written and does actually call node.done().
// Otherwise, we will call node.done() after the function returns regardless.
if (/node\.done\s*\(\s*\)/.test(node.func)) {
handleNodeDoneCall = false;
}
var functionText = "var results = null;"+
"results = (async function(msg,__send__,__done__){ "+
@ -130,6 +125,26 @@ module.exports = function(RED) {
"};\n"+
node.func+"\n"+
"})(msg,__send__,__done__);";
var handleNodeDoneCall = true;
// Check to see if the Function appears to call `node.done()`. If so,
// we will assume it is well written and does actually call node.done().
// Otherwise, we will call node.done() after the function returns regardless.
if (/node\.done\s*\(\s*\)/.test(functionText)) {
// We have spotted the code contains `node.done`. It could be in a comment
// so need to do the extra work to parse the AST and examine it properly.
acornWalk.simple(acorn.parse(functionText,{ecmaVersion: "latest"} ), {
CallExpression(astNode) {
if (astNode.callee && astNode.callee.object) {
if (astNode.callee.object.name === "node" && astNode.callee.property.name === "done") {
handleNodeDoneCall = false;
}
}
}
})
}
var finScript = null;
var finOpt = null;
node.topic = n.topic;

View File

@ -217,6 +217,10 @@ module.exports = function(RED) {
function applyRules(node, msg, property,state,done) {
if (!state) {
if (node.rules.length === 0) {
done(undefined, []);
return;
}
state = {
currentRule: 0,
elseflag: true,

View File

@ -15,6 +15,8 @@
}
],
"dependencies": {
"acorn": "8.3.0",
"acorn-walk": "8.1.0",
"ajv": "8.2.0",
"body-parser": "1.19.0",
"cheerio": "0.22.0",
@ -37,7 +39,7 @@
"on-headers": "1.0.2",
"raw-body": "2.4.1",
"request": "2.88.0",
"ws": "6.2.1",
"ws": "6.2.2",
"xml2js": "0.4.23",
"iconv-lite": "0.6.2"
}

View File

@ -110,7 +110,7 @@ function createNode(flow,config) {
switch(typeof config[nodeProp.name]) {
case "string": nodePropType = "str"; break;
case "number": nodePropType = "num"; break;
case "boolean": nodePropType = "bool"; nodePropValue = nodeProp?"true":"false"; break;
case "boolean": nodePropType = "bool"; nodePropValue == nodeProp?"true":"false"; break;
default:
nodePropType = config[nodeProp.name].type;
nodePropValue = config[nodeProp.name].value;

View File

@ -1134,4 +1134,20 @@ describe('switch Node', function() {
});
});
it('should handle empty rule', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[],checkall:true,outputs:0,wires:[]}];
helper.load(switchNode, flow, function() {
var n1 = helper.getNode("switchNode1");
setTimeout(function() {
var logEvents = helper.log().args.filter(function (evt) {
return evt[0].type == "switch";
});
if (logEvents.length === 0) {
done();
}
}, 150);
n1.receive({payload:1});
});
});
});