diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 43b0137c4..9a278b223 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,6 +27,9 @@ jobs: with: node-version: '12' - run: node ./node-red/.github/scripts/update-node-red-docker.js + with: + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true - name: Create Docker Pull Request uses: peter-evans/create-pull-request@v2 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3ab41b3..e9d7ba010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +### 1.2.5: Maintenance Release + +Editor + + - Fix import of config nodes with unknown z property + +Runtime + + - Set ACTIONS_ALLOW_UNSECURE_COMMANDS in GH Action + +### 1.2.4: Maintenance Release + +Editor + + - Support bigint types in Debug sidebar + - Clear retained status of deleted nodes + - Prevent needless retention of node status messages + - Update projects dialogs to use TypedInput-cred input + - Restore cursor position in TypedInput cred-mode + - Ensure config nodes with invalid z are imported somewhere + - Ensure user keyboard shortcuts override defaults Fixes #2753 + +Runtime + + - Disable projects when flowFile passed into grunt dev + - Add Russian Locale (#2761) (#2531) (@alexk111) + - Add Japanese translation for http-in node (#2758) (@kazuhitoyokoi) + +Nodes + + - CSV: Fix CSV node repeating array output + ### 1.2.3: Maintenance Release Editor diff --git a/Gruntfile.js b/Gruntfile.js index 49d2f154e..6272e9818 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -24,6 +24,7 @@ module.exports = function(grunt) { var flowFile = grunt.option('flowFile'); if (flowFile) { nodemonArgs.push(flowFile); + process.env.NODE_RED_ENABLE_PROJECTS=false; } var userDir = grunt.option('userDir'); if (userDir) { diff --git a/package.json b/package.json index 4f3c0bb00..15abf0507 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "media-typer": "1.1.0", "memorystore": "1.6.4", "mime": "2.4.6", - "moment-timezone": "^0.5.31", - "mqtt": "4.2.4", + "moment-timezone": "0.5.32", + "mqtt": "4.2.5", "multer": "1.4.2", "mustache": "4.0.1", "node-red-admin": "^0.2.6", @@ -73,7 +73,7 @@ "request": "2.88.0", "semver": "6.3.0", "tar": "6.0.5", - "uglify-js": "3.11.4", + "uglify-js": "3.11.6", "when": "3.7.8", "ws": "6.2.1", "xml2js": "0.4.23" @@ -104,7 +104,7 @@ "grunt-simple-nyc": "^3.0.1", "http-proxy": "1.18.1", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", - "marked": "1.2.2", + "marked": "1.2.4", "minami": "1.2.3", "mocha": "^5.2.0", "node-red-node-test-helper": "^0.2.5", diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/comms.js b/packages/node_modules/@node-red/editor-api/lib/editor/comms.js index 386b5f8a8..9c96bbf5b 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/comms.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/comms.js @@ -33,8 +33,6 @@ var activeConnections = []; var anonymousUser; -var retained = {}; - var heartbeatTimer; var lastSentTime; diff --git a/packages/node_modules/@node-red/editor-client/locales/ru/editor.json b/packages/node_modules/@node-red/editor-client/locales/ru/editor.json index e6522b27a..1f91d4b0b 100755 --- a/packages/node_modules/@node-red/editor-client/locales/ru/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ru/editor.json @@ -42,7 +42,8 @@ "loadNodeCatalogs": "Загрузка каталогов узлов", "loadNodes": "Загрузка узлов __count__", "loadFlows": "Загрузка потоков", - "importFlows": "Добавление потоков в рабочую область" + "importFlows": "Добавление потоков в рабочую область", + "importError": "
Ошибка добавления потоков
__message__
" }, "workspace": { "defaultName": "Поток __number__", @@ -214,6 +215,9 @@ "importUnrecognised": "Импортирован неопознанный тип:", "importUnrecognised_plural_2": "Импортированы неопознанные типы:", "importUnrecognised_plural_5": "Импортированы неопознанные типы:", + "importDuplicate": "Импортирован дубликат узла:", + "importDuplicate_plural_2": "Импортированы дубликаты узлов:", + "importDuplicate_plural_5": "Импортированы дубликаты узлов:", "nodesExported": "Узлы экспортированы в буфер обмена", "nodesImported": "Импортированы:", "nodeCopied": "__count__ узел скопирован", 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 0d620e70a..ddeea65e6 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 @@ -1359,6 +1359,10 @@ RED.nodes = (function() { } } } + } else { + if (n.z && !workspaces[n.z]) { + n.z = activeWorkspace; + } } if (!existingConfigNode || existingConfigNode._def.exclusive) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode.z !== n.z) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js index b7c25a14f..e46c88b4f 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js @@ -773,6 +773,9 @@ RED.clipboard = (function() { // representation or null return null; } + if (value.type === 'bigint') { + return value.data.toString(); + } if (value.type === 'undefined') { return undefined; } 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 037e8e454..fa1e68cca 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 @@ -173,6 +173,7 @@ valueLabel: function(container,value) { var that = this; container.css("pointer-events","none"); + container.css("flex-grow",0); this.elementDiv.hide(); var buttons = $('').text(RED._("projects.welcome.desc2")).appendTo(body); var row = $('
').appendTo(body); - var createAsEmpty = $('').appendTo(row); - var createAsClone = $('').appendTo(row); + var createAsEmpty = $('').appendTo(row); + var createAsClone = $('').appendTo(row); createAsEmpty.on("click", function(e) { e.preventDefault(); @@ -511,7 +511,8 @@ RED.projects = (function() { subrow = $('').appendTo(row); $('').appendTo(subrow); - projectRepoPasswordInput = $('').appendTo(subrow); + projectRepoPasswordInput = $('').appendTo(subrow); + projectRepoPasswordInput.typedInput({type:"cred"}); // ----------------------------------------------------- // Repo credentials - key/passphrase ------------------- @@ -539,12 +540,12 @@ RED.projects = (function() { subrow = $('').appendTo(row); $('').appendTo(subrow); projectRepoPassphrase = $('').appendTo(subrow); - + projectRepoPassphrase.typedInput({type:"cred"}); subrow = $('').appendTo(cloneAuthRows); var sshwarningRow = $('').hide().appendTo(subrow); $('
- Если шаблон пуст, то узел может использовать простой список свойств, разделенных запятыми, предоставленных в msg.columns
, чтобы определить, что извлечь. Если этого нет, то все свойства объекта выводятся в том порядке, в котором они были найдены.
+ Если шаблон пуст, то узел может использовать простой список свойств, разделенных запятыми, предоставленных в msg.columns
, чтобы определить, что извлечь. Если этого нет, то все свойства объекта выводятся в том порядке, в котором они были найдены в первой строке.
Если входные данные являются массивом, то шаблон столбцов используется только для необязательного генерирования строки с заголовками столбцов. diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index ad10ebc65..bf7f3a362 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -31,7 +31,7 @@ "is-utf8": "0.2.1", "js-yaml": "3.14.0", "media-typer": "1.1.0", - "mqtt": "4.2.4", + "mqtt": "4.2.5", "multer": "1.4.2", "mustache": "4.0.1", "on-headers": "1.0.2", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 691b55f3c..47472f38e 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -19,7 +19,7 @@ "@node-red/util": "1.3.0-beta.1", "semver": "6.3.0", "tar": "6.0.5", - "uglify-js": "3.11.4", + "uglify-js": "3.11.6", "when": "3.7.8" } } diff --git a/packages/node_modules/@node-red/runtime/lib/api/comms.js b/packages/node_modules/@node-red/runtime/lib/api/comms.js index 0652a651b..55789b806 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/comms.js +++ b/packages/node_modules/@node-red/runtime/lib/api/comms.js @@ -38,12 +38,20 @@ function handleCommsEvent(event) { publish(event.topic,event.data,event.retain); } function handleStatusEvent(event) { - var status = { - text: event.status.text, - fill: event.status.fill, - shape: event.status.shape - }; - publish("status/"+event.id,status,true); + if (!event.status) { + delete retained["status/"+event.id] + } else if (!event.status.text && !event.status.fill && !event.status.shape) { + if (retained["status/"+event.id]) { + publish("status/"+event.id,{},false); + } + } else { + var status = { + text: event.status.text, + fill: event.status.fill, + shape: event.status.shape + }; + publish("status/"+event.id,status,true); + } } function handleRuntimeEvent(event) { runtime.log.trace("runtime event: "+JSON.stringify(event)); diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js index 20a4f6c3d..a7e00bfbc 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js @@ -319,6 +319,11 @@ class Flow { node.error(err); } } + if (removedMap[stopList[i]]) { + events.emit("node-status",{ + id: node.id + }); + } } } return Promise.all(promises); diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js index 8b78cad17..78ec9ee75 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js @@ -18,6 +18,7 @@ const clone = require("clone"); const Flow = require('./Flow').Flow; const context = require('../nodes/context'); const util = require("util"); +const events = require("../events"); const redUtil = require("@node-red/util").util; const flowUtil = require("./util"); @@ -308,7 +309,26 @@ class Subflow extends Flow { super.start(diff); } + /** + * Stop this subflow. + * The `stopList` argument helps define what needs to be stopped in the case + * of a modified-nodes/flows type deploy. + * @param {[type]} stopList [description] + * @param {[type]} removedList [description] + * @return {[type]} [description] + */ + stop(stopList, removedList) { + const nodes = Object.keys(this.activeNodes); + return super.stop(stopList, removedList).then(res => { + nodes.forEach(id => { + events.emit("node-status",{ + id: id + }); + }) + return res; + }) + } /** * Get environment variable of subflow * @param {String} name name of env var diff --git a/packages/node_modules/@node-red/util/lib/util.js b/packages/node_modules/@node-red/util/lib/util.js index 261dc3867..07f506007 100644 --- a/packages/node_modules/@node-red/util/lib/util.js +++ b/packages/node_modules/@node-red/util/lib/util.js @@ -774,6 +774,12 @@ function encodeObject(msg,opts) { data: value.toString() } } + } else if (typeof value === 'bigint') { + value = { + __enc__: true, + type: 'bigint', + data: value.toString() + } } else if (value && value.constructor) { if (value.type === "Buffer") { value.__enc__ = true; @@ -808,6 +814,13 @@ function encodeObject(msg,opts) { } else if (msgType === "number") { msg.format = "number"; msg.msg = msg.msg.toString(); + } else if (msgType === "bigint") { + msg.format = "bigint"; + msg.msg = { + __enc__: true, + type: 'bigint', + data: msg.msg.toString() + }; } else if (msg.msg === null || msgType === "undefined") { msg.format = (msg.msg === null)?"null":"undefined"; msg.msg = "(undefined)"; diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index fc5d48849..9d447a280 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -20,7 +20,7 @@ "json-stringify-safe": "5.0.1", "jsonata": "1.8.4", "lodash.clonedeep": "^4.5.0", - "moment-timezone": "^0.5.31", + "moment-timezone": "0.5.32", "when": "3.7.8" } } diff --git a/test/unit/@node-red/runtime/lib/api/comms_spec.js b/test/unit/@node-red/runtime/lib/api/comms_spec.js index df423b7dd..e1359cb7d 100644 --- a/test/unit/@node-red/runtime/lib/api/comms_spec.js +++ b/test/unit/@node-red/runtime/lib/api/comms_spec.js @@ -211,6 +211,82 @@ describe("runtime-api/comms", function() { }); }).catch(done); }) + it('retains non-blank status message',function(done){ + eventHandlers['node-status']({ + id: "node1234", + status: {text:"hello"} + }) + messages.should.have.length(0); + comms.addConnection({client: clientConnection}).then(function() { + return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() { + messages.should.have.length(1); + messages[0].should.have.property("topic","status/node1234"); + messages[0].should.have.property("data",{text:"hello", fill: undefined, shape: undefined}); + done(); + }); + }).catch(done); + }) + it('does not retain blank status message',function(done){ + eventHandlers['node-status']({ + id: "node1234", + status: {} + }) + messages.should.have.length(0); + comms.addConnection({client: clientConnection}).then(function() { + return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() { + messages.should.have.length(0); + done(); + }); + }).catch(done); + }) + it('does not send blank status if first status',function(done){ + messages.should.have.length(0); + comms.addConnection({client: clientConnection}).then(function() { + return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() { + eventHandlers['node-status']({ + id: "node5678", + status: {} + }) + messages.should.have.length(0); + done() + }) + }).catch(done); + }); + it('sends blank status if replacing retained',function(done){ + eventHandlers['node-status']({ + id: "node5678", + status: {text:"hello"} + }) + messages.should.have.length(0); + comms.addConnection({client: clientConnection}).then(function() { + return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() { + messages.should.have.length(1); + eventHandlers['node-status']({ + id: "node5678", + status: {} + }) + messages.should.have.length(2); + done() + }) + }).catch(done); + }); + + it('does not retain initial status blank message',function(done){ + eventHandlers['node-status']({ + id: "my-event", + status: {} + }) + messages.should.have.length(0); + comms.addConnection({client: clientConnection}).then(function() { + return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() { + messages.should.have.length(1); + messages[0].should.have.property("topic","my-event"); + messages[0].should.have.property("data","my-payload"); + done(); + }); + }).catch(done); + }) + it('retained messages get cleared',function(done) { eventHandlers['comms']({ topic: "my-event",
'); @@ -352,7 +352,7 @@ RED.utils = (function() { $('