mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
1 Commits
4.0.1
...
optionally
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c264419dd9 |
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,23 +1,3 @@
|
|||||||
#### 4.0.1: Maintenance Release
|
|
||||||
|
|
||||||
Editor
|
|
||||||
|
|
||||||
- Ensure subflow instance credential property values are extracted (#4802) @knolleary
|
|
||||||
- Use `_ADD_` value for both `add new...` and `none` options (#4800) @GogoVega
|
|
||||||
- Fix the config node select value assignment (#4788) @GogoVega
|
|
||||||
- Add tooltip for number of subflow instance on info tab (#4786) @kazuhitoyokoi
|
|
||||||
- Add Japanese translations for v4.0.0 (#4785) @kazuhitoyokoi
|
|
||||||
|
|
||||||
Runtime
|
|
||||||
|
|
||||||
- Ensure group nodes are properly exported in /flow api (#4803) @knolleary
|
|
||||||
|
|
||||||
Nodes
|
|
||||||
|
|
||||||
- Joins: make using msg.parts optional in join node (#4796) @dceejay
|
|
||||||
- HTTP Request: UI proxy should setup agents for both http_proxy and https_proxy (#4794) @Steve-Mcl
|
|
||||||
- HTTP Request: Remove default user agent (#4791) @Steve-Mcl
|
|
||||||
|
|
||||||
#### 4.0.0: Milestone Release
|
#### 4.0.0: Milestone Release
|
||||||
|
|
||||||
This marks the next major release of Node-RED. The following changes represent
|
This marks the next major release of Node-RED. The following changes represent
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red",
|
"name": "node-red",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"description": "Low-code programming for event-driven applications",
|
"description": "Low-code programming for event-driven applications",
|
||||||
"homepage": "https://nodered.org",
|
"homepage": "https://nodered.org",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/editor-api",
|
"name": "@node-red/editor-api",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/util": "4.0.1",
|
"@node-red/util": "4.0.0",
|
||||||
"@node-red/editor-client": "4.0.1",
|
"@node-red/editor-client": "4.0.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"body-parser": "1.20.2",
|
"body-parser": "1.20.2",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
|
|||||||
@@ -27,8 +27,7 @@
|
|||||||
"lock": "固定",
|
"lock": "固定",
|
||||||
"unlock": "固定を解除",
|
"unlock": "固定を解除",
|
||||||
"locked": "固定済み",
|
"locked": "固定済み",
|
||||||
"unlocked": "固定なし",
|
"unlocked": "固定なし"
|
||||||
"format": "形式"
|
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"string": "文字列",
|
"string": "文字列",
|
||||||
@@ -282,8 +281,8 @@
|
|||||||
"selected": "選択したフロー",
|
"selected": "選択したフロー",
|
||||||
"current": "現在のタブ",
|
"current": "現在のタブ",
|
||||||
"all": "全てのタブ",
|
"all": "全てのタブ",
|
||||||
"compact": "インデントなし",
|
"compact": "インデントのないJSONフォーマット",
|
||||||
"formatted": "インデント付き",
|
"formatted": "インデント付きのJSONフォーマット",
|
||||||
"copy": "書き出し",
|
"copy": "書き出し",
|
||||||
"export": "ライブラリに書き出し",
|
"export": "ライブラリに書き出し",
|
||||||
"exportAs": "書き出し先",
|
"exportAs": "書き出し先",
|
||||||
@@ -924,8 +923,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typedInput": {
|
"typedInput": {
|
||||||
"selected": "__count__個を選択",
|
|
||||||
"selected_plural": "__count__個を選択",
|
|
||||||
"type": {
|
"type": {
|
||||||
"str": "文字列",
|
"str": "文字列",
|
||||||
"num": "数値",
|
"num": "数値",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/editor-client",
|
"name": "@node-red/editor-client",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -413,8 +413,11 @@ RED.editor = (function() {
|
|||||||
if (selectedOpt?.data('env')) {
|
if (selectedOpt?.data('env')) {
|
||||||
disableButton(addButton, true);
|
disableButton(addButton, true);
|
||||||
disableButton(editButton, true);
|
disableButton(editButton, true);
|
||||||
// disable the edit button if no options available or 'none' selected
|
// disable the edit button if no options available
|
||||||
} else if (optionsLength === 1 || selectedOpt.val() === "_ADD_") {
|
} else if (optionsLength === 1 && selectedOpt.val() === "_ADD_") {
|
||||||
|
disableButton(addButton, false);
|
||||||
|
disableButton(editButton, true);
|
||||||
|
} else if (selectedOpt.val() === "") {
|
||||||
disableButton(addButton, false);
|
disableButton(addButton, false);
|
||||||
disableButton(editButton, true);
|
disableButton(editButton, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -423,9 +426,14 @@ RED.editor = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the value is "", 'add new...' option if no config node available or 'none' option
|
var label = "";
|
||||||
// Otherwise, it's a config node
|
var configNode = RED.nodes.node(nodeValue);
|
||||||
select.val(nodeValue || '_ADD_');
|
|
||||||
|
if (configNode) {
|
||||||
|
label = RED.utils.getNodeLabel(configNode, configNode.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.val(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -926,11 +934,9 @@ RED.editor = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!configNodes.length) {
|
if (!configNodes.length) {
|
||||||
// Add 'add new...' option
|
|
||||||
select.append('<option value="_ADD_" selected>' + RED._("editor.addNewType", { type: label }) + '</option>');
|
select.append('<option value="_ADD_" selected>' + RED._("editor.addNewType", { type: label }) + '</option>');
|
||||||
} else {
|
} else {
|
||||||
// Add 'none' option
|
select.append('<option value="">' + RED._("editor.inputs.none") + '</option>');
|
||||||
select.append('<option value="_ADD_">' + RED._("editor.inputs.none") + '</option>');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.setTimeout(function() { select.trigger("change");},50);
|
window.setTimeout(function() { select.trigger("change");},50);
|
||||||
|
|||||||
@@ -1100,7 +1100,7 @@ RED.subflow = (function() {
|
|||||||
input.val(val.value);
|
input.val(val.value);
|
||||||
break;
|
break;
|
||||||
case "cred":
|
case "cred":
|
||||||
input = $('<input type="password">').css('width','70%').attr('id', elId).appendTo(row);
|
input = $('<input type="password">').css('width','70%').appendTo(row);
|
||||||
if (node.credentials) {
|
if (node.credentials) {
|
||||||
if (node.credentials[tenv.name]) {
|
if (node.credentials[tenv.name]) {
|
||||||
input.val(node.credentials[tenv.name]);
|
input.val(node.credentials[tenv.name]);
|
||||||
@@ -1346,7 +1346,7 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cred":
|
case "cred":
|
||||||
item.value = input.typedInput('value');
|
item.value = input.val();
|
||||||
item.type = 'cred';
|
item.type = 'cred';
|
||||||
break;
|
break;
|
||||||
case "spinner":
|
case "spinner":
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ RED.sidebar.info.outliner = (function() {
|
|||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
RED.search.show("type:subflow:"+n.id);
|
RED.search.show("type:subflow:"+n.id);
|
||||||
})
|
})
|
||||||
RED.popover.tooltip(subflowInstanceBadge,function() { return RED._('subflow.subflowInstances',{count:n.instances.length})});
|
// RED.popover.tooltip(userCountBadge,function() { return RED._('editor.nodesUse',{count:n.users.length})});
|
||||||
}
|
}
|
||||||
if (n._def.category === "config" && n.type !== "group") {
|
if (n._def.category === "config" && n.type !== "group") {
|
||||||
var userCountBadge = $('<button type="button" class="red-ui-info-outline-item-control-users red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').text(n.users.length).appendTo(controls).on("click",function(evt) {
|
var userCountBadge = $('<button type="button" class="red-ui-info-outline-item-control-users red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').text(n.users.length).appendTo(controls).on("click",function(evt) {
|
||||||
|
|||||||
@@ -108,13 +108,12 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|||||||
if (n.proxy && proxyConfig) {
|
if (n.proxy && proxyConfig) {
|
||||||
proxyOptions.env = {
|
proxyOptions.env = {
|
||||||
no_proxy: (proxyConfig.noproxy || []).join(','),
|
no_proxy: (proxyConfig.noproxy || []).join(','),
|
||||||
http_proxy: (proxyConfig.url),
|
http_proxy: (proxyConfig.url)
|
||||||
https_proxy: (proxyConfig.url)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getProxyForUrl(url, proxyOptions)
|
return getProxyForUrl(url, proxyOptions)
|
||||||
}
|
}
|
||||||
let prox = nodeUrl ? getProxy(nodeUrl) : null
|
let prox = getProxy(nodeUrl || '')
|
||||||
|
|
||||||
let timingLog = false;
|
let timingLog = false;
|
||||||
if (RED.settings.hasOwnProperty("httpRequestTimingLog")) {
|
if (RED.settings.hasOwnProperty("httpRequestTimingLog")) {
|
||||||
@@ -535,7 +534,9 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|||||||
opts.headers[clSet] = opts.headers['content-length'];
|
opts.headers[clSet] = opts.headers['content-length'];
|
||||||
delete opts.headers['content-length'];
|
delete opts.headers['content-length'];
|
||||||
}
|
}
|
||||||
|
if (!opts.headers.hasOwnProperty('user-agent')) {
|
||||||
|
opts.headers['user-agent'] = 'Mozilla/5.0 (Node-RED)';
|
||||||
|
}
|
||||||
if (proxyUrl) {
|
if (proxyUrl) {
|
||||||
const match = proxyUrl.match(/^(https?:\/\/)?(.+)?:([0-9]+)?/i);
|
const match = proxyUrl.match(/^(https?:\/\/)?(.+)?:([0-9]+)?/i);
|
||||||
if (match) {
|
if (match) {
|
||||||
@@ -565,7 +566,7 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
|||||||
//need both incase of http -> https redirect
|
//need both incase of http -> https redirect
|
||||||
opts.agent = {
|
opts.agent = {
|
||||||
http: new HttpProxyAgent(proxyOptions),
|
http: new HttpProxyAgent(proxyOptions),
|
||||||
https: new HttpsProxyAgent(proxyOptions)
|
https: new HttpProxyAgent(proxyOptions)
|
||||||
};
|
};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,6 +24,10 @@
|
|||||||
<label for="node-input-property"><i class="fa fa-forward"></i> <span data-i18n="split.split"></span></label>
|
<label for="node-input-property"><i class="fa fa-forward"></i> <span data-i18n="split.split"></span></label>
|
||||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<input type="checkbox" id="node-input-addcomplete" style="margin-left:10px; vertical-align:baseline; width:auto;">
|
||||||
|
<label for="node-input-addcomplete" style="width:auto;" data-i18n="split.addcomplete"></label>
|
||||||
|
</div>
|
||||||
<div class="form-row"><span data-i18n="[html]split.strBuff"></span></div>
|
<div class="form-row"><span data-i18n="[html]split.strBuff"></span></div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-splt" style="padding-left:10px; margin-right:-10px;" data-i18n="split.splitUsing"></label>
|
<label for="node-input-splt" style="padding-left:10px; margin-right:-10px;" data-i18n="split.splitUsing"></label>
|
||||||
@@ -61,6 +65,7 @@
|
|||||||
arraySpltType: {value:"len"},
|
arraySpltType: {value:"len"},
|
||||||
stream: {value:false},
|
stream: {value:false},
|
||||||
addname: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })},
|
addname: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })},
|
||||||
|
addcomplete: {value:false},
|
||||||
property: {value:"payload",required:true}
|
property: {value:"payload",required:true}
|
||||||
},
|
},
|
||||||
inputs:1,
|
inputs:1,
|
||||||
@@ -122,10 +127,6 @@
|
|||||||
|
|
||||||
|
|
||||||
<script type="text/html" data-template-name="join">
|
<script type="text/html" data-template-name="join">
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
|
||||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label data-i18n="join.mode.mode"></label>
|
<label data-i18n="join.mode.mode"></label>
|
||||||
<select id="node-input-mode" style="width:200px;">
|
<select id="node-input-mode" style="width:200px;">
|
||||||
@@ -161,12 +162,6 @@
|
|||||||
<input type="text" id="node-input-joiner" style="width:70%">
|
<input type="text" id="node-input-joiner" style="width:70%">
|
||||||
<input type="hidden" id="node-input-joinerType">
|
<input type="hidden" id="node-input-joinerType">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<input type="checkbox" id="node-input-useparts" style="margin-left:8px; margin-right:8px; vertical-align:baseline; width:auto;">
|
|
||||||
<label for="node-input-useparts" style="width:auto;" data-i18n="join.useparts"></label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row node-row-trigger" id="trigger-row">
|
<div class="form-row node-row-trigger" id="trigger-row">
|
||||||
<label style="width:auto;" data-i18n="join.send"></label>
|
<label style="width:auto;" data-i18n="join.send"></label>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -205,6 +200,10 @@
|
|||||||
<label for="node-input-reduceRight" style="width:70%;" data-i18n="join.reduce.right" style="margin-left:10px;"/>
|
<label for="node-input-reduceRight" style="width:70%;" data-i18n="join.reduce.right" style="margin-left:10px;"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||||
|
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||||
|
</div>
|
||||||
<div class="form-tips form-tips-auto hide" data-i18n="[html]join.tip"></div>
|
<div class="form-tips form-tips-auto hide" data-i18n="[html]join.tip"></div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -240,7 +239,6 @@
|
|||||||
},
|
},
|
||||||
joiner: { value:"\\n"},
|
joiner: { value:"\\n"},
|
||||||
joinerType: { value:"str"},
|
joinerType: { value:"str"},
|
||||||
useparts: { value:false },
|
|
||||||
accumulate: { value:"false" },
|
accumulate: { value:"false" },
|
||||||
timeout: {value:""},
|
timeout: {value:""},
|
||||||
count: {value:""},
|
count: {value:""},
|
||||||
@@ -266,12 +264,6 @@
|
|||||||
},
|
},
|
||||||
oneditprepare: function() {
|
oneditprepare: function() {
|
||||||
var node = this;
|
var node = this;
|
||||||
$("#node-input-useparts").on("change", function(e) {
|
|
||||||
if (node.useparts === undefined) {
|
|
||||||
node.useparts = true;
|
|
||||||
$("#node-input-useparts").attr('checked', true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#node-input-mode").on("change", function(e) {
|
$("#node-input-mode").on("change", function(e) {
|
||||||
var val = $(this).val();
|
var val = $(this).val();
|
||||||
|
|||||||
@@ -21,13 +21,17 @@ module.exports = function(RED) {
|
|||||||
for (var i = 0; i < array.length-1; i++) {
|
for (var i = 0; i < array.length-1; i++) {
|
||||||
RED.util.setMessageProperty(msg,node.property,array[i]);
|
RED.util.setMessageProperty(msg,node.property,array[i]);
|
||||||
msg.parts.index = node.c++;
|
msg.parts.index = node.c++;
|
||||||
if (node.stream !== true) { msg.parts.count = array.length; }
|
if (node.stream !== true) {
|
||||||
|
msg.parts.count = array.length;
|
||||||
|
if (node.addcomplete === true) { msg.complete = true; }
|
||||||
|
}
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
}
|
}
|
||||||
if (node.stream !== true) {
|
if (node.stream !== true) {
|
||||||
RED.util.setMessageProperty(msg,node.property,array[i]);
|
RED.util.setMessageProperty(msg,node.property,array[i]);
|
||||||
msg.parts.index = node.c++;
|
msg.parts.index = node.c++;
|
||||||
msg.parts.count = array.length;
|
msg.parts.count = array.length;
|
||||||
|
if (node.addcomplete === true) { msg.complete = true; }
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
node.c = 0;
|
node.c = 0;
|
||||||
}
|
}
|
||||||
@@ -40,6 +44,7 @@ module.exports = function(RED) {
|
|||||||
node.stream = n.stream;
|
node.stream = n.stream;
|
||||||
node.spltType = n.spltType || "str";
|
node.spltType = n.spltType || "str";
|
||||||
node.addname = n.addname || "";
|
node.addname = n.addname || "";
|
||||||
|
node.addcomplete = n.addcomplete || false;
|
||||||
node.property = n.property||"payload";
|
node.property = n.property||"payload";
|
||||||
try {
|
try {
|
||||||
if (node.spltType === "str") {
|
if (node.spltType === "str") {
|
||||||
@@ -111,6 +116,7 @@ module.exports = function(RED) {
|
|||||||
if ((node.stream !== true) || (node.remainder.length === node.splt)) {
|
if ((node.stream !== true) || (node.remainder.length === node.splt)) {
|
||||||
RED.util.setMessageProperty(msg,node.property,node.remainder);
|
RED.util.setMessageProperty(msg,node.property,node.remainder);
|
||||||
msg.parts.index = node.c++;
|
msg.parts.index = node.c++;
|
||||||
|
if (node.addcomplete === true) { msg.complete = true; }
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
node.pendingDones.forEach(d => d());
|
node.pendingDones.forEach(d => d());
|
||||||
node.pendingDones = [];
|
node.pendingDones = [];
|
||||||
@@ -153,6 +159,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
RED.util.setMessageProperty(msg,node.property,m);
|
RED.util.setMessageProperty(msg,node.property,m);
|
||||||
msg.parts.index = i;
|
msg.parts.index = i;
|
||||||
|
if (i === count-1 && node.addcomplete === true) { msg.complete = true; }
|
||||||
pos += node.arraySplt;
|
pos += node.arraySplt;
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
}
|
}
|
||||||
@@ -172,6 +179,7 @@ module.exports = function(RED) {
|
|||||||
msg.parts.key = p;
|
msg.parts.key = p;
|
||||||
msg.parts.index = j;
|
msg.parts.index = j;
|
||||||
msg.parts.count = l;
|
msg.parts.count = l;
|
||||||
|
if (j == l-1 && node.addcomplete === true) { msg.complete = true; }
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
@@ -207,6 +215,7 @@ module.exports = function(RED) {
|
|||||||
if ((node.stream !== true) || (node.buffer.length === node.splt)) {
|
if ((node.stream !== true) || (node.buffer.length === node.splt)) {
|
||||||
RED.util.setMessageProperty(msg,node.property,node.buffer);
|
RED.util.setMessageProperty(msg,node.property,node.buffer);
|
||||||
msg.parts.index = node.c++;
|
msg.parts.index = node.c++;
|
||||||
|
if (node.addcomplete === true) { msg.complete = true; }
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
node.pendingDones.forEach(d => d());
|
node.pendingDones.forEach(d => d());
|
||||||
node.pendingDones = [];
|
node.pendingDones = [];
|
||||||
@@ -253,6 +262,7 @@ module.exports = function(RED) {
|
|||||||
RED.util.setMessageProperty(msg,node.property,buff.slice(p,buff.length));
|
RED.util.setMessageProperty(msg,node.property,buff.slice(p,buff.length));
|
||||||
msg.parts.index = node.c++;
|
msg.parts.index = node.c++;
|
||||||
msg.parts.count = node.c++;
|
msg.parts.count = node.c++;
|
||||||
|
if (node.addcomplete === true) { msg.complete = true; }
|
||||||
send(RED.util.cloneMessage(msg));
|
send(RED.util.cloneMessage(msg));
|
||||||
node.pendingDones.forEach(d => d());
|
node.pendingDones.forEach(d => d());
|
||||||
node.pendingDones = [];
|
node.pendingDones = [];
|
||||||
@@ -444,8 +454,6 @@ module.exports = function(RED) {
|
|||||||
this.count = Number(n.count || 0);
|
this.count = Number(n.count || 0);
|
||||||
this.joiner = n.joiner||"";
|
this.joiner = n.joiner||"";
|
||||||
this.joinerType = n.joinerType||"str";
|
this.joinerType = n.joinerType||"str";
|
||||||
if (n.useparts === undefined) { this.useparts = true; }
|
|
||||||
else { this.useparts = n.useparts || false; }
|
|
||||||
|
|
||||||
this.reduce = (this.mode === "reduce");
|
this.reduce = (this.mode === "reduce");
|
||||||
if (this.reduce) {
|
if (this.reduce) {
|
||||||
@@ -613,7 +621,7 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.mode === 'custom' && msg.hasOwnProperty('parts') && node.useparts === false ) {
|
if (node.mode === 'custom' && msg.hasOwnProperty('parts')) {
|
||||||
if (msg.parts.hasOwnProperty('parts')) {
|
if (msg.parts.hasOwnProperty('parts')) {
|
||||||
msg.parts = { parts: msg.parts.parts };
|
msg.parts = { parts: msg.parts.parts };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1020,7 +1020,8 @@
|
|||||||
"splitUsing": "Split using",
|
"splitUsing": "Split using",
|
||||||
"splitLength": "Fixed length of",
|
"splitLength": "Fixed length of",
|
||||||
"stream": "Handle as a stream of messages",
|
"stream": "Handle as a stream of messages",
|
||||||
"addname": " Copy key to "
|
"addname": " Copy key to ",
|
||||||
|
"addcomplete": " Add msg.complete to last element of split."
|
||||||
},
|
},
|
||||||
"join": {
|
"join": {
|
||||||
"join": "join",
|
"join": "join",
|
||||||
@@ -1046,7 +1047,6 @@
|
|||||||
"joinedUsing": "joined using",
|
"joinedUsing": "joined using",
|
||||||
"send": "Send the message:",
|
"send": "Send the message:",
|
||||||
"afterCount": "After a number of message parts",
|
"afterCount": "After a number of message parts",
|
||||||
"useparts": "Use existing msg.parts property",
|
|
||||||
"count": "count",
|
"count": "count",
|
||||||
"subsequent": "and every subsequent message.",
|
"subsequent": "and every subsequent message.",
|
||||||
"afterTimeout": "After a timeout following the first message",
|
"afterTimeout": "After a timeout following the first message",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/nodes",
|
"name": "@node-red/nodes",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/registry",
|
"name": "@node-red/registry",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/util": "4.0.1",
|
"@node-red/util": "4.0.0",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
"semver": "7.5.4",
|
"semver": "7.5.4",
|
||||||
|
|||||||
@@ -645,27 +645,16 @@ function getFlow(id) {
|
|||||||
if (id !== 'global') {
|
if (id !== 'global') {
|
||||||
result.nodes = [];
|
result.nodes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flow.groups) {
|
|
||||||
var nodeIds = Object.keys(flow.groups);
|
|
||||||
if (nodeIds.length > 0) {
|
|
||||||
nodeIds.forEach(function(nodeId) {
|
|
||||||
var node = jsonClone(flow.groups[nodeId]);
|
|
||||||
delete node.credentials;
|
|
||||||
result.nodes.push(node)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flow.nodes) {
|
if (flow.nodes) {
|
||||||
var nodeIds = Object.keys(flow.nodes);
|
var nodeIds = Object.keys(flow.nodes);
|
||||||
if (nodeIds.length > 0) {
|
if (nodeIds.length > 0) {
|
||||||
nodeIds.forEach(function(nodeId) {
|
result.nodes = nodeIds.map(function(nodeId) {
|
||||||
var node = jsonClone(flow.nodes[nodeId]);
|
var node = jsonClone(flow.nodes[nodeId]);
|
||||||
if (node.type === 'link out') {
|
if (node.type === 'link out') {
|
||||||
delete node.wires;
|
delete node.wires;
|
||||||
}
|
}
|
||||||
delete node.credentials;
|
delete node.credentials;
|
||||||
result.nodes.push(node)
|
return node;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,17 +680,6 @@ function getFlow(id) {
|
|||||||
delete node.credentials
|
delete node.credentials
|
||||||
return node
|
return node
|
||||||
});
|
});
|
||||||
if (subflow.groups) {
|
|
||||||
var nodeIds = Object.keys(subflow.groups);
|
|
||||||
if (nodeIds.length > 0) {
|
|
||||||
nodeIds.forEach(function(nodeId) {
|
|
||||||
var node = jsonClone(subflow.groups[nodeId]);
|
|
||||||
delete node.credentials;
|
|
||||||
subflow.nodes.push(node)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
delete subflow.groups
|
|
||||||
}
|
|
||||||
if (subflow.configs) {
|
if (subflow.configs) {
|
||||||
var configIds = Object.keys(subflow.configs);
|
var configIds = Object.keys(subflow.configs);
|
||||||
subflow.configs = configIds.map(function(id) {
|
subflow.configs = configIds.map(function(id) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/runtime",
|
"name": "@node-red/runtime",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/registry": "4.0.1",
|
"@node-red/registry": "4.0.0",
|
||||||
"@node-red/util": "4.0.1",
|
"@node-red/util": "4.0.0",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"express": "4.19.2",
|
"express": "4.19.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/util",
|
"name": "@node-red/util",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
10
packages/node_modules/node-red/package.json
vendored
10
packages/node_modules/node-red/package.json
vendored
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red",
|
"name": "node-red",
|
||||||
"version": "4.0.1",
|
"version": "4.0.0",
|
||||||
"description": "Low-code programming for event-driven applications",
|
"description": "Low-code programming for event-driven applications",
|
||||||
"homepage": "https://nodered.org",
|
"homepage": "https://nodered.org",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@@ -31,10 +31,10 @@
|
|||||||
"flow"
|
"flow"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/editor-api": "4.0.1",
|
"@node-red/editor-api": "4.0.0",
|
||||||
"@node-red/runtime": "4.0.1",
|
"@node-red/runtime": "4.0.0",
|
||||||
"@node-red/util": "4.0.1",
|
"@node-red/util": "4.0.0",
|
||||||
"@node-red/nodes": "4.0.1",
|
"@node-red/nodes": "4.0.0",
|
||||||
"basic-auth": "2.0.1",
|
"basic-auth": "2.0.1",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
var http = require("http");
|
var http = require("http");
|
||||||
var https = require("https");
|
var https = require("https");
|
||||||
var should = require("should");
|
var should = require("should");
|
||||||
var sinon = require("sinon");
|
|
||||||
var httpProxyHelper = require("nr-test-utils").require("@node-red/nodes/core/network/lib/proxyHelper.js");
|
|
||||||
var express = require("express");
|
var express = require("express");
|
||||||
var bodyParser = require('body-parser');
|
var bodyParser = require('body-parser');
|
||||||
var stoppable = require('stoppable');
|
var stoppable = require('stoppable');
|
||||||
@@ -495,7 +493,6 @@ describe('HTTP Request Node', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
sinon.restore();
|
|
||||||
process.env.http_proxy = preEnvHttpProxyLowerCase;
|
process.env.http_proxy = preEnvHttpProxyLowerCase;
|
||||||
process.env.HTTP_PROXY = preEnvHttpProxyUpperCase;
|
process.env.HTTP_PROXY = preEnvHttpProxyUpperCase;
|
||||||
// On Windows, if environment variable of NO_PROXY that includes lower cases
|
// On Windows, if environment variable of NO_PROXY that includes lower cases
|
||||||
@@ -1802,80 +1799,27 @@ describe('HTTP Request Node', function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use env var http_proxy', function(done) {
|
//Removing HTTP Proxy testcases as GOT + Proxy_Agent doesn't work with mock'd proxy
|
||||||
const url = getTestURL('/postInspect')
|
/* */
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
it('should use http_proxy', function(done) {
|
||||||
|
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
|
||||||
const flow = [
|
{id:"n2", type:"helper"}];
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: url },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
deleteProxySetting();
|
||||||
process.env.http_proxy = proxyUrl
|
process.env.http_proxy = "http://localhost:" + testProxyPort;
|
||||||
helper.load(testNode, flow, function (msg) {
|
helper.load(httpRequestNode, flow, function() {
|
||||||
try {
|
var n1 = helper.getNode("n1");
|
||||||
// static URL set in the nodes configuration and the proxy will be setup upon initialisation
|
var n2 = helper.getNode("n2");
|
||||||
proxySpy.calledOnce.should.be.true()
|
n2.on("input", function(msg) {
|
||||||
proxySpy.calledWith(url, { }).should.be.true()
|
try {
|
||||||
proxySpy.returnValues[0].should.be.equal(proxyUrl)
|
msg.should.have.property('statusCode',200);
|
||||||
done()
|
msg.payload.should.have.property('headers');
|
||||||
} catch (err) {
|
//msg.payload.headers.should.have.property('x-testproxy-header','foobar');
|
||||||
done(err);
|
done();
|
||||||
}
|
} catch(err) {
|
||||||
});
|
done(err);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
it('should use env var https_proxy', function(done) {
|
n1.receive({payload:"foo"});
|
||||||
const url = getSslTestURL('/postInspect')
|
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
|
||||||
|
|
||||||
const flow = [
|
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: url },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
|
||||||
process.env.https_proxy = proxyUrl
|
|
||||||
helper.load(testNode, flow, function (msg) {
|
|
||||||
try {
|
|
||||||
// static URL set in the nodes configuration and the proxy will be setup upon initialisation
|
|
||||||
proxySpy.calledOnce.should.be.true()
|
|
||||||
proxySpy.calledWith(url, { }).should.be.true()
|
|
||||||
proxySpy.returnValues[0].should.be.equal(proxyUrl)
|
|
||||||
done()
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not use env var http*_proxy when no_proxy is set', function(done) {
|
|
||||||
const url = getSslTestURL('/postInspect')
|
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
|
||||||
|
|
||||||
const flow = [
|
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: url },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
|
||||||
process.env.http_proxy = proxyUrl
|
|
||||||
process.env.https_proxy = proxyUrl
|
|
||||||
process.env.no_proxy = "localhost"
|
|
||||||
helper.load(testNode, flow, function (msg) {
|
|
||||||
try {
|
|
||||||
// static URL set in the nodes configuration and the proxy will be setup upon initialisation
|
|
||||||
proxySpy.calledOnce.should.be.true()
|
|
||||||
proxySpy.calledWith(url, { }).should.be.true()
|
|
||||||
proxySpy.returnValues[0].should.be.equal('')
|
|
||||||
done()
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2053,135 +1997,6 @@ describe('HTTP Request Node', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use UI proxy for statically configured URL', function (done) {
|
|
||||||
const url = getTestURL('/postInspect')
|
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
|
||||||
const flow = [
|
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: url, proxy: "n3" },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
{ id: "n3", type: "http proxy", url: proxyUrl, noproxy: ["foo"] }
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
|
||||||
|
|
||||||
// static URL set in the nodes configuration will cause the proxy setup to be called
|
|
||||||
// no no need to send a message to the node
|
|
||||||
helper.load(testNode, flow, function () {
|
|
||||||
try {
|
|
||||||
// ensure getProxyForUrl was called and returned the correct proxy URL
|
|
||||||
proxySpy.calledOnce.should.be.true()
|
|
||||||
proxySpy.calledWith(url, { env: { no_proxy: "foo", http_proxy: proxyUrl, https_proxy: proxyUrl } }).should.be.true()
|
|
||||||
proxySpy.returnValues[0].should.be.equal(proxyUrl)
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should use UI proxy for HTTP URL passed in via msg', function (done) {
|
|
||||||
const url = getTestURL('/postInspect')
|
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
|
||||||
const flow = [
|
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: "", proxy: "n3" },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
{ id: "n3", type: "http proxy", url: proxyUrl, noproxy: ["foo,bar"] }
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
|
||||||
helper.load(testNode, flow, function () {
|
|
||||||
const n1 = helper.getNode("n1");
|
|
||||||
const n2 = helper.getNode("n2");
|
|
||||||
try {
|
|
||||||
proxySpy.calledOnce.should.be.false() // proxy setup should not be called when there is no URL to check needs proxying
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n2.on("input", function (msg) {
|
|
||||||
try {
|
|
||||||
// ensure getProxyForUrl was called and returned the correct proxy URL
|
|
||||||
proxySpy.calledOnce.should.be.true()
|
|
||||||
proxySpy.calledWith(url, { env: { no_proxy: "foo,bar", http_proxy: proxyUrl, https_proxy: proxyUrl } }).should.be.true()
|
|
||||||
proxySpy.returnValues[0].should.be.equal(proxyUrl)
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
n1.receive({ url: url });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should use UI proxy for HTTPS URL passed in via msg', function (done) {
|
|
||||||
const url = getSslTestURL('/postInspect')
|
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
|
||||||
const flow = [
|
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: "", proxy: "n3" },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
{ id: "n3", type: "http proxy", url: proxyUrl, noproxy: ["foo,bar,baz"] }
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
|
||||||
helper.load(testNode, flow, function () {
|
|
||||||
const n1 = helper.getNode("n1");
|
|
||||||
const n2 = helper.getNode("n2");
|
|
||||||
try {
|
|
||||||
proxySpy.calledOnce.should.be.false() // proxy setup should not be called when there is no URL to check needs proxying
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n2.on("input", function (msg) {
|
|
||||||
try {
|
|
||||||
// ensure getProxyForUrl was called and returned the correct proxy URL
|
|
||||||
proxySpy.calledOnce.should.be.true()
|
|
||||||
proxySpy.calledWith(url, { env: { no_proxy: "foo,bar,baz", http_proxy: proxyUrl, https_proxy: proxyUrl } }).should.be.true()
|
|
||||||
proxySpy.returnValues[0].should.be.equal(proxyUrl)
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
n1.receive({ url: url });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should not use UI proxy if noproxy excludes it', function (done) {
|
|
||||||
const url = getSslTestURL('/postInspect')
|
|
||||||
const proxyUrl = "http://localhost:" + testProxyPort
|
|
||||||
const flow = [
|
|
||||||
{ id: "n1", type: "http request", wires: [["n2"]], method: "POST", ret: "obj", url: "", proxy: "n3" },
|
|
||||||
{ id: "n2", type: "helper" },
|
|
||||||
{ id: "n3", type: "http proxy", url: proxyUrl, noproxy: ["foo,localhost,baz"] }
|
|
||||||
];
|
|
||||||
const proxySpy = sinon.spy(httpProxyHelper, 'getProxyForUrl')
|
|
||||||
const testNode = [httpRequestNode, httpProxyNode];
|
|
||||||
deleteProxySetting();
|
|
||||||
helper.load(testNode, flow, function () {
|
|
||||||
const n1 = helper.getNode("n1");
|
|
||||||
const n2 = helper.getNode("n2");
|
|
||||||
try {
|
|
||||||
proxySpy.calledOnce.should.be.false() // proxy setup should not be called when there is no URL to check needs proxying
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n2.on("input", function (msg) {
|
|
||||||
try {
|
|
||||||
// ensure getProxyForUrl was called and returned no proxy
|
|
||||||
proxySpy.calledOnce.should.be.true()
|
|
||||||
proxySpy.calledWith(url, { env: { no_proxy: "foo,localhost,baz", http_proxy: proxyUrl, https_proxy: proxyUrl } }).should.be.true()
|
|
||||||
proxySpy.returnValues[0].should.be.equal('')
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
n1.receive({ url: url });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
describe('authentication', function() {
|
describe('authentication', function() {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user