From c3df1c6cdea0a5de0e3408d03f47df3377122ea2 Mon Sep 17 00:00:00 2001 From: Paul Wieland Date: Thu, 23 Jan 2020 08:55:50 -0500 Subject: [PATCH 01/39] Add support for user definable properties to inject node --- .../nodes/core/common/20-inject.html | 179 ++++++++++++++---- .../@node-red/nodes/core/common/20-inject.js | 67 ++++--- 2 files changed, 181 insertions(+), 65 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/common/20-inject.html b/packages/node_modules/@node-red/nodes/core/common/20-inject.html index 77ced7d66..c45be4f86 100644 --- a/packages/node_modules/@node-red/nodes/core/common/20-inject.html +++ b/packages/node_modules/@node-red/nodes/core/common/20-inject.html @@ -15,15 +15,12 @@ --> diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index 5dfe45fee..d0a350e6a 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -25,6 +25,7 @@ module.exports = function(RED) { this.op1type = n.op1type || "str"; this.op2type = n.op2type || "str"; this.second = n.second || false; + this.property = n.property || "topic"; if (this.op1type === 'val') { if (this.op1 === 'true' || this.op1 === 'false') { @@ -112,7 +113,7 @@ module.exports = function(RED) { }); var processMessage = function(msg) { - var topic = msg.topic || "_none"; + var topic = RED.util.getMessageProperty(msg,node.property) || "_none"; var promise; if (node.bytopic === "all") { topic = "_none"; } node.topics[topic] = node.topics[topic] || {}; diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/function/89-trigger.html b/packages/node_modules/@node-red/nodes/locales/en-US/function/89-trigger.html index 836cabc6f..3caa0ab0a 100644 --- a/packages/node_modules/@node-red/nodes/locales/en-US/function/89-trigger.html +++ b/packages/node_modules/@node-red/nodes/locales/en-US/function/89-trigger.html @@ -14,7 +14,7 @@ limitations under the License. --> - diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json index 5eb83f9d1..5774d5dac 100755 --- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json @@ -302,7 +302,7 @@ "wait-for": "wait for", "wait-loop": "resend it every", "for": "Handling", - "bytopics": "each msg.topic independently", + "bytopics": "each", "alltopics": "all messages", "duration": { "ms": "Milliseconds", diff --git a/packages/node_modules/@node-red/nodes/locales/ja/messages.json b/packages/node_modules/@node-red/nodes/locales/ja/messages.json index adc033390..be98d50e3 100755 --- a/packages/node_modules/@node-red/nodes/locales/ja/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/ja/messages.json @@ -302,7 +302,7 @@ "wait-for": "指定した時間待機", "wait-loop": "指定した時間間隔毎に送信を繰り返す", "for": "処理対象", - "bytopics": "msg.topic毎", + "bytopics": "毎", "alltopics": "全メッセージ", "duration": { "ms": "ミリ秒", diff --git a/test/nodes/core/function/89-trigger_spec.js b/test/nodes/core/function/89-trigger_spec.js index ebf1c8db9..063fec47c 100644 --- a/test/nodes/core/function/89-trigger_spec.js +++ b/test/nodes/core/function/89-trigger_spec.js @@ -378,6 +378,51 @@ describe('trigger node', function() { }); }); + it('should handle multiple other properties individually if asked to do so', function(done) { + var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", property:"foo", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(triggerNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var c = 0; + n2.on("input", function(msg) { + try { + c += 1; + if (c === 1) { + msg.should.have.a.property("payload", 1); + msg.should.have.a.property("foo", "A"); + } + else if (c === 2) { + msg.should.have.a.property("payload", 1); + msg.should.have.a.property("foo", "B"); + } + else if (c === 3) { + msg.should.have.a.property("payload", 1); + msg.should.have.a.property("foo", "C"); + } + else if (c === 4) { + msg.should.have.a.property("payload", 0); + msg.should.have.a.property("foo", "A"); + } + else if (c === 5) { + msg.should.have.a.property("payload", 0); + msg.should.have.a.property("foo", "B"); + } + else if (c === 6) { + msg.should.have.a.property("payload", 0); + msg.should.have.a.property("foo", "C"); + done(); + } + } catch(err) { + done(err); + } + }); + n1.emit("input", {payload:1,foo:"A"}); + n1.emit("input", {payload:2,foo:"B"}); + n1.emit("input", {payload:3,foo:"C"}); + }); + }); + it('should be able to return things from flow and global context variables', function(done) { var spy = sinon.stub(RED.util, 'evaluateNodeProperty', function(arg1, arg2, arg3, arg4, arg5) { if (arg5) { arg5(null, arg1) } else { return arg1; } } From 87aacb4270f1db52952e6257e115cc359f8350f9 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 30 Jan 2020 22:20:55 +0000 Subject: [PATCH 07/39] change property name to leave space if we want to also do main payload property --- .../@node-red/nodes/core/function/89-trigger.html | 10 +++++----- .../@node-red/nodes/core/function/89-trigger.js | 4 ++-- test/nodes/core/function/89-trigger_spec.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.html b/packages/node_modules/@node-red/nodes/core/function/89-trigger.html index 5e250be28..187a87190 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.html +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.html @@ -66,8 +66,8 @@ - - + +
@@ -93,7 +93,7 @@ reset: {value:""}, bytopic: {value:"all"}, outputs: {value:1}, - property: {value:"topic",required:true} + topic: {value:"topic",required:true} }, inputs:1, outputs:1, @@ -121,9 +121,9 @@ $("#node-input-bytopic").on("change", function() { console.log("BYT",$("#node-input-bytopic").val()); if ($("#node-input-bytopic").val() === "all") { - $("#node-trigger-property").hide(); + $("#node-stream-topic").hide(); } else { - $("#node-trigger-property").show(); + $("#node-stream-topic").show(); } }); diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index d0a350e6a..dab7a83ab 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -25,7 +25,7 @@ module.exports = function(RED) { this.op1type = n.op1type || "str"; this.op2type = n.op2type || "str"; this.second = n.second || false; - this.property = n.property || "topic"; + this.topic = n.topic || "topic"; if (this.op1type === 'val') { if (this.op1 === 'true' || this.op1 === 'false') { @@ -113,7 +113,7 @@ module.exports = function(RED) { }); var processMessage = function(msg) { - var topic = RED.util.getMessageProperty(msg,node.property) || "_none"; + var topic = RED.util.getMessageProperty(msg,node.topic) || "_none"; var promise; if (node.bytopic === "all") { topic = "_none"; } node.topics[topic] = node.topics[topic] || {}; diff --git a/test/nodes/core/function/89-trigger_spec.js b/test/nodes/core/function/89-trigger_spec.js index 063fec47c..582b47904 100644 --- a/test/nodes/core/function/89-trigger_spec.js +++ b/test/nodes/core/function/89-trigger_spec.js @@ -379,7 +379,7 @@ describe('trigger node', function() { }); it('should handle multiple other properties individually if asked to do so', function(done) { - var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", property:"foo", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] }, + var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", topic:"foo", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] }, {id:"n2", type:"helper"} ]; helper.load(triggerNode, flow, function() { var n1 = helper.getNode("n1"); From 88e729664afa71b275c0f1ce38ede42adc81ef2b Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Fri, 31 Jan 2020 17:56:06 +0000 Subject: [PATCH 08/39] complete tidy up of trigger node remove unnecessary console.log --- .../@node-red/nodes/core/function/89-trigger.html | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.html b/packages/node_modules/@node-red/nodes/core/function/89-trigger.html index 187a87190..79b022519 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.html +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.html @@ -92,8 +92,8 @@ units: {value:"ms"}, reset: {value:""}, bytopic: {value:"all"}, - outputs: {value:1}, - topic: {value:"topic",required:true} + topic: {value:"topic",required:true}, + outputs: {value:1} }, inputs:1, outputs:1, @@ -114,12 +114,9 @@ }, oneditprepare: function() { var that = this; - if (this.property === undefined) { - $("#node-input-property").val("topic"); - } - $("#node-input-property").typedInput({default:'msg',types:['msg']}); + if (this.topic === undefined) { $("#node-input-topic").val("topic"); } + $("#node-input-topic").typedInput({default:'msg',types:['msg']}); $("#node-input-bytopic").on("change", function() { - console.log("BYT",$("#node-input-bytopic").val()); if ($("#node-input-bytopic").val() === "all") { $("#node-stream-topic").hide(); } else { From 127b3619795970cb52f9378adddba46125e63d71 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Fri, 14 Feb 2020 20:13:37 -0500 Subject: [PATCH 09/39] change PR to only use a single property for the 2nd output --- .../@node-red/nodes/core/function/89-trigger.html | 4 +++- .../node_modules/@node-red/nodes/core/function/89-trigger.js | 2 +- test/nodes/core/function/89-trigger_spec.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.html b/packages/node_modules/@node-red/nodes/core/function/89-trigger.html index 79b022519..8917f81d8 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.html +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.html @@ -88,7 +88,6 @@ op2type: {value:"val"}, duration: {value:"250",required:true,validate:RED.validators.number()}, extend: {value:"false"}, - second: {value:false}, units: {value:"ms"}, reset: {value:""}, bytopic: {value:"all"}, @@ -123,6 +122,9 @@ $("#node-stream-topic").show(); } }); + + if (this.outputs == 2) { $("#node-input-second").prop('checked', true) } + else { $("#node-input-second").prop('checked', false) } $("#node-input-second").change(function() { if ($("#node-input-second").is(":checked")) { diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index dab7a83ab..e3fca00aa 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -24,7 +24,7 @@ module.exports = function(RED) { this.op2 = n.op2 || "0"; this.op1type = n.op1type || "str"; this.op2type = n.op2type || "str"; - this.second = n.second || false; + this.second = (n.outputs == 2) ? true : false; this.topic = n.topic || "topic"; if (this.op1type === 'val') { diff --git a/test/nodes/core/function/89-trigger_spec.js b/test/nodes/core/function/89-trigger_spec.js index 582b47904..f13e23a5e 100644 --- a/test/nodes/core/function/89-trigger_spec.js +++ b/test/nodes/core/function/89-trigger_spec.js @@ -827,7 +827,7 @@ describe('trigger node', function() { }); it('should be able to send 2nd message to a 2nd output', function(done) { - var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"hello", op2:"world", duration:"50", second:true, wires:[["n2"],["n3"]] }, + var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"hello", op2:"world", duration:"50", outputs:2, wires:[["n2"],["n3"]] }, {id:"n2", type:"helper"}, {id:"n3", type:"helper"} ]; helper.load(triggerNode, flow, function() { var n1 = helper.getNode("n1"); From dea47a6e3db761bb2e2400e6d0e8a5ba9a0dd4e5 Mon Sep 17 00:00:00 2001 From: Thierry Le Gal Date: Tue, 3 Mar 2020 18:43:44 +0100 Subject: [PATCH 10/39] Improve performance in change node panel --- .../nodes/core/function/15-change.html | 118 +++++++++++++----- 1 file changed, 89 insertions(+), 29 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/15-change.html b/packages/node_modules/@node-red/nodes/core/function/15-change.html index fc9fa8d84..59d4337c5 100644 --- a/packages/node_modules/@node-red/nodes/core/function/15-change.html +++ b/packages/node_modules/@node-red/nodes/core/function/15-change.html @@ -1,5 +1,10 @@ diff --git a/test/nodes/core/parsers/70-CSV_spec.js b/test/nodes/core/parsers/70-CSV_spec.js index 3917d2d7c..9e7b45d8f 100644 --- a/test/nodes/core/parsers/70-CSV_spec.js +++ b/test/nodes/core/parsers/70-CSV_spec.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef */ /** * Copyright JS Foundation and other contributors, http://js.foundation * @@ -70,12 +71,13 @@ describe('CSV node', function() { it('should convert a simple csv string to a javascript object', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); n2.on("input", function(msg) { msg.should.have.property('payload', { a: 1, b: 2, c: 3, d: 4 }); + msg.should.have.property('columns', "a,b,c,d"); check_parts(msg, 0, 1); done(); }); @@ -86,7 +88,7 @@ describe('CSV node', function() { it('should remove quotes and whitespace from template', function(done) { var flow = [ { id:"n1", type:"csv", temp:'"a", "b" , " c "," d " ', wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -102,12 +104,13 @@ describe('CSV node', function() { it('should create column names if no template provided', function(done) { var flow = [ { id:"n1", type:"csv", temp:'', wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); n2.on("input", function(msg) { msg.should.have.property('payload', { col1: 1, col2: 2, col3: 3, col4: 4 }); + msg.should.have.property('columns', "col1,col2,col3,col4"); check_parts(msg, 0, 1); done(); }); @@ -118,12 +121,13 @@ describe('CSV node', function() { it('should allow dropping of fields from the template', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,,,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); n2.on("input", function(msg) { msg.should.have.property('payload', { a: 1, d: 4 }); + msg.should.have.property('columns', 'a,d'); check_parts(msg, 0, 1); done(); }); @@ -134,7 +138,7 @@ describe('CSV node', function() { it('should leave numbers starting with 0, e and + as strings (except 0.)', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -150,7 +154,7 @@ describe('CSV node', function() { it('should not parse numbers when told not to do so', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", strings:false, wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -166,7 +170,7 @@ describe('CSV node', function() { it('should leave handle strings with scientific notation as numbers', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -183,7 +187,7 @@ describe('CSV node', function() { it('should allow quotes in the input (but drop blank strings)', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g,h", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -234,7 +238,7 @@ describe('CSV node', function() { it('should recover from an odd number of quotes in the input', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -277,12 +281,13 @@ describe('CSV node', function() { it('should be able to output multiple lines as one array', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", multi:"yes", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); n2.on("input", function(msg) { msg.should.have.property('payload', [ { a: 1, b: 2, c: 3, d: 4 },{ a: 5, b: -6, c: '07', d: '+8' },{ a: 9, b: 0, c: 'a', d: 'b' },{ a: 'c', b: 'd', c: 'e', d: 'f' } ]); + msg.should.have.property('columns','a,b,c,d'); msg.should.not.have.property('parts'); done(); }); @@ -293,7 +298,7 @@ describe('CSV node', function() { it('should handle numbers in strings but not IP addresses', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -309,7 +314,7 @@ describe('CSV node', function() { it('should preserve parts property', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -353,7 +358,7 @@ describe('CSV node', function() { it('should skip several lines from start if requested', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", skip: 2, wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -367,9 +372,9 @@ describe('CSV node', function() { }); }); - it('should skip several lines from start then use next line as a tempate', function(done) { + it('should skip several lines from start then use next line as a template', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", hdrin:true, skip: 2, wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -385,7 +390,7 @@ describe('CSV node', function() { it('should skip several lines from start and correct parts', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", skip: 2, wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -417,11 +422,13 @@ describe('CSV node', function() { n2.on("input", function(msg) { if (c === 0) { msg.should.have.property('payload', { w: 1, x: 2, y: 3, z: 4 }); + msg.should.have.property('columns', 'w,x,y,z'); check_parts(msg, 0, 2); c += 1; } else { msg.should.have.property('payload', { w: 5, x: 6, y: 7, z: 8 }); + msg.should.have.property('columns', 'w,x,y,z'); check_parts(msg, 1, 2); done(); } @@ -445,7 +452,7 @@ describe('CSV node', function() { it('should convert a simple object back to a csv', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,,e", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -463,7 +470,7 @@ describe('CSV node', function() { it('should convert a simple object back to a csv with no template', function(done) { var flow = [ { id:"n1", type:"csv", temp:" ", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -481,7 +488,7 @@ describe('CSV node', function() { it('should handle a template with spaces in the property names', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b o,c p,,e", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -499,7 +506,7 @@ describe('CSV node', function() { it('should convert an array of objects to a multi-line csv', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -517,7 +524,7 @@ describe('CSV node', function() { it('should convert a simple array back to a csv', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -535,7 +542,7 @@ describe('CSV node', function() { it('should convert an array of arrays back to a multi-line csv', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -553,7 +560,7 @@ describe('CSV node', function() { it('should be able to include column names as first row', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", hdrout:true, ret:"\r\n", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -569,9 +576,36 @@ describe('CSV node', function() { }); }); + it('should be able to pass in column names', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"", hdrout:"once", ret:"\r\n", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var count = 0; + n2.on("input", function(msg) { + count += 1; + try { + if (count === 1) { + msg.should.have.property('payload', 'a,,b,a\r\n4,,3,4\r\n'); + } + if (count === 3) { + msg.should.have.property('payload', '4,,3,4\r\n'); + done() + } + } + catch(e) { done(e); } + }); + var testJson = [{ d: 1, b: 3, c: 2, a: 4 }]; + n1.emit("input", {payload:testJson, columns:"a,,b,a"}); + n1.emit("input", {payload:testJson}); + n1.emit("input", {payload:testJson}); + }); + }); + it('should handle quotes and sub-properties', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -591,7 +625,7 @@ describe('CSV node', function() { it('should just pass through if no payload provided', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); @@ -611,7 +645,7 @@ describe('CSV node', function() { it('should warn if provided a number or boolean', function(done) { var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, - {id:"n2", type:"helper"} ]; + {id:"n2", type:"helper"} ]; helper.load(csvNode, flow, function() { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); From 24eb78d1371bf1ada68ebaa3556376fb92250943 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Fri, 3 Apr 2020 16:55:43 +0100 Subject: [PATCH 13/39] add ja translations --- .../node_modules/@node-red/nodes/locales/ja/messages.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/node_modules/@node-red/nodes/locales/ja/messages.json b/packages/node_modules/@node-red/nodes/locales/ja/messages.json index e15947fa6..92f0b1677 100755 --- a/packages/node_modules/@node-red/nodes/locales/ja/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/ja/messages.json @@ -719,6 +719,11 @@ "mac": "Mac (\\r)", "windows": "Windows (\\r\\n)" }, + "hdrout": { + "none": "カラムヘッダを送信しない", + "all": "カラムヘッダを常に送信する", + "once": "ヘッダを一度だけ送信する(msg.resetの受け付けると再送)" + }, "errors": { "csv_js": "本ノードが処理できる形式は、CSV文字列またはJSONのみです", "obj_csv": "オブジェクトをCSVへ変換する際の列名が設定されていません" From 2f869a55e2fd1fc3d229dc38989307f916d08ad2 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 6 Apr 2020 15:39:48 +0100 Subject: [PATCH 14/39] Handle nodes with no wires array --- packages/node_modules/@node-red/editor-client/src/js/nodes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 61a5ae806..8beb9f9f4 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -1109,7 +1109,7 @@ RED.nodes = (function() { defaults: {}, label: "unknown: "+n.type, labelStyle: "red-ui-flow-node-label-italic", - outputs: n.outputs||n.wires.length, + outputs: n.outputs|| (n.wires && n.wires.length) || 0, set: registry.getNodeSet("node-red/unknown") } } else { From 572c03631da00f97409192e10510fec281289802 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 6 Apr 2020 15:40:06 +0100 Subject: [PATCH 15/39] Do not collapse whitespace in Debug string messages --- .../node_modules/@node-red/editor-client/src/sass/debug.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/node_modules/@node-red/editor-client/src/sass/debug.scss b/packages/node_modules/@node-red/editor-client/src/sass/debug.scss index c92c43320..1e77e46e1 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/debug.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/debug.scss @@ -217,6 +217,10 @@ .red-ui-debug-msg-type-number { color: $debug-message-text-color-msg-type-number; }; .red-ui-debug-msg-type-number-toggle { cursor: pointer;} +.red-ui-debug-msg-type-string { + white-space: pre-wrap; +} + .red-ui-debug-msg-row { display: block; padding: 4px 2px 2px; From 513957eea16456862d88cc85e783532c860f86cf Mon Sep 17 00:00:00 2001 From: martinLim45 Date: Tue, 7 Apr 2020 16:41:49 +0900 Subject: [PATCH 16/39] Set flow.disabled when disabled property is false --- .../node_modules/@node-red/runtime/lib/nodes/flows/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/index.js index 16166fbc1..1a350ce7c 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/index.js @@ -553,7 +553,7 @@ function getFlow(id) { if (flow.label) { result.label = flow.label; } - if (flow.disabled) { + if (flow.hasOwnProperty('disabled')) { result.disabled = flow.disabled; } if (flow.hasOwnProperty('info')) { From 97c771f93a0b4129c2f0f61e5c3480bc65c69686 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 8 Apr 2020 11:32:39 +0100 Subject: [PATCH 17/39] Ensure file context does not write 'undefined' to store Fixes #2522 --- .../@node-red/runtime/lib/nodes/context/localfilesystem.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js b/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js index cf1769700..9755681d8 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js @@ -203,10 +203,10 @@ LocalFileSystem.prototype.open = function(){ var newContext = self.cache._export(); scopes.forEach(function(scope) { var storagePath = getStoragePath(self.storageBaseDir,scope); - var context = newContext[scope]; + var context = newContext[scope] || {}; var stringifiedContext = stringify(context); if (stringifiedContext.circular && !self.knownCircularRefs[scope]) { - log.warn(log._("error-circular",{scope:scope})); + log.warn(log._("context.localfilesystem.error-circular",{scope:scope})); self.knownCircularRefs[scope] = true; } else { delete self.knownCircularRefs[scope]; @@ -324,7 +324,7 @@ LocalFileSystem.prototype.set = function(scope, key, value, callback) { } var stringifiedContext = stringify(obj); if (stringifiedContext.circular && !self.knownCircularRefs[scope]) { - log.warn(log._("error-circular",{scope:scope})); + log.warn(log._("context.localfilesystem.error-circular",{scope:scope})); self.knownCircularRefs[scope] = true; } else { delete self.knownCircularRefs[scope]; From c989f466ed99f36166080eaf870a1df63bb7b2ea Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 8 Apr 2020 12:38:49 +0100 Subject: [PATCH 18/39] Update changelog --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea3845c2..dbd14497a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +#### 1.0.5: Maintenance Release + +Runtime + + - #2500 Support for context stores using JSONata and evaluateNodeProperty() + - Add better handling of host-key-verify error with projects + - #2517 Handle false values in $env() properly + - #2514 Ensure complete node scope is remapped in subflows + - #2513 Flows/subflows must preinitialise their context objects + - Clear node.close timeout to avoid unnecessary work on restart + - #2532 Set flow.disabled when disabled property is false + - #2522 Ensure file context does not write 'undefined' to store + +Editor + + - #2489 Fix XPath in UI tests + - #2504 Fix paletteCategories order + - #2501 Add page objects for UI testing + - #2494 Check node props when deciding if pasted node can splice links + - #2521 Don't double-sanitize node name in debug sidebar + - #2519 German i18n updates + - #2523 Update nodeTabMap when replacing unknown nodes + - Update TypedInput to use flexbox and remove resizing code + - Handle nodes with no wires array + - Do not collapse whitespace in Debug string messages + +Nodes + + - File: Remove old legacy wording from file node info to stop confusing users. + - Join: Ensure join node handles missing buffer joiner when not in string mode + - Exec: make exec node logging consistent with itself. (only be verbose when in verbose mode) + - Trigger: reset default timeout value when switching away from wait for reset + - Join: Fix join to not crash on appending invalid types to buffer. + - MQTT out: Add warning if topic contains + or # + - #2502 WebSocket i18n update + - #2508 Add Japanese translation for join node + - TCP out: tidy up select of which rows to display + + #### 1.0.4: Maintenance Release Runtime From e26eb85718e55c91a688a5309287e47354ad901d Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 8 Apr 2020 17:06:11 +0100 Subject: [PATCH 19/39] Fine tune typedInput flexbox handling on option-button --- .../src/js/ui/common/typedInput.js | 4 +++- .../editor-client/src/sass/editor.scss | 2 +- .../src/sass/ui/common/typedInput.scss | 24 ++++++++----------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js index 88c842c2f..a6713951a 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js @@ -657,11 +657,13 @@ this.optionExpandButton.shown = false; } if (this.optionSelectTrigger) { - this.optionSelectTrigger.show(); + this.optionSelectTrigger.css({"display":"inline-flex"}); if (!opt.hasValue) { + this.optionSelectTrigger.css({"flex-grow":1}) this.elementDiv.hide(); this.valueLabelContainer.hide(); } else { + this.optionSelectTrigger.css({"flex-grow":0}) this.elementDiv.show(); this.valueLabelContainer.hide(); } diff --git a/packages/node_modules/@node-red/editor-client/src/sass/editor.scss b/packages/node_modules/@node-red/editor-client/src/sass/editor.scss index b13941f22..c95fecad6 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/editor.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/editor.scss @@ -633,7 +633,7 @@ button.red-ui-toggleButton.toggle { .red-ui-typedInput-value-label,.red-ui-typedInput-option-label { select,.placeholder-input { margin: 3px; - height: 26px; + height: 24px; width: calc(100% - 10px); padding-left: 3px; } diff --git a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss index 243c42e17..ffa424841 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss @@ -171,25 +171,21 @@ button.red-ui-typedInput-option-trigger { padding: 0 0 0 0; position:relative; flex-grow: 1; + line-height: 32px; + display: inline-flex; .red-ui-typedInput-option-label { background:$form-button-background; color: $form-text-color; - position:absolute; - left:0; - right:23px; - top: 0; - padding: 0 5px 0 8px; - i.red-ui-typedInput-icon { - margin-right: 4px; - } + flex-grow: 1; + padding: 0 0 0 8px; + display:inline-block; } .red-ui-typedInput-option-caret { - top: 0; - position: absolute; - right: 0; - bottom: 0; - width: 17px; - padding-left: 5px; + flex-grow: 0; + display:inline-block; + width: 23px; + text-align: center; + height: 100%; &:before { content:''; display: inline-block; From 7c1853431ac44725b97361a828bcf163fc566daf Mon Sep 17 00:00:00 2001 From: Paul Wieland Date: Wed, 8 Apr 2020 12:29:55 -0400 Subject: [PATCH 20/39] Update 20-inject.html Cleanup old payload, topic & type. Move name and remove tip. --- .../nodes/core/common/20-inject.html | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/common/20-inject.html b/packages/node_modules/@node-red/nodes/core/common/20-inject.html index 5b3c53076..bc99fb92f 100644 --- a/packages/node_modules/@node-red/nodes/core/common/20-inject.html +++ b/packages/node_modules/@node-red/nodes/core/common/20-inject.html @@ -15,6 +15,10 @@ --> diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json index e1cfe23bc..979238ac9 100755 --- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json @@ -52,7 +52,7 @@ "string": "string", "boolean": "boolean", "number": "number", - "Array": "Array", + "Array": "array", "invalid": "Invalid JSON Object" }, "timestamp": "timestamp", From 36b06984324f045d9043b7a88ee02c9f5e39fefd Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Mon, 4 May 2020 17:11:09 +0100 Subject: [PATCH 38/39] Trigger - redo second output code update --- .../@node-red/nodes/core/function/89-trigger.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index 091e51ebe..0f35d813a 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -191,17 +191,16 @@ module.exports = function(RED) { } promise.then(() => { if (node.op2type === "payl") { - node.send(npay[topic]); + if (node.second === true) { node.send([null,npay[topic]]); } + else { node.send(npay[topic]); } delete npay[topic]; } else { msg2.payload = node.topics[topic].m2; - node.send(msg2); + if (node.second === true) { node.send([null,msg2]); } + else { node.send(msg2); } } delete node.topics[topic]; - - if (node.second === true) { node.send([null,msg2]); } - else { node.send(msg2); } node.status({}); }).catch(err => { node.error(err); From 417d2cb40a22c91737bde5ce985e6477154f1356 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Mon, 4 May 2020 21:48:34 +0100 Subject: [PATCH 39/39] Add nodejs14 to Travis test matrix --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a101eecb0..5a8eebb8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ sudo: false language: node_js matrix: include: + - node_js: "14" - node_js: "12" - node_js: "10" script: