Compare commits

..

5 Commits

Author SHA1 Message Date
Dave Conway-Jones
d22979659b This add jsonata output to trigger node output options 2020-12-13 12:31:14 +00:00
Nick O'Leary
bbe3ee701f Merge pull request #2768 from natcl/librarySymlinks
Library: properly handle symlinked folders
2020-11-25 21:07:50 +00:00
Nathanaël Lécaudé
b1c0d6b452 Library: properly handle symlinked folders 2020-11-24 18:29:39 -05:00
Nick O'Leary
c6129b44a1 Merge branch 'master' into dev 2020-11-18 16:36:56 +00:00
Nick O'Leary
2a8290a4b7 Bump version to 1.3.0-beta.1 2020-11-13 18:23:35 +00:00
27 changed files with 95 additions and 233 deletions

View File

@@ -27,8 +27,9 @@ jobs:
with:
node-version: '12'
- run: node ./node-red/.github/scripts/update-node-red-docker.js
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
with:
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
- name: Create Docker Pull Request
uses: peter-evans/create-pull-request@v2
with:

View File

@@ -11,11 +11,5 @@ matrix:
before_script:
- npm install -g coveralls
- node_js: "12"
script:
- ./node_modules/.bin/grunt no-coverage
- node_js: "10"
script:
- ./node_modules/.bin/grunt no-coverage
- node_js: "8"
script:
- ./node_modules/.bin/grunt no-coverage

View File

@@ -1,45 +1,3 @@
### 1.2.7: Maintenance Release
Editor
- Ensure subflow-scoped config nodes do not get moved on import Fixes #2789
- Allow TypedInput to be disabled (#2752) @bartbutenaers
- Allow userMenu to be explicitly enabled (#2805) @tfmf
- Improvements to DE translation (#2192) @ketzu
Runtime
- Handle `undefined` error passed to node.error (#2781) @johnwang71
- Disable nyc coverage reporting on older node versions
- Improve Editor API unit test coverage (#2777) @aaronmyatt
Nodes
- Trigger: ensure timestamp option sends .now() at point of sending
### 1.2.6: Maintenance Release
Editor
- Update Japanese translations for 1.2.5 (#2764) @kazuhitoyokoi
- Library: properly handle symlinked folders (#2768) @natcl
Runtime
- Support Windows paths when installing tarball by path name Fixes #2769
- Fix unsecure command usage in GH Action
Nodes
- Update MQTT to latest to fix Node 8 URL breakage
### 1.2.5: Maintenance Release
Editor

View File

@@ -623,11 +623,6 @@ module.exports = function(grunt) {
'Builds editor content then runs code style checks and unit tests on all components',
['build','verifyPackageDependencies','jshint:editor','nyc:all']);
grunt.registerTask('no-coverage',
'Builds editor content then runs code style checks and unit tests on all components without code coverage',
['build','verifyPackageDependencies','jshint:editor','simplemocha:all']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',
['build','nyc:core']);

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -27,7 +27,7 @@
],
"dependencies": {
"ajv": "6.12.6",
"async-mutex": "0.2.6",
"async-mutex": "0.2.4",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
@@ -38,7 +38,7 @@
"cookie-parser": "1.4.5",
"cors": "2.8.5",
"cron": "1.7.2",
"denque": "1.5.0",
"denque": "1.4.1",
"express": "4.17.1",
"express-session": "1.17.1",
"fs-extra": "8.1.0",
@@ -54,11 +54,11 @@
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0",
"memorystore": "1.6.4",
"mime": "2.4.7",
"mime": "2.4.6",
"moment-timezone": "0.5.32",
"mqtt": "4.2.6",
"mqtt": "4.2.5",
"multer": "1.4.2",
"mustache": "4.1.0",
"mustache": "4.0.1",
"node-red-admin": "^0.2.6",
"node-red-node-rbe": "^0.2.9",
"node-red-node-sentiment": "^0.1.6",
@@ -73,7 +73,7 @@
"request": "2.88.0",
"semver": "6.3.0",
"tar": "6.0.5",
"uglify-js": "3.12.4",
"uglify-js": "3.11.6",
"when": "3.7.8",
"ws": "6.2.1",
"xml2js": "0.4.23"
@@ -82,7 +82,7 @@
"bcrypt": "3.0.8"
},
"devDependencies": {
"dompurify": "2.2.6",
"dompurify": "2.2.2",
"grunt": "1.3.0",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.3.2",
@@ -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.7",
"marked": "1.2.4",
"minami": "1.2.3",
"mocha": "^5.2.0",
"node-red-node-test-helper": "^0.2.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/util": "1.2.7",
"@node-red/editor-client": "1.2.7",
"@node-red/util": "1.3.0-beta.1",
"@node-red/editor-client": "1.3.0-beta.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",
@@ -25,9 +25,9 @@
"express-session": "1.17.1",
"express": "4.17.1",
"memorystore": "1.6.4",
"mime": "2.4.7",
"mime": "2.4.6",
"multer": "1.4.2",
"mustache": "4.1.0",
"mustache": "4.0.1",
"oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",

View File

@@ -32,7 +32,7 @@
"label" : {
"view" : {
"view" : "Ansicht",
"grid" : "Raster",
"grid" : "Gitter",
"showGrid" : "Raster anzeigen",
"snapGrid" : "Am Raster ausrichten",
"gridSize" : "Rastergröße",

View File

@@ -1089,7 +1089,6 @@
"en-US": "英語",
"ja": "日本語",
"ko": "韓国語",
"ru": "ロシア語",
"zh-CN": "中国語(簡体)",
"zh-TW": "中国語(繁体)"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1360,7 +1360,7 @@ RED.nodes = (function() {
}
}
} else {
if (n.z && !workspaces[n.z] && !subflow_map[n.z]) {
if (n.z && !workspaces[n.z]) {
n.z = activeWorkspace;
}
}

View File

@@ -965,18 +965,6 @@
},
hide: function() {
this.uiSelect.hide();
},
disable: function(val) {
if(val === true) {
this.uiSelect.attr("disabled", "disabled");
} else if (val === false) {
this.uiSelect.attr("disabled", null); //remove attr
} else {
this.uiSelect.attr("disabled", val); //user value
}
},
disabled: function() {
return this.uiSelect.attr("disabled");
}
});
})(jQuery);

View File

@@ -219,7 +219,7 @@ RED.user = (function() {
function init() {
if (RED.settings.user) {
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu") || RED.settings.editorTheme.userMenu) {
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) {
var userMenu = $('<li><a id="red-ui-header-button-user" class="button hide" href="#"></a></li>')
.prependTo(".red-ui-header-toolbar");

View File

@@ -26,14 +26,6 @@
box-sizing: border-box;
overflow:visible;
position: relative;
&[disabled] {
input, button {
background: $secondary-background-inactive;
pointer-events: none;
cursor: not-allowed;
}
}
.red-ui-typedInput-input-wrap {
flex-grow: 1;
}

View File

@@ -181,7 +181,7 @@
$("#node-input-op1").typedInput({
default: 'str',
typeField: $("#node-input-op1type"),
types:['flow','global','str','num','bool','json','bin','date','env',
types:['flow','global','str','num','bool','json','bin','date','jsonata','env',
optionPayload,
optionNothing
]
@@ -189,7 +189,7 @@
$("#node-input-op2").typedInput({
default: 'str',
typeField: $("#node-input-op2type"),
types:['flow','global','str','num','bool','json','bin','date','env',
types:['flow','global','str','num','bool','json','bin','date','jsonata','env',
optionOriginalPayload,
optionLatestPayload,
optionNothing

View File

@@ -75,6 +75,20 @@ module.exports = function(RED) {
//catch(e) { this.op1 = this.op1; }
//try { this.op2 = JSON.parse(this.op2); }
//catch(e) { this.op2 = this.op2; }
if (this.op1type === 'jsonata') {
try {
this.op1j = RED.util.prepareJSONataExpression(this.op1,this);
} catch(e) {
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
}
}
if (this.op2type === 'jsonata') {
try {
this.op2j = RED.util.prepareJSONataExpression(this.op2,this);
} catch(e) {
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
}
}
var node = this;
node.topics = {};
@@ -137,10 +151,10 @@ module.exports = function(RED) {
node.status(stat());
}
else {
if (node.op2type === "payl") { npay[topic] = RED.util.cloneMessage(msg); }
if (node.op2type !== "nul") { npay[topic] = RED.util.cloneMessage(msg); }
if (((!node.topics[topic].tout) && (node.topics[topic].tout !== 0)) || (node.loop === true)) {
promise = Promise.resolve();
if (node.op2type === "pay") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
if (node.op2type !== "nul") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
else if (node.op2Templated) { node.topics[topic].m2 = mustache.render(node.op2,msg); }
else if (node.op2type !== "nul") {
promise = new Promise((resolve,reject) => {
@@ -159,6 +173,18 @@ module.exports = function(RED) {
promise = Promise.resolve();
if (node.op1type === "pay") { }
else if (node.op1Templated) { msg.payload = mustache.render(node.op1,msg); }
else if (node.op1type === 'jsonata') {
promise = new Promise((resolve,reject) => {
RED.util.evaluateJSONataExpression(node.op1j,msg, (err, value) => {
if (err) {
reject(err);
} else {
msg.payload = value;
resolve();
}
});
});
}
else if (node.op1type !== "nul") {
promise = new Promise((resolve,reject) => {
RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg,(err,value) => {
@@ -179,10 +205,7 @@ module.exports = function(RED) {
/* istanbul ignore else */
if (node.op1type !== "nul") {
var msg2 = RED.util.cloneMessage(msg);
node.topics[topic].tout = setInterval(function() {
if (node.op1type === "date") { msg2.payload = Date.now(); }
node.send(RED.util.cloneMessage(msg2));
}, delayDuration);
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, delayDuration);
}
}
else {
@@ -191,10 +214,22 @@ module.exports = function(RED) {
var msg2 = null;
if (node.op2type !== "nul") {
var promise = Promise.resolve();
msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") {
msg2 = npay[topic];
if (node.op2type === "flow" || node.op2type === "global" || node.op2type === "env") {
promise = new Promise((resolve,reject) => {
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg2,(err,value) => {
if (err) {
reject(err);
} else {
node.topics[topic].m2 = value;
resolve();
}
});
});
}
else if (node.op2type === 'jsonata') {
promise = new Promise((resolve,reject) => {
RED.util.evaluateJSONataExpression(node.op2j,msg2,(err, value) => {
if (err) {
reject(err);
} else {
@@ -212,7 +247,6 @@ module.exports = function(RED) {
}
else {
msg2.payload = node.topics[topic].m2;
if (node.op2type === "date") { msg2.payload = Date.now(); }
if (node.second === true) { node.send([null,msg2]); }
else { node.send(msg2); }
}
@@ -244,7 +278,7 @@ module.exports = function(RED) {
var promise = Promise.resolve();
if (node.op2type !== "nul") {
if (node.op2type === "flow" || node.op2type === "global") {
if (node.op2type === "flow" || node.op2type === "global" || node.op2type === "env") {
promise = new Promise((resolve,reject) => {
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
if (err) {

View File

@@ -583,11 +583,11 @@
"regex" : "Reguläre Ausdrücke verwenden"
},
"action" : {
"set" : "Setze",
"set" : "Festlegen",
"change" : "Ändern",
"delete" : "Löschen",
"move" : "Bewegen",
"to" : "auf",
"to" : "bis",
"search" : "Suchen nach",
"replace" : "Ersetzen durch"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -23,7 +23,7 @@
"cookie": "0.4.1",
"cors": "2.8.5",
"cron": "1.7.2",
"denque": "1.5.0",
"denque": "1.4.1",
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
@@ -31,9 +31,9 @@
"is-utf8": "0.2.1",
"js-yaml": "3.14.0",
"media-typer": "1.1.0",
"mqtt": "4.2.6",
"mqtt": "4.2.5",
"multer": "1.4.2",
"mustache": "4.1.0",
"mustache": "4.0.1",
"on-headers": "1.0.2",
"raw-body": "2.4.1",
"request": "2.88.0",

View File

@@ -35,7 +35,7 @@ var settings;
const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/;
const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/;
const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//;
const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/;
const localtgzRe = /^\/.+tgz$/;
function init(runtime) {
events = runtime.events;

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,10 +16,10 @@
}
],
"dependencies": {
"@node-red/util": "1.2.7",
"@node-red/util": "1.3.0-beta.1",
"semver": "6.3.0",
"tar": "6.0.5",
"uglify-js": "3.12.4",
"uglify-js": "3.11.6",
"when": "3.7.8"
}
}

View File

@@ -470,8 +470,8 @@ class Flow {
}
// console.log("HE",logMessage);
var count = 1;
if (msg && msg.hasOwnProperty("error") && msg.error) {
if (msg.error.hasOwnProperty("source") && msg.error.source) {
if (msg && msg.hasOwnProperty("error") && msg.error !== null) {
if (msg.error.hasOwnProperty("source") && msg.error.source !== null) {
if (msg.error.source.id === node.id) {
count = msg.error.source.count+1;
if (count === 10) {

View File

@@ -117,8 +117,8 @@ class Subflow extends Flow {
this.node_map = node_map;
this.path = parent.path+"/"+(subflowInstance._alias||subflowInstance.id);
this.templateCredentials = credentials.get(subflowDef.id) || {};
this.instanceCredentials = credentials.get(this.id) || {};
this.templateCredentials = credentials.get(subflowDef.id);
this.instanceCredentials = credentials.get(this.id);
var env = [];
if (this.subflowDef.env) {

View File

@@ -169,7 +169,6 @@
"error-invalid-default-module": "デフォルトコンテキストストアが不明: '__storage__'",
"unknown-store": "不明なコンテキストストア '__name__' が指定されました。デフォルトストアを使用します。",
"localfilesystem": {
"invalid-json": "コンテキストファイル '__file__' のJSONが不正",
"error-circular": "コンテキスト __scope__ は永続化できない循環参照を含んでいます",
"error-write": "コンテキスト書込みエラー: __message__"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,9 +16,9 @@
}
],
"dependencies": {
"@node-red/registry": "1.2.7",
"@node-red/util": "1.2.7",
"async-mutex": "0.2.6",
"@node-red/registry": "1.3.0-beta.1",
"@node-red/util": "1.3.0-beta.1",
"async-mutex": "0.2.4",
"clone": "2.1.2",
"express": "4.17.1",
"fs-extra": "8.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/util",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "1.2.7",
"version": "1.3.0-beta.1",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -31,10 +31,10 @@
"flow"
],
"dependencies": {
"@node-red/editor-api": "1.2.7",
"@node-red/runtime": "1.2.7",
"@node-red/util": "1.2.7",
"@node-red/nodes": "1.2.7",
"@node-red/editor-api": "1.3.0-beta.1",
"@node-red/runtime": "1.3.0-beta.1",
"@node-red/util": "1.3.0-beta.1",
"@node-red/nodes": "1.3.0-beta.1",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"express": "4.17.1",

View File

@@ -143,19 +143,4 @@ describe("api/editor/theme", function () {
settings.projects.should.have.a.property("enabled", false);
});
it("test explicit userMenu set to true in theme setting", function () {
theme.init({
editorTheme: {
userMenu: true,
}
});
theme.app();
var settings = theme.settings();
settings.should.have.a.property("userMenu");
settings.userMenu.should.be.eql(true);
});
});

View File

@@ -18,9 +18,11 @@ var should = require("should");
var sinon = require("sinon");
var request = require("supertest");
var express = require("express");
var when = require("when");
var fs = require("fs");
var path = require("path");
var NR_TEST_UTILS = require("nr-test-utils");
const auth = require("basic-auth");
var api = NR_TEST_UTILS.require("@node-red/editor-api");
@@ -94,89 +96,4 @@ describe("api/index", function() {
request(api.httpAdmin).get("/auth/login").expect(200).end(done)
})
});
describe('initialises api with admin middleware', function(done) {
it('ignores non-function values',function(done) {
api.init({ httpAdminRoot: true, httpAdminMiddleware: undefined },{},{},{});
const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'testMiddleware')
should(middlewareFound).be.empty();
done();
});
it('only accepts functions as middleware',function(done) {
const testMiddleware = function(req, res, next){ next(); };
api.init({ httpAdminRoot: true, httpAdminMiddleware: testMiddleware },{},{},{});
const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'testMiddleware')
should(middlewareFound).be.length(1);
done();
});
});
describe('initialises api with authentication enabled', function(done) {
it('enables an oauth/openID based authentication mechanism',function(done) {
const stub = sinon.stub(apiAuth, 'genericStrategy', function(){});
const adminAuth = { type: 'strategy', strategy: {} }
api.init({ httpAdminRoot: true, adminAuth },{},{},{});
should(stub.called).be.ok();
stub.restore();
done();
});
it('enables password protection',function(done) {
const adminAuth = { type: 'credentials' }
api.init({ httpAdminRoot: true, adminAuth },{},{},{});
// is the name ("initialize") of the passport middleware present
const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'initialize')
should(middlewareFound).be.length(1);
done();
});
});
describe('initialises api with custom cors config', function (done) {
const httpAdminCors = {
origin: "*",
methods: "GET,PUT,POST,DELETE"
};
it('uses default cors middleware when user settings absent', function(done){
api.init({ httpAdminRoot: true }, {}, {}, {});
const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'corsMiddleware')
should(middlewareFound).be.length(1);
done();
})
it('enables custom cors middleware when settings present', function(done){
api.init({ httpAdminRoot: true, httpAdminCors }, {}, {}, {});
const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'corsMiddleware')
should(middlewareFound).be.length(2);
done();
})
});
describe('editor start', function (done) {
it('cannot be started when editor is disabled', function (done) {
const stub = sinon.stub(apiEditor, 'start', function () {
return Promise.resolve(true);
});
api.init({ httpAdminRoot: true, disableEditor: true }, {}, {}, {});
should(api.start()).resolvedWith(true);
stub.restore();
done();
});
it('can be started when editor enabled', function (done) {
const stub = sinon.stub(apiEditor, 'start');
api.init({ httpAdminRoot: true, disableEditor: false }, {}, {}, {});
api.start();
should(stub.called).be.true();
stub.restore();
done();
});
});
});