Compare commits

...

14 Commits

Author SHA1 Message Date
Nick O'Leary
1a3cc06935 Use rfdc module for cloning when we know its pure JSON 2024-05-03 16:45:50 +01:00
Nick O'Leary
a712a9363b Merge pull request #4674 from kazuhitoyokoi/dev-addjpn
Add Japanese translations for 4.0.0-beta.2
2024-05-03 16:18:50 +01:00
Kazuhito Yokoi
437c28e2b8 Fix typos in welcome tour for 4.0.0-beta.2 2024-04-28 21:27:25 +09:00
Kazuhito Yokoi
c05d18ada1 Add Japanese translations for 4.0.0-beta.2 2024-04-28 21:22:15 +09:00
Nick O'Leary
cfb300ec06 Merge pull request #4672 from node-red/allow-blank-env-var-substitutions
Allow blank strings to be used for env var property substitutions
2024-04-24 23:37:23 +02:00
Nick O'Leary
236e668201 Allow blank strings to be used for env var property substitutions
Fixes #4663
2024-04-24 22:58:11 +02:00
Nick O'Leary
c9b902c2b4 Merge pull request #4658 from node-red/fix-subflow-conf-type
Fix saving of conf-type properties in module packaged subflows
2024-04-23 23:45:29 +02:00
Nick O'Leary
ac8b1e19b7 Merge pull request #4662 from hardillb/timeout-npm-install
Add npm install timeout notification
2024-04-23 23:44:51 +02:00
Ben Hardill
148e64c3da Update packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2024-04-18 14:22:50 +01:00
Ben Hardill
c6289ebb2c Merge branch 'dev' into timeout-npm-install 2024-04-18 12:12:53 +01:00
Ben Hardill
5f4ece6813 Move translation 2024-04-18 11:47:49 +01:00
Ben Hardill
c990ec39d6 revert DELETE change 2024-04-18 11:35:51 +01:00
Ben Hardill
1fdc600ecd Add npm install timeout notification
part of https://github.com/node-red/node-red/issues/4622
2024-04-18 11:27:32 +01:00
Nick O'Leary
e354d2ce29 Fix saving of conf-type properties in module packaged subflows 2024-04-12 14:08:07 +01:00
13 changed files with 98 additions and 51 deletions

View File

@@ -73,6 +73,7 @@
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.5.2",
"rfdc": "^1.3.1",
"semver": "7.5.4",
"tar": "6.2.1",
"tough-cookie": "4.1.3",

View File

@@ -643,6 +643,7 @@
"errors": {
"catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
"installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"installTimeout": "<p>Install continuing the background.</p><p>Nodes will appear in palette when complete. Check the log for more information.</p>",
"removeFailed": "<p>Failed to remove: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"updateFailed": "<p>Failed to update: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"enableFailed": "<p>Failed to enable: __module__</p><p>__message__</p><p>Check the log for more information</p>",
@@ -657,6 +658,9 @@
"body": "<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
"title": "Remove nodes"
},
"removePlugin": {
"body": "<p>Removed plugin __module__. Please reload the editor to clear left-overs.</p>"
},
"update": {
"body": "<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
"title": "Update nodes"
@@ -668,7 +672,8 @@
"review": "Open node information",
"install": "Install",
"remove": "Remove",
"update": "Update"
"update": "Update",
"understood": "Understood"
}
}
}

View File

@@ -614,6 +614,8 @@
},
"nodeCount": "__label__ 個のノード",
"nodeCount_plural": "__label__ 個のノード",
"pluginCount": "__count__ 個のプラグイン",
"pluginCount_plural": "__count__ 個のプラグイン",
"moduleCount": "__count__ 個のモジュール",
"moduleCount_plural": "__count__ 個のモジュール",
"inuse": "使用中",
@@ -641,6 +643,7 @@
"errors": {
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
"installTimeout": "<p>バックグラウンドでインストールが継続されます。</p><p>完了した時にノードが表示されます。詳細はログを確認してください。</p>",
"removeFailed": "<p>削除処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
"updateFailed": "<p>更新処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
"enableFailed": "<p>有効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
@@ -655,6 +658,9 @@
"body": "<p>__module__ を削除します。</p><p>Node-REDからードを削除します。ードはNode-REDが再起動されるまで、リソースを使い続ける可能性があります。</p>",
"title": "ノードを削除"
},
"removePlugin": {
"body": "<p>プラグイン __module__ を削除しました。ブラウザを再読み込みして残った表示を消してください。</p>"
},
"update": {
"body": "<p>__module__ を更新します。</p><p>更新を完了するには手動でNode-REDを再起動する必要があります。</p>",
"title": "ノードの更新"
@@ -666,7 +672,8 @@
"review": "ノードの情報を参照",
"install": "追加",
"remove": "削除",
"update": "更新"
"update": "更新",
"understood": "了解"
}
}
}

View File

@@ -133,7 +133,7 @@ RED.palette.editor = (function() {
}).done(function(data,textStatus,xhr) {
callback();
}).fail(function(xhr,textStatus,err) {
callback(xhr);
callback(xhr,textStatus,err);
});
}
function removeNodeModule(id,callback) {
@@ -1346,13 +1346,13 @@ RED.palette.editor = (function() {
});
if (!found_onremove) {
let removeNotify = RED.notify("Removed plugin " + entry.name + ". Please reload the editor to clear left-overs.",{
let removeNotify = RED.notify(RED._("palette.editor.confirm.removePlugin.body",{module:entry.name}),{
modal: true,
fixed: true,
type: 'warning',
buttons: [
{
text: "Understood",
text: RED._("palette.editor.confirm.button.understood"),
class:"primary",
click: function(e) {
removeNotify.close();
@@ -1405,9 +1405,28 @@ RED.palette.editor = (function() {
RED.actions.invoke("core:show-event-log");
});
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.id+" "+entry.version);
installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr) {
installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr, textStatus,err) {
spinner.remove();
if (xhr) {
if (err && xhr.status === 504) {
var notification = RED.notify(RED._("palette.editor.errors.installTimeout"), {
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.close"),
click: function() {
notification.close();
}
},{
text: RED._("eventLog.view"),
click: function() {
notification.close();
RED.actions.invoke("core:show-event-log");
}
}
]
})
} else if (xhr) {
if (xhr.responseJSON) {
var notification = RED.notify(RED._('palette.editor.errors.installFailed',{module: entry.id,message:xhr.responseJSON.message}),{
type: 'error',

View File

@@ -1363,7 +1363,7 @@ RED.subflow = (function() {
break;
case "conf-types":
item.value = input.val()
item.type = data.parent.value;
item.type = "conf-type"
}
if (ui.type === "cred" || item.type !== data.parent.type || item.value !== data.parent.value) {
env.push(item);

View File

@@ -16,7 +16,8 @@ export default {
},
{
title: {
"en-US": "Multiplayer Mode"
"en-US": "Multiplayer Mode",
"ja": "複数ユーザ同時利用モード"
},
image: 'images/nr4-multiplayer.png',
description: {
@@ -24,46 +25,58 @@ export default {
to work with when you have multiple people editing flows at the same time.</p>
<p>When this feature is enabled, you will now see who else has the editor open and some
basic information on where they are in the editor.</p>
<p>Check the release post for details on how to enable this feature in your settings file.</p>`
<p>Check the release post for details on how to enable this feature in your settings file.</p>`,
"ja": `<p>本リリースには、複数ユーザが同時にフローを編集する時に、Node-REDをより使いやすくするのための最初の微修正が入っています。</p>
<p>本機能を有効にすると、誰がエディタを開いているか、その人がエディタ上のどこにいるかの基本的な情報が表示されます。</p>
<p>設定ファイルで本機能を有効化する方法の詳細は、リリースの投稿を確認してください。</p>`
}
},
{
title: {
"en-US": "Better Configuration Node UX"
"en-US": "Better Configuration Node UX",
"ja": "設定ードのUXが向上"
},
image: 'images/nr4-config-select.png',
description: {
"en-US": `<p>The Configuration node selection UI has had a small update to have a dedicated 'add' button
next to the select box.</p>
<p>It's a small change, but should make it easier to work with your config nodes.</p>`
<p>It's a small change, but should make it easier to work with your config nodes.</p>`,
"ja": `<p>設定ードを選択するUIが修正され、選択ボックスの隣に専用の「追加」ボタンが追加されました。</p>
<p>微修正ですが設定ノードの操作が容易になります。</p>`
}
},
{
title: {
"en-US": "Remembering palette state"
"en-US": "Remembering palette state",
"ja": "パレットの状態を維持"
},
description: {
"en-US": `<p>The palette now remembers what categories you have hidden between reloads - as well as any
filter you have applied.</p>`
filter you have applied.</p>`,
"ja": `<p>パレット上で非表示にしたカテゴリや適用したフィルタが、リロードしても記憶されるようになりました。</p>`
}
},
{
title: {
"en-US": "Plugins shown in the Palette Manager"
"en-US": "Plugins shown in the Palette Manager",
"ja": "パレット管理にプラグインを表示"
},
image: 'images/nr4-plugins.png',
description: {
"en-US": `<p>The palette manager now shows any plugin modules you have installed, such as
<code>node-red-debugger</code>. Previously they would only be shown if they plugin include
nodes for the palette.</p>`
<code>node-red-debugger</code>. Previously they would only be shown if the plugins include
nodes for the palette.</p>`,
"ja": `<p>パレットの管理に <code>node-red-debugger</code> の様なインストールしたプラグインが表示されます。以前はプラグインにパレット向けのノードが含まれている時のみ表示されていました。</p>`
}
},
{
title: {
"en-US": "That's if for Beta 2!"
"en-US": "That's it for Beta 2!",
"ja": "ベータ2については以上です!"
},
description: {
"en-US": `<p>Keep clicking through to see what was added in Beta 1</p>`
"en-US": `<p>Keep clicking through to see what was added in Beta 1</p>`,
"ja": `<p>クリックを続けてベータ1で追加された内容を確認してください。</p>`
}
},
{

View File

@@ -88,7 +88,7 @@ function generateSubflowConfig(subflow) {
this.credentials['has_' + prop.name] = (this.credentials[prop.name] !== "");
} else {
switch(prop.type) {
case "str": this[prop.name] = prop.value||""; break;
case "str": case "conf-type": this[prop.name] = prop.value||""; break;
case "bool": this[prop.name] = (typeof prop.value === 'boolean')?prop.value:prop.value === "true" ; break;
case "num": this[prop.name] = (typeof prop.value === 'number')?prop.value:Number(prop.value); break;
default:

View File

@@ -15,6 +15,7 @@
**/
const clone = require("clone");
const jsonClone = require("rfdc")();
const Flow = require('./Flow').Flow;
const context = require('../nodes/context');
const util = require("util");
@@ -108,7 +109,7 @@ class Subflow extends Flow {
}
}
subflowInternalFlowConfig.subflows = clone(subflowDef.subflows || {});
subflowInternalFlowConfig.subflows = jsonClone(subflowDef.subflows || {});
remapSubflowNodes(subflowInternalFlowConfig.configs,node_map);
remapSubflowNodes(subflowInternalFlowConfig.nodes,node_map);
@@ -220,7 +221,7 @@ class Subflow extends Flow {
}
if (this.subflowDef.in) {
subflowInstanceConfig.wires = this.subflowDef.in.map(function(n) { return n.wires.map(function(w) { return self.node_map[w.id].id;})})
subflowInstanceConfig._originalWires = clone(subflowInstanceConfig.wires);
subflowInstanceConfig._originalWires = jsonClone(subflowInstanceConfig.wires);
}
this.node = new Node(subflowInstanceConfig);
@@ -244,14 +245,14 @@ class Subflow extends Flow {
if (self.subflowDef.out) {
var node,wires,i,j;
// Restore the original wiring to the internal nodes
subflowInstanceConfig.wires = clone(subflowInstanceConfig._originalWires);
subflowInstanceConfig.wires = jsonClone(subflowInstanceConfig._originalWires);
for (i=0;i<self.subflowDef.out.length;i++) {
wires = self.subflowDef.out[i].wires;
for (j=0;j<wires.length;j++) {
if (wires[j].id != self.subflowDef.id) {
node = self.node_map[wires[j].id];
if (node && node._originalWires) {
node.wires = clone(node._originalWires);
node.wires = jsonClone(node._originalWires);
}
}
}
@@ -300,7 +301,7 @@ class Subflow extends Flow {
var node = self.node_map[wires[j].id];
if (node) {
if (!node._originalWires) {
node._originalWires = clone(node.wires);
node._originalWires = jsonClone(node.wires);
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]).concat(this.subflowInstance.wires[i]);
} else {
@@ -323,7 +324,7 @@ class Subflow extends Flow {
var node = self.node_map[wires[j].id];
if (node) {
if (!node._originalWires) {
node._originalWires = clone(node.wires);
node._originalWires = jsonClone(node.wires);
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
node.wires[wires[j].port].push(subflowStatusId);
@@ -463,7 +464,7 @@ class Subflow extends Flow {
* @return {[type]} [description]
*/
function createNodeInSubflow(subflowInstanceId, def) {
let node = clone(def);
let node = jsonClone(def);
let nid = `${subflowInstanceId}-${node.id}` //redUtil.generateId();
// console.log("Create Node In subflow",node._alias, "--->",nid, "(",node.type,")")
// node_map[node.id] = node;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
**/
var clone = require("clone");
const jsonClone = require("rfdc")();
var Flow = require('./Flow');
@@ -140,16 +140,16 @@ function setFlows(_config,_credentials,type,muteLog,forceStart,user) {
if (type === "load") {
isLoad = true;
configSavePromise = loadFlows().then(function(_config) {
config = clone(_config.flows);
newFlowConfig = flowUtil.parseConfig(clone(config));
config = jsonClone(_config.flows);
newFlowConfig = flowUtil.parseConfig(jsonClone(config));
type = "full";
return _config.rev;
});
} else {
// Clone the provided config so it can be manipulated
config = clone(_config);
config = jsonClone(_config);
// Parse the configuration
newFlowConfig = flowUtil.parseConfig(clone(config));
newFlowConfig = flowUtil.parseConfig(jsonClone(config));
// Generate a diff to identify what has changed
diff = flowUtil.diffConfigs(activeFlowConfig,newFlowConfig);
@@ -609,7 +609,7 @@ async function addFlow(flow, user) {
nodes.push(node);
}
}
var newConfig = clone(activeConfig.flows);
var newConfig = jsonClone(activeConfig.flows);
newConfig = newConfig.concat(nodes);
return setFlows(newConfig, null, 'flows', true, null, user).then(function() {
@@ -650,7 +650,7 @@ function getFlow(id) {
var nodeIds = Object.keys(flow.nodes);
if (nodeIds.length > 0) {
result.nodes = nodeIds.map(function(nodeId) {
var node = clone(flow.nodes[nodeId]);
var node = jsonClone(flow.nodes[nodeId]);
if (node.type === 'link out') {
delete node.wires;
}
@@ -662,7 +662,7 @@ function getFlow(id) {
if (flow.configs) {
var configIds = Object.keys(flow.configs);
result.configs = configIds.map(function(configId) {
const node = clone(flow.configs[configId]);
const node = jsonClone(flow.configs[configId]);
delete node.credentials;
return node
@@ -674,17 +674,17 @@ function getFlow(id) {
if (flow.subflows) {
var subflowIds = Object.keys(flow.subflows);
result.subflows = subflowIds.map(function(subflowId) {
var subflow = clone(flow.subflows[subflowId]);
var subflow = jsonClone(flow.subflows[subflowId]);
var nodeIds = Object.keys(subflow.nodes);
subflow.nodes = nodeIds.map(function(id) {
const node = clone(subflow.nodes[id])
const node = jsonClone(subflow.nodes[id])
delete node.credentials
return node
});
if (subflow.configs) {
var configIds = Object.keys(subflow.configs);
subflow.configs = configIds.map(function(id) {
const node = clone(subflow.configs[id])
const node = jsonClone(subflow.configs[id])
delete node.credentials
return node
})
@@ -709,7 +709,7 @@ async function updateFlow(id,newFlow, user) {
}
label = activeFlowConfig.flows[id].label;
}
var newConfig = clone(activeConfig.flows);
var newConfig = jsonClone(activeConfig.flows);
var nodes;
if (id === 'global') {
@@ -779,7 +779,7 @@ async function removeFlow(id, user) {
throw e;
}
var newConfig = clone(activeConfig.flows);
var newConfig = jsonClone(activeConfig.flows);
newConfig = newConfig.filter(function(node) {
return node.z !== id && node.id !== id;
});

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
const clone = require("clone");
const jsonClone = require("rfdc")();
const redUtil = require("@node-red/util").util;
const Log = require("@node-red/util").log;
const typeRegistry = require("@node-red/registry");
@@ -68,7 +68,7 @@ function mapEnvVarProperties(obj,prop,flow,config) {
if (obj[prop][0] === "$" && (EnvVarPropertyRE_old.test(v) || EnvVarPropertyRE.test(v)) ) {
const envVar = v.substring(2,v.length-1);
const r = redUtil.getSetting(config, envVar, flow);
if (r !== undefined && r !== '') {
if (r !== undefined) {
obj[prop] = r
}
}
@@ -175,7 +175,7 @@ async function createNode(flow,config) {
try {
var nodeTypeConstructor = typeRegistry.get(type);
if (typeof nodeTypeConstructor === "function") {
var conf = clone(config);
var conf = jsonClone(config);
delete conf.credentials;
try {
Object.defineProperty(conf,'_module', {value: typeRegistry.getNodeInfo(type), enumerable: false, writable: true })
@@ -202,8 +202,8 @@ async function createNode(flow,config) {
var subflowInstanceConfig = subflowConfig.subflows[nodeTypeConstructor.subflow.id];
delete subflowConfig.subflows[nodeTypeConstructor.subflow.id];
subflowInstanceConfig.subflows = subflowConfig.subflows;
var instanceConfig = clone(config);
instanceConfig.env = clone(nodeTypeConstructor.subflow.env);
var instanceConfig = jsonClone(config);
instanceConfig.env = jsonClone(nodeTypeConstructor.subflow.env);
instanceConfig.env = nodeTypeConstructor.subflow.env.map(nodeProp => {
var nodePropType;
@@ -256,7 +256,7 @@ function parseConfig(config) {
flow.missingTypes = [];
config.forEach(function (n) {
flow.allNodes[n.id] = clone(n);
flow.allNodes[n.id] = jsonClone(n);
if (n.type === 'tab') {
flow.flows[n.id] = n;
flow.flows[n.id].subflows = {};

View File

@@ -14,9 +14,8 @@
* limitations under the License.
**/
var path = require("path");
var fs = require("fs");
var clone = require("clone");
const jsonClone = require("rfdc")();
var util = require("util");
var registry = require("@node-red/registry");
@@ -98,7 +97,7 @@ function createNode(node,def) {
}
var creds = credentials.get(id);
if (creds) {
creds = clone(creds);
creds = jsonClone(creds);
//console.log("Attaching credentials to ",node.id);
// allow $(foo) syntax to substitute env variables for credentials also...
for (var p in creds) {

View File

@@ -25,6 +25,7 @@
"removing-modules": "設定からモジュールを削除します",
"added-types": "追加したノード:",
"removed-types": "削除したノード:",
"removed-plugins": "削除したプラグイン:",
"install": {
"invalid": "不正なモジュール名",
"installing": "モジュール __name__, バージョン: __version__ をインストールします",

View File

@@ -22,6 +22,7 @@
"clone": "2.1.2",
"express": "4.19.2",
"fs-extra": "11.1.1",
"json-stringify-safe": "5.0.1"
"json-stringify-safe": "5.0.1",
"rfdc": "^1.3.1"
}
}