1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge branch 'master' into dev

This commit is contained in:
Nick O'Leary 2021-12-05 19:32:13 +00:00
commit 7cd3e49f04
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
47 changed files with 541 additions and 177 deletions

View File

@ -2,6 +2,39 @@
#### 2.1.4: Maintenance Release
Runtime
- fix env var access using $parent for groups (#3278) @HiroyasuNishiyama
- Add proper error handling for 404 errors when serving debug files (#3277) @knolleary
- Add Japanese translations for Node-RED v2.1.0-beta.1 (#3179) @kazuhitoyokoi
- Include full user object on login audit events (#3269) @knolleary
- Remove styling from de locale files (#3237) @knolleary
Editor
- Change tab hide button icon to an eye and add search option (#3282) @knolleary
- Fix i18n handling of namespaces with spaces in (#3281) @knolleary
- Trigger change event when autoComplete fills in input (#3280) @knolleary
- Apply CN i18n fix (#3279) @knolleary
- fix select menu label of config node to use paletteLabel (#3273) @HiroyasuNishiyama
- fix removed tab not to cause node conflict (#3275) @HiroyasuNishiyama
- Group diff fix (#3239) @knolleary
- Only toggle disabled workspace flag if on activeWorkspace (#3252) @knolleary
- Do not show status for disabled nodes (#3253) @knolleary
- Set dimension value for tour guide (#3265) @kazuhitoyokoi
- Avoid redundant initialisation of TypedInput type (#3263) @knolleary
- Don't let themes change flow port label color (#3270) @bonanitech
- Fix treeList gutter calculation to handle floating gutters (#3238) @knolleary
Nodes
- Debug: Handle RegExp types in Debug sidebar (#3251) @knolleary
- Delay: fix 2nd output when in rate limit per topic modes (#3261) @dceejay
- Link: fix to show link target when selected (#3267) @HiroyasuNishiyama
- Inject: Do not modify inject node props in oneditprepare (#3242) @knolleary
- HTTP Request: HTTP Basic Auth should always add : between username and password even if empty (#3236) @hardillb
#### 2.1.3: Maintenance Release #### 2.1.3: Maintenance Release

View File

@ -26,9 +26,9 @@
} }
], ],
"dependencies": { "dependencies": {
"acorn": "8.5.0", "acorn": "8.6.0",
"acorn-walk": "8.2.0", "acorn-walk": "8.2.0",
"ajv": "8.6.3", "ajv": "8.8.2",
"async-mutex": "0.3.2", "async-mutex": "0.3.2",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
@ -37,7 +37,7 @@
"clone": "2.1.2", "clone": "2.1.2",
"content-type": "1.0.4", "content-type": "1.0.4",
"cookie": "0.4.1", "cookie": "0.4.1",
"cookie-parser": "1.4.5", "cookie-parser": "1.4.6",
"cors": "2.8.5", "cors": "2.8.5",
"cronosjs": "1.7.1", "cronosjs": "1.7.1",
"denque": "2.0.1", "denque": "2.0.1",
@ -46,11 +46,11 @@
"form-data": "4.0.0", "form-data": "4.0.0",
"fs-extra": "10.0.0", "fs-extra": "10.0.0",
"fs.notify": "0.0.4", "fs.notify": "0.0.4",
"got": "11.8.2", "got": "11.8.3",
"hash-sum": "2.0.0", "hash-sum": "2.0.0",
"hpagent": "0.1.2", "hpagent": "0.1.2",
"https-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.0",
"i18next": "21.3.1", "i18next": "21.5.4",
"iconv-lite": "0.6.3", "iconv-lite": "0.6.3",
"is-utf8": "0.2.1", "is-utf8": "0.2.1",
"js-yaml": "3.14.1", "js-yaml": "3.14.1",
@ -60,22 +60,22 @@
"media-typer": "1.1.0", "media-typer": "1.1.0",
"memorystore": "1.6.6", "memorystore": "1.6.6",
"mime": "2.5.2", "mime": "2.5.2",
"moment-timezone": "0.5.33", "moment-timezone": "0.5.34",
"mqtt": "4.2.8", "mqtt": "4.2.8",
"multer": "1.4.3", "multer": "1.4.3",
"mustache": "4.2.0", "mustache": "4.2.0",
"node-red-admin": "^2.2.1", "node-red-admin": "^2.2.1",
"nopt": "5.0.0", "nopt": "5.0.0",
"oauth2orize": "1.11.0", "oauth2orize": "1.11.1",
"on-headers": "1.0.2", "on-headers": "1.0.2",
"passport": "0.5.0", "passport": "0.5.0",
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.1", "raw-body": "2.4.2",
"semver": "7.3.5", "semver": "7.3.5",
"tar": "6.1.11", "tar": "6.1.11",
"tough-cookie": "4.0.0", "tough-cookie": "4.0.0",
"uglify-js": "3.14.2", "uglify-js": "3.14.4",
"uuid": "8.3.2", "uuid": "8.3.2",
"ws": "7.5.1", "ws": "7.5.1",
"xml2js": "0.4.23" "xml2js": "0.4.23"
@ -109,11 +109,11 @@
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "3.0.7", "marked": "3.0.7",
"minami": "1.2.3", "minami": "1.2.3",
"mocha": "9.1.2", "mocha": "9.1.3",
"node-red-node-test-helper": "^0.2.7", "node-red-node-test-helper": "^0.2.7",
"nodemon": "2.0.13", "nodemon": "2.0.15",
"proxy": "^1.0.2", "proxy": "^1.0.2",
"sass": "1.43.2", "sass": "1.44.0",
"should": "13.2.3", "should": "13.2.3",
"sinon": "11.1.2", "sinon": "11.1.2",
"stoppable": "^1.1.0", "stoppable": "^1.1.0",

View File

@ -141,7 +141,7 @@ function completeVerify(profile,done) {
Users.authenticate(profile).then(function(user) { Users.authenticate(profile).then(function(user) {
if (user) { if (user) {
Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) { Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
log.audit({event: "auth.login",username:user.username,scope:user.permissions}); log.audit({event: "auth.login",user,username:user.username,scope:user.permissions});
user.tokens = tokens; user.tokens = tokens;
done(null,user); done(null,user);
}); });

View File

@ -93,7 +93,7 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
return logEntry.user !== username; return logEntry.user !== username;
}); });
Tokens.create(username,client.id,scope).then(function(tokens) { Tokens.create(username,client.id,scope).then(function(tokens) {
log.audit({event: "auth.login",username:username,client:client.id,scope:scope}); log.audit({event: "auth.login",user,username:username,client:client.id,scope:scope});
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in}); done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
}); });
} else { } else {

View File

@ -28,7 +28,7 @@
"mime": "2.5.2", "mime": "2.5.2",
"multer": "1.4.3", "multer": "1.4.3",
"mustache": "4.2.0", "mustache": "4.2.0",
"oauth2orize": "1.11.0", "oauth2orize": "1.11.1",
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"passport": "0.5.0", "passport": "0.5.0",

View File

@ -59,6 +59,8 @@
"hideOtherFlows": "Hide other flows", "hideOtherFlows": "Hide other flows",
"showAllFlows": "Show all flows", "showAllFlows": "Show all flows",
"hideAllFlows": "Hide all flows", "hideAllFlows": "Hide all flows",
"hiddenFlows": "List __count__ hidden flow",
"hiddenFlows_plural": "List __count__ hidden flows",
"showLastHiddenFlow": "Show last hidden flow", "showLastHiddenFlow": "Show last hidden flow",
"listFlows": "List flows", "listFlows": "List flows",
"listSubflows": "List subflows", "listSubflows": "List subflows",
@ -90,6 +92,7 @@
"palette": { "palette": {
"show": "Show palette" "show": "Show palette"
}, },
"edit": "Edit",
"settings": "Settings", "settings": "Settings",
"userSettings": "User Settings", "userSettings": "User Settings",
"nodes": "Nodes", "nodes": "Nodes",
@ -668,7 +671,8 @@
"unusedConfigNodes": "Unused configuration nodes", "unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes", "invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes", "uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows" "unusedSubflows": "Unused subflows",
"hiddenFlows": "Hidden flows"
} }
}, },
"help": { "help": {
@ -1135,6 +1139,7 @@
"defaultValue": "Default value" "defaultValue": "Default value"
}, },
"tourGuide": { "tourGuide": {
"takeATour": "Take a tour",
"start": "Start", "start": "Start",
"next": "Next" "next": "Next"
}, },

View File

@ -54,7 +54,14 @@
"delete": "本当に '__label__' を削除しますか?", "delete": "本当に '__label__' を削除しますか?",
"dropFlowHere": "ここにフローをドロップしてください", "dropFlowHere": "ここにフローをドロップしてください",
"addFlow": "フローの追加", "addFlow": "フローの追加",
"addFlowToRight": "右側にフローを追加",
"hideFlow": "フローを非表示",
"hideOtherFlows": "他のフローを非表示",
"showAllFlows": "全てのフローを表示",
"hideAllFlows": "全てのフローを非表示",
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
"listFlows": "フロー一覧", "listFlows": "フロー一覧",
"listSubflows": "サブフロー一覧",
"status": "状態", "status": "状態",
"enabled": "有効", "enabled": "有効",
"disabled": "無効", "disabled": "無効",
@ -83,6 +90,7 @@
"palette": { "palette": {
"show": "パレットを表示" "show": "パレットを表示"
}, },
"edit": "編集",
"settings": "設定", "settings": "設定",
"userSettings": "ユーザ設定", "userSettings": "ユーザ設定",
"nodes": "ノード", "nodes": "ノード",
@ -105,6 +113,7 @@
"editPalette": "パレットの管理", "editPalette": "パレットの管理",
"other": "その他", "other": "その他",
"showTips": "ヒントを表示", "showTips": "ヒントを表示",
"showWelcomeTours": "新バージョンのガイドツアーを表示",
"help": "Node-REDウェブサイト", "help": "Node-REDウェブサイト",
"projects": "プロジェクト", "projects": "プロジェクト",
"projects-new": "新規", "projects-new": "新規",
@ -116,7 +125,20 @@
"groupSelection": "選択部分をグループ化", "groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除", "ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ", "groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除" "groupRemoveSelection": "グループから削除",
"arrange": "配置",
"alignLeft": "左揃え",
"alignCenter": "左右中央揃え",
"alignRight": "右揃え",
"alignTop": "上揃え",
"alignMiddle": "上下中央揃え",
"alignBottom": "下揃え",
"distributeHorizontally": "左右に整列",
"distributeVertically": "上下に整列",
"moveToBack": "最背面へ移動",
"moveToFront": "最前面へ移動",
"moveBackwards": "背面へ移動",
"moveForwards": "前面へ移動"
} }
}, },
"actions": { "actions": {
@ -451,7 +473,8 @@
"global": "グローバル", "global": "グローバル",
"workspace": "ワークスペース", "workspace": "ワークスペース",
"selectAll": "全てのノードを選択", "selectAll": "全てのノードを選択",
"selectAllConnected": "接続された全てのノードを選択", "selectNone": "選択を外す",
"selectAllConnected": "接続されたノードを選択",
"addRemoveNode": "ノードの選択、選択解除", "addRemoveNode": "ノードの選択、選択解除",
"editSelected": "選択したノードを編集", "editSelected": "選択したノードを編集",
"deleteSelected": "選択したノードや接続を削除", "deleteSelected": "選択したノードや接続を削除",
@ -461,10 +484,13 @@
"moveNode": "選択したノードを移動(移動量大)", "moveNode": "選択したノードを移動(移動量大)",
"toggleSidebar": "サイドバーの表示/非表示", "toggleSidebar": "サイドバーの表示/非表示",
"togglePalette": "パレットの表示/非表示", "togglePalette": "パレットの表示/非表示",
"copyNode": "選択したノードをコピー", "copyNode": "ノードをコピー",
"cutNode": "選択したノードを切り取り", "cutNode": "ノードを切り取り",
"pasteNode": "ノードを貼り付け", "pasteNode": "ノードを貼り付け",
"copyGroupStyle": "グループ様式をコピー",
"pasteGroupStyle": "グループ様式を貼り付け",
"undoChange": "変更操作を戻す", "undoChange": "変更操作を戻す",
"redoChange": "変更操作をやり直し",
"searchBox": "ノードを検索", "searchBox": "ノードを検索",
"managePalette": "パレットの管理", "managePalette": "パレットの管理",
"actionList": "動作一覧" "actionList": "動作一覧"
@ -519,7 +545,8 @@
"nodeEnabled_plural": "ノードを有効化しました:", "nodeEnabled_plural": "ノードを有効化しました:",
"nodeDisabled": "ノードを無効化しました:", "nodeDisabled": "ノードを無効化しました:",
"nodeDisabled_plural": "ノードを無効化しました:", "nodeDisabled_plural": "ノードを無効化しました:",
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました" "nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
}, },
"editor": { "editor": {
"title": "パレットの管理", "title": "パレットの管理",
@ -1108,6 +1135,11 @@
"preview": "UIプレビュー", "preview": "UIプレビュー",
"defaultValue": "デフォルト値" "defaultValue": "デフォルト値"
}, },
"tourGuide": {
"takeATour": "ツアーを開始",
"start": "開始",
"next": "次へ"
},
"languages": { "languages": {
"de": "ドイツ語", "de": "ドイツ語",
"en-US": "英語", "en-US": "英語",

View File

@ -225,7 +225,7 @@
"compact": "紧凑", "compact": "紧凑",
"formatted": "已格式化", "formatted": "已格式化",
"copy": "导出到剪贴板", "copy": "导出到剪贴板",
"export": "到处到库", "export": "导出到库",
"exportAs": "导出为", "exportAs": "导出为",
"overwrite": "替换", "overwrite": "替换",
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>" "exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"

View File

@ -38,6 +38,8 @@ RED.i18n = (function() {
defaultNS: "editor", defaultNS: "editor",
fallbackLng: ['en-US'], fallbackLng: ['en-US'],
returnObjects: true, returnObjects: true,
keySeparator: ".",
nsSeparator: ":",
interpolation: { interpolation: {
unescapeSuffix: 'HTML', unescapeSuffix: 'HTML',
escapeValue: false, escapeValue: false,

View File

@ -805,7 +805,6 @@ RED.nodes = (function() {
var removedGroups = []; var removedGroups = [];
if (ws) { if (ws) {
delete workspaces[id]; delete workspaces[id];
allNodes.removeTab(id);
delete linkTabMap[id]; delete linkTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1); workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var i; var i;
@ -843,6 +842,7 @@ RED.nodes = (function() {
for (i=removedGroups.length-1; i>=0; i--) { for (i=removedGroups.length-1; i>=0; i--) {
removeGroup(removedGroups[i]); removeGroup(removedGroups[i]);
} }
allNodes.removeTab(id);
RED.events.emit('flows:remove',ws); RED.events.emit('flows:remove',ws);
} }
return {nodes:removedNodes,links:removedLinks, groups: removedGroups}; return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
@ -1097,6 +1097,11 @@ RED.nodes = (function() {
// Until we know how that can happen, add a filter here to remove them // Until we know how that can happen, add a filter here to remove them
node.nodes = node.nodes.filter(function(n) { return !!n }).map(function(n) { return n.id }); node.nodes = node.nodes.filter(function(n) { return !!n }).map(function(n) { return n.id });
} }
if (n.type === "tab" || n.type === "group") {
if (node.env && node.env.length === 0) {
delete node.env;
}
}
if (n._def.category != "config") { if (n._def.category != "config") {
node.x = n.x; node.x = n.x;
node.y = n.y; node.y = n.y;

View File

@ -590,7 +590,7 @@ var RED = (function() {
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"} {id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
]}); ]});
} }
menuOptions.push({id:"menu-item-edit-menu", label:"Edit", options: [ menuOptions.push({id:"menu-item-edit-menu", label:RED._("menu.label.edit"), options: [
{id: "menu-item-edit-undo", label:RED._("keyboard.undoChange"), disabled: true, onselect: "core:undo"}, {id: "menu-item-edit-undo", label:RED._("keyboard.undoChange"), disabled: true, onselect: "core:undo"},
{id: "menu-item-edit-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"}, {id: "menu-item-edit-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"},
null, null,

View File

@ -21,7 +21,7 @@
* value: String : the value to insert if selected * value: String : the value to insert if selected
* label: String|DOM Element : the label to display in the dropdown. * label: String|DOM Element : the label to display in the dropdown.
* } * }
* *
*/ */
$.widget( "nodered.autoComplete", { $.widget( "nodered.autoComplete", {
@ -62,7 +62,7 @@
maxHeight: 200, maxHeight: 200,
class: "red-ui-autoComplete-container", class: "red-ui-autoComplete-container",
options: completions, options: completions,
onselect: (opt) => { this.element.val(opt.value); this.element.focus() }, onselect: (opt) => { this.element.val(opt.value); this.element.focus(); this.element.trigger("change") },
onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()} onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()}
}); });
this.menu.show({ this.menu.show({

View File

@ -117,6 +117,8 @@ RED.tabs = (function() {
menuOptions = options.menu() menuOptions = options.menu()
} else if (Array.isArray(options.menu)) { } else if (Array.isArray(options.menu)) {
menuOptions = options.menu; menuOptions = options.menu;
} else if (typeof options.menu === 'function') {
menuOptions = options.menu();
} }
menu = RED.menu.init({options: menuOptions}); menu = RED.menu.init({options: menuOptions});
menu.attr("id",options.id+"-menu"); menu.attr("id",options.id+"-menu");
@ -809,15 +811,18 @@ RED.tabs = (function() {
event.preventDefault(); event.preventDefault();
removeTab(tab.id); removeTab(tab.id);
}); });
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
} }
if (tab.hideable) { if (tab.hideable) {
li.addClass("red-ui-tabs-closeable") li.addClass("red-ui-tabs-closeable")
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li); var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
closeLink.append('<i class="fa fa-times" />'); closeLink.append('<i class="fa fa-eye" />');
closeLink.append('<i class="fa fa-eye-slash" />');
closeLink.on("click",function(event) { closeLink.on("click",function(event) {
event.preventDefault(); event.preventDefault();
hideTab(tab.id); hideTab(tab.id);
}); });
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
} }
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li); var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
@ -826,7 +831,8 @@ RED.tabs = (function() {
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges); $('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
} }
link.attr("title",tab.label); // link.attr("title",tab.label);
RED.popover.tooltip(link,function() { return tab.label})
if (options.onadd) { if (options.onadd) {
options.onadd(tab); options.onadd(tab);
@ -945,7 +951,6 @@ RED.tabs = (function() {
renameTab: function(id,label) { renameTab: function(id,label) {
tabs[id].label = label; tabs[id].label = label;
var tab = ul.find("a[href='#"+id+"']"); var tab = ul.find("a[href='#"+id+"']");
tab.attr("title",label);
tab.find("span.red-ui-text-bidi-aware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label)); tab.find("span.red-ui-text-bidi-aware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
updateTabWidths(); updateTabWidths();
}, },

View File

@ -556,7 +556,7 @@
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect); this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton); this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
this.type(this.options.default||this.typeList[0].value); this.type(this.typeField.val() || this.options.default||this.typeList[0].value);
this.typeChanged = !!this.options.default; this.typeChanged = !!this.options.default;
}catch(err) { }catch(err) {
console.log(err.stack); console.log(err.stack);
@ -805,6 +805,7 @@
var that = this; var that = this;
var currentType = this.type(); var currentType = this.type();
this.typeMap = {}; this.typeMap = {};
var firstCall = (this.typeList === undefined);
this.typeList = types.map(function(opt) { this.typeList = types.map(function(opt) {
var result; var result;
if (typeof opt === 'string') { if (typeof opt === 'string') {
@ -829,10 +830,14 @@
} }
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) }); this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
if (currentType && !this.typeMap.hasOwnProperty(currentType)) { if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
this.type(this.typeList[0].value); if (!firstCall) {
this.type(this.typeList[0].value);
}
} else { } else {
this.propertyType = null; this.propertyType = null;
this.type(currentType); if (!firstCall) {
this.type(currentType);
}
} }
if (this.typeList.length === 1 && !this.typeList[0].icon && (!this.typeList[0].label || this.typeList[0].showLabel === false)) { if (this.typeList.length === 1 && !this.typeList[0].icon && (!this.typeList[0].label || this.typeList[0].showLabel === false)) {
this.selectTrigger.hide() this.selectTrigger.hide()

View File

@ -554,6 +554,8 @@ RED.diff = (function() {
color: "#DDAA99", color: "#DDAA99",
defaults:{name:{value:""}} defaults:{name:{value:""}}
} }
} else if (node.type === "group") {
def = RED.group.def;
} else { } else {
def = {}; def = {};
} }
@ -763,16 +765,15 @@ RED.diff = (function() {
} }
} }
if (node.hasOwnProperty('x')) { if (node.hasOwnProperty('x')) {
if (localNode) { if (localNode) {
if (localNode.x !== node.x || localNode.y !== node.y) { if (localNode.x !== node.x || localNode.y !== node.y || localNode.w !== node.w || localNode.h !== node.h ) {
localChanged = true; localChanged = true;
localChanges++; localChanges++;
} }
} }
if (remoteNode) { if (remoteNode) {
if (remoteNode.x !== node.x || remoteNode.y !== node.y) { if (remoteNode.x !== node.x || remoteNode.y !== node.y|| remoteNode.w !== node.w || remoteNode.h !== node.h) {
remoteChanged = true; remoteChanged = true;
remoteChanges++; remoteChanges++;
} }
@ -790,7 +791,12 @@ RED.diff = (function() {
localCell.addClass("red-ui-diff-status-"+(localChanged?"changed":"unchanged")); localCell.addClass("red-ui-diff-status-"+(localChanged?"changed":"unchanged"));
$('<span class="red-ui-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell); $('<span class="red-ui-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(localCell); element = $('<span class="red-ui-diff-list-element"></span>').appendTo(localCell);
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y}, var localPosition = {x:localNode.x,y:localNode.y};
if (localNode.hasOwnProperty('w')) {
localPosition.w = localNode.w;
localPosition.h = localNode.h;
}
propertyElements['local.position'] = RED.utils.createObjectElement(localPosition,
{ {
path: "position", path: "position",
exposeApi: true, exposeApi: true,
@ -811,7 +817,12 @@ RED.diff = (function() {
if (remoteNode) { if (remoteNode) {
$('<span class="red-ui-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell); $('<span class="red-ui-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(remoteCell); element = $('<span class="red-ui-diff-list-element"></span>').appendTo(remoteCell);
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y}, var remotePosition = {x:remoteNode.x,y:remoteNode.y};
if (remoteNode.hasOwnProperty('w')) {
remotePosition.w = remoteNode.w;
remotePosition.h = remoteNode.h;
}
propertyElements['remote.position'] = RED.utils.createObjectElement(remotePosition,
{ {
path: "position", path: "position",
exposeApi: true, exposeApi: true,
@ -883,11 +894,11 @@ RED.diff = (function() {
} }
} }
} }
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))}); var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='w'&&p!=='h'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
if (def.defaults) { if (def.defaults) {
properties = properties.concat(Object.keys(def.defaults)); properties = properties.concat(Object.keys(def.defaults));
} }
if (node.type !== 'tab') { if (node.type !== 'tab' && node.type !== "group") {
properties = properties.concat(['inputLabels','outputLabels']); properties = properties.concat(['inputLabels','outputLabels']);
} }
if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) && if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) &&

View File

@ -744,7 +744,16 @@ RED.editor = (function() {
delete cn.__label__; delete cn.__label__;
}); });
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>'+RED._("editor.addNewType", {type:type})+'</option>'); var label = type;
if (typeof node_def.paletteLabel !== "undefined") {
try {
label = RED.utils.sanitize((typeof node_def.paletteLabel === "function" ? node_def.paletteLabel.call(node_def) : node_def.paletteLabel)||type);
} catch(err) {
console.log("Definition error: "+type+".paletteLabel",err);
}
}
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>'+RED._("editor.addNewType", {type:label})+'</option>');
window.setTimeout(function() { select.trigger("change");},50); window.setTimeout(function() { select.trigger("change");},50);
} }
} }

View File

@ -56,8 +56,12 @@
}); });
} }
if (!isSameObj(old_env, new_env)) { if (!isSameObj(old_env, new_env)) {
node.env = new_env;
editState.changes.env = node.env; editState.changes.env = node.env;
if (new_env.length === 0) {
delete node.env;
} else {
node.env = new_env;
}
editState.changed = true; editState.changed = true;
} }
} }

View File

@ -105,6 +105,7 @@ RED.search = (function() {
val = extractFlag(val,"unused",flags); val = extractFlag(val,"unused",flags);
val = extractFlag(val,"config",flags); val = extractFlag(val,"config",flags);
val = extractFlag(val,"subflow",flags); val = extractFlag(val,"subflow",flags);
val = extractFlag(val,"hidden",flags);
// uses:<node-id> // uses:<node-id>
val = extractValue(val,"uses",flags); val = extractValue(val,"uses",flags);
@ -150,7 +151,15 @@ RED.search = (function() {
continue; continue;
} }
} }
if (flags.hasOwnProperty("hidden")) {
// Only tabs can be hidden
if (node.node.type !== 'tab') {
continue
}
if (!RED.workspaces.isHidden(node.node.id)) {
continue
}
}
if (flags.hasOwnProperty("unused")) { if (flags.hasOwnProperty("unused")) {
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) || var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0) (isConfigNode && node.node.users.length === 0)

View File

@ -379,7 +379,7 @@ RED.sidebar.help = (function() {
var currentVersionParts = RED.settings.version.split("."); var currentVersionParts = RED.settings.version.split(".");
var tourVersionParts = tour.version.split("."); var tourVersionParts = tour.version.split(".");
if (tourVersionParts[0] === currentVersionParts[0] && tourVersionParts[1] === currentVersionParts[1]) { if (tourVersionParts[0] === currentVersionParts[0] && tourVersionParts[1] === currentVersionParts[1]) {
tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">Take a tour</button></div>' tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">' + RED._("tourGuide.takeATour") + '</button></div>';
} }
} }
var aboutHeader = '<div style="text-align:center;">'+tourHeader+'</div>' var aboutHeader = '<div style="text-align:center;">'+tourHeader+'</div>'

View File

@ -175,6 +175,7 @@ RED.sidebar.info.outliner = (function() {
n.d = true; n.d = true;
} }
n.dirty = true; n.dirty = true;
n.dirtyStatus = true;
n.changed = true; n.changed = true;
RED.events.emit("nodes:change",n); RED.events.emit("nodes:change",n);
groupHistoryEvent.events.push(historyEvent); groupHistoryEvent.events.push(historyEvent);
@ -203,6 +204,7 @@ RED.sidebar.info.outliner = (function() {
n.d = true; n.d = true;
} }
n.dirty = true; n.dirty = true;
n.dirtyStatus = true;
n.changed = true; n.changed = true;
RED.events.emit("nodes:change",n); RED.events.emit("nodes:change",n);
RED.history.push(historyEvent); RED.history.push(historyEvent);
@ -272,6 +274,7 @@ RED.sidebar.info.outliner = (function() {
{label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"}, {label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"},
{label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"}, {label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"},
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"}, {label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
{label:RED._("sidebar.info.search.hiddenFlows"), value:"is:hidden"},
] ]
}); });

View File

@ -364,6 +364,8 @@ RED.tourGuide = (function() {
if (step.fallback) { if (step.fallback) {
focus.one("mouseenter", function(evt) { focus.one("mouseenter", function(evt) {
setTimeout(function() { setTimeout(function() {
var pos = targetElement[0].getBoundingClientRect();
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
focus.css({ focus.css({
width: (4*dimension)+"px", width: (4*dimension)+"px",
height: (4*dimension)+"px" height: (4*dimension)+"px"

View File

@ -142,6 +142,8 @@ RED.utils = (function() {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function'); result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function');
} else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) { } else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data); result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
} else if (value.hasOwnProperty('type') && value.type === 'regexp') {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>').text(value.data);
} else { } else {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>'); result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
} }
@ -440,6 +442,8 @@ RED.utils = (function() {
$('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj); $('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj);
} else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) { } else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) {
e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj); e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj);
} else if (typeHint === "regexp" || (obj.__enc__ && obj.type === 'regexp')) {
e = $('<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>').text((typeof obj === "string")?obj:obj.data).appendTo(entryObj);
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) { } else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj); e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj);
} else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) { } else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) {

View File

@ -3675,7 +3675,11 @@ RED.view = (function() {
nodeEl = document.getElementById(d.id); nodeEl = document.getElementById(d.id);
} }
if (nodeEl) { if (nodeEl) {
if (!showStatus || !d.status) { // Do not show node status if:
// - global flag set
// - node has no status
// - node is disabled
if (!showStatus || !d.status || d.d === true) {
nodeEl.__statusGroup__.style.display = "none"; nodeEl.__statusGroup__.style.display = "none";
} else { } else {
nodeEl.__statusGroup__.style.display = "inline"; nodeEl.__statusGroup__.style.display = "inline";
@ -4421,6 +4425,9 @@ RED.view = (function() {
n.selected = true; n.selected = true;
n.dirty = true; n.dirty = true;
movingSet.add(n); movingSet.add(n);
if (targets.length === 1) {
RED.view.reveal(n.id);
}
}); });
updateSelection(); updateSelection();
redraw(); redraw();
@ -5029,6 +5036,7 @@ RED.view = (function() {
delete node.d; delete node.d;
} }
node.dirty = true; node.dirty = true;
node.dirtyStatus = true;
node.changed = true; node.changed = true;
RED.events.emit("nodes:change",node); RED.events.emit("nodes:change",node);
} }

View File

@ -218,55 +218,64 @@ RED.workspaces = (function() {
scrollable: true, scrollable: true,
addButton: "core:add-flow", addButton: "core:add-flow",
addButtonCaption: RED._("workspace.addFlow"), addButtonCaption: RED._("workspace.addFlow"),
menu: [ menu: function() {
{ var menuItems = [
id:"red-ui-tabs-menu-option-search-flows", {
label: RED._("workspace.listFlows"), id:"red-ui-tabs-menu-option-search-flows",
onselect: "core:list-flows" label: RED._("workspace.listFlows"),
}, onselect: "core:list-flows"
{ },
id:"red-ui-tabs-menu-option-search-subflows", {
label: RED._("workspace.listSubflows"), id:"red-ui-tabs-menu-option-search-subflows",
onselect: "core:list-subflows" label: RED._("workspace.listSubflows"),
}, onselect: "core:list-subflows"
null, },
{ null,
id:"red-ui-tabs-menu-option-add-flow", {
label: RED._("workspace.addFlow"), id:"red-ui-tabs-menu-option-add-flow",
onselect: "core:add-flow" label: RED._("workspace.addFlow"),
}, onselect: "core:add-flow"
{ },
id:"red-ui-tabs-menu-option-add-flow-right", {
label: RED._("workspace.addFlowToRight"), id:"red-ui-tabs-menu-option-add-flow-right",
onselect: "core:add-flow-to-right" label: RED._("workspace.addFlowToRight"),
}, onselect: "core:add-flow-to-right"
null, },
{ null,
id:"red-ui-tabs-menu-option-add-hide-flows", {
label: RED._("workspace.hideFlow"), id:"red-ui-tabs-menu-option-add-hide-flows",
onselect: "core:hide-flow" label: RED._("workspace.hideFlow"),
}, onselect: "core:hide-flow"
{ },
id:"red-ui-tabs-menu-option-add-hide-other-flows", {
label: RED._("workspace.hideOtherFlows"), id:"red-ui-tabs-menu-option-add-hide-other-flows",
onselect: "core:hide-other-flows" label: RED._("workspace.hideOtherFlows"),
}, onselect: "core:hide-other-flows"
{ },
id:"red-ui-tabs-menu-option-add-show-all-flows", {
label: RED._("workspace.showAllFlows"), id:"red-ui-tabs-menu-option-add-show-all-flows",
onselect: "core:show-all-flows" label: RED._("workspace.showAllFlows"),
}, onselect: "core:show-all-flows"
{ },
id:"red-ui-tabs-menu-option-add-hide-all-flows", {
label: RED._("workspace.hideAllFlows"), id:"red-ui-tabs-menu-option-add-hide-all-flows",
onselect: "core:hide-all-flows" label: RED._("workspace.hideAllFlows"),
}, onselect: "core:hide-all-flows"
{ },
id:"red-ui-tabs-menu-option-add-show-last-flow", {
label: RED._("workspace.showLastHiddenFlow"), id:"red-ui-tabs-menu-option-add-show-last-flow",
onselect: "core:show-last-hidden-flow" label: RED._("workspace.showLastHiddenFlow"),
onselect: "core:show-last-hidden-flow"
}
]
if (hideStack.length > 0) {
menuItems.unshift({
label: RED._("workspace.hiddenFlows",{count: hideStack.length}),
onselect: "core:list-hidden-flows"
})
} }
] return menuItems;
}
}); });
workspaceTabCount = 0; workspaceTabCount = 0;
} }
@ -406,7 +415,9 @@ RED.workspaces = (function() {
} }
} }
}) })
RED.actions.add("core:list-hidden-flows",function() {
RED.actions.invoke("core:search","is:hidden ");
})
RED.actions.add("core:list-flows",function() { RED.actions.add("core:list-flows",function() {
RED.actions.invoke("core:search","type:tab "); RED.actions.invoke("core:search","type:tab ");
}) })
@ -450,7 +461,7 @@ RED.workspaces = (function() {
var changes = { disabled: workspace.disabled }; var changes = { disabled: workspace.disabled };
workspace.disabled = disabled; workspace.disabled = disabled;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled); $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
if (id || activeWorkspace) { if (!id || (id === activeWorkspace)) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled); $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
} }
var historyEvent = { var historyEvent = {
@ -536,6 +547,9 @@ RED.workspaces = (function() {
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs)); RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
} }
}, },
isHidden: function(id) {
return hideStack.includes(id)
},
show: function(id,skipStack,unhideOnly) { show: function(id,skipStack,unhideOnly) {
if (!workspace_tabs.contains(id)) { if (!workspace_tabs.contains(id)) {
var sf = RED.nodes.subflow(id); var sf = RED.nodes.subflow(id);

View File

@ -197,6 +197,7 @@ $view-select-mode-background: $secondary-background-selected;
$view-grid-color: #eee; $view-grid-color: #eee;
$node-label-color: #333; $node-label-color: #333;
$node-port-label-color: #888;
$node-border: #999; $node-border: #999;
$node-border-unknown: #f33; $node-border-unknown: #f33;
$node-border-placeholder: #aaa; $node-border-placeholder: #aaa;

View File

@ -47,7 +47,7 @@
.red-ui-flow-port-label { .red-ui-flow-port-label {
stroke-width: 0; stroke-width: 0;
fill: $secondary-text-color; fill: $node-port-label-color;
font-size: 16px; font-size: 16px;
dominant-baseline: middle; dominant-baseline: middle;
text-anchor: middle; text-anchor: middle;

View File

@ -187,7 +187,7 @@
ul.red-ui-menu-dropdown { ul.red-ui-menu-dropdown {
background: $header-menu-background; background: $header-menu-background;
border: 1px solid $header-menu-background; border: 1px solid $header-menu-background;
width: 250px !important; width: 260px !important;
margin-top: 0; margin-top: 0;
li a { li a {
color: $header-menu-color; color: $header-menu-color;

View File

@ -389,7 +389,19 @@ i.red-ui-tab-icon {
vertical-align: top; vertical-align: top;
} }
.red-ui-tab-hide {
.fa-eye-slash {
display: none;
}
&:hover {
.fa-eye-slash {
display: inline
}
.fa-eye {
display: none
}
}
}
.red-ui-tab-close { .red-ui-tab-close {
display: none; display: none;
background: $tab-background-inactive; background: $tab-background-inactive;

View File

@ -1,14 +1,23 @@
export default { export default {
steps: [ steps: [
{ {
title: "Create your first flow", title: {
'en-US': 'Create your first flow',
'ja': 'はじめてのフローを作成'
},
width: 400, width: 400,
description: 'This tutorial will guide you through creating your first flow', description: {
'en-US': 'This tutorial will guide you through creating your first flow',
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
},
nextButton: 'start' nextButton: 'start'
}, },
{ {
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add", element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
description: 'To add a new tab, click the <i class="fa fa-plus"></i> button', description: {
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
},
wait: { wait: {
type: "dom-event", type: "dom-event",
event: "click", event: "click",
@ -18,7 +27,10 @@ export default {
{ {
element: '.red-ui-palette-node[data-palette-type="inject"]', element: '.red-ui-palette-node[data-palette-type="inject"]',
direction: 'right', direction: 'right',
description: 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.', description: {
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
'ja': 'パレットには、利用できる全てのードが一覧表示されます。injectードをワークスペースにドラッグします。'
},
fallback: 'inset-bottom-right', fallback: 'inset-bottom-right',
wait: { wait: {
type: "nr-event", type: "nr-event",
@ -38,7 +50,10 @@ export default {
{ {
element: '.red-ui-palette-node[data-palette-type="debug"]', element: '.red-ui-palette-node[data-palette-type="debug"]',
direction: 'right', direction: 'right',
description: 'Next, drag a new Debug node into the workspace.', description: {
'en-US': 'Next, drag a new Debug node into the workspace.',
'ja': '次に、debugードをワークスペースにドラッグします。'
},
fallback: 'inset-bottom-right', fallback: 'inset-bottom-right',
wait: { wait: {
type: "nr-event", type: "nr-event",
@ -57,7 +72,10 @@ export default {
}, },
{ {
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") }, element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
description: 'Add a wire from the output of the Inject node to the input of the Debug node', description: {
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
'ja': 'injectードの出力から、debugードの入力へワイヤーで接続します。'
},
fallback: 'inset-bottom-right', fallback: 'inset-bottom-right',
wait: { wait: {
type: "nr-event", type: "nr-event",
@ -69,7 +87,10 @@ export default {
}, },
{ {
element: "#red-ui-header-button-deploy", element: "#red-ui-header-button-deploy",
description: 'Deploy your changes so the flow is active in the runtime', description: {
'en-US': 'Deploy your changes so the flow is active in the runtime',
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
},
width: 200, width: 200,
wait: { wait: {
type: "dom-event", type: "dom-event",

View File

@ -3,48 +3,79 @@ export default {
steps: [ steps: [
{ {
titleIcon: "fa fa-map-o", titleIcon: "fa fa-map-o",
title: { "en-US": "Welcome to Node-RED 2.1!" }, title: {
description: { "en-US": "Let's take a moment to discover the new features in this release." } "en-US": "Welcome to Node-RED 2.1!",
"ja": "Node-RED 2.1へようこそ!"
},
description: {
"en-US": "Let's take a moment to discover the new features in this release.",
"ja": "本リリースの新機能を見つけてみましょう。"
}
}, },
{ {
title: { "en-US": "A new Tour Guide" }, title: {
description: { "en-US": "<p>First, as you've already found, we now have this tour of new features. We'll only show the tour the first time you open the editor for each new version of Node-RED.</p>"+ "en-US": "A new Tour Guide",
"<p>You can choose not to see this tour in the future by disabling it under the View tab of User Settings.</p>" } "ja": "新しいツアーガイド"
},
description: {
"en-US": "<p>First, as you've already found, we now have this tour of new features. We'll only show the tour the first time you open the editor for each new version of Node-RED.</p>" +
"<p>You can choose not to see this tour in the future by disabling it under the View tab of User Settings.</p>",
"ja": "<p>最初に、既に見つけている様に、新機能の本ツアーがあります。本ツアーは、新バージョンのNode-REDフローエディタを初めて開いた時のみ表示されます。</p>" +
"<p>ユーザ設定の表示タブの中で、この機能を無効化することで、本ツアーを表示しないようにすることもできます。</p>"
}
}, },
{ {
title: { "en-US": "New Edit menu" }, title: {
"en-US": "New Edit menu",
"ja": "新しい編集メニュー"
},
prepare() { prepare() {
$("#red-ui-header-button-sidemenu").trigger("click"); $("#red-ui-header-button-sidemenu").trigger("click");
$("#menu-item-edit-menu").parent().addClass("open") $("#menu-item-edit-menu").parent().addClass("open");
}, },
complete() { complete() {
$("#menu-item-edit-menu").parent().removeClass("open") $("#menu-item-edit-menu").parent().removeClass("open");
}, },
element: "#menu-item-edit-menu-submenu", element: "#menu-item-edit-menu-submenu",
interactive: false, interactive: false,
direction: "left", direction: "left",
description: { "en-US": "<p>The main menu has been updated with a new 'Edit' section. This includes all of the familar options, like cut/paste and undo/redo.</p>"+ description: {
"<p>The menu now displays keyboard shortcuts for the options.</p>" } "en-US": "<p>The main menu has been updated with a new 'Edit' section. This includes all of the familar options, like cut/paste and undo/redo.</p>" +
"<p>The menu now displays keyboard shortcuts for the options.</p>",
"ja": "<p>メインメニューに「編集」セクションが追加されました。本セクションには、切り取り/貼り付けや、変更操作を戻す/やり直しの様な使い慣れたオプションが含まれています。</p>" +
"<p>本メニューには、オプションのためのキーボードショートカットも表示されるようになりました。</p>"
}
}, },
{ {
title: { "en-US": "Arranging nodes" }, title: {
"en-US": "Arranging nodes",
"ja": "ノードの配置"
},
prepare() { prepare() {
$("#red-ui-header-button-sidemenu").trigger("click"); $("#red-ui-header-button-sidemenu").trigger("click");
$("#menu-item-arrange-menu").parent().addClass("open") $("#menu-item-arrange-menu").parent().addClass("open");
}, },
complete() { complete() {
$("#menu-item-arrange-menu").parent().removeClass("open") $("#menu-item-arrange-menu").parent().removeClass("open");
}, },
element: "#menu-item-arrange-menu-submenu", element: "#menu-item-arrange-menu-submenu",
interactive: false, interactive: false,
direction: "left", direction: "left",
description: { "en-US": "<p>The new 'Arrange' section of the menu provides new options to help arrange your nodes. You can align them to a common edge, spread them out evenly or change their order.</p>" }, description: {
"en-US": "<p>The new 'Arrange' section of the menu provides new options to help arrange your nodes. You can align them to a common edge, spread them out evenly or change their order.</p>",
"ja": "<p>メニューの新しい「配置」セクションには、ノードの配置を助ける新しいオプションが提供されています。ノードの端を揃えたり、均等に配置したり、表示順序を変更したりできます。</p>"
}
}, },
{ {
title: { "en-US": "Hiding tabs" }, title: {
"en-US": "Hiding tabs",
"ja": "タブの非表示"
},
element: "#red-ui-workspace-tabs > li.active", element: "#red-ui-workspace-tabs > li.active",
description: { "en-US": '<p>Tabs can now be hidden by clicking their <i class="fa fa-times"></i> icon.</p><p>The Info Sidebar will still list all of your tabs, and tell you which ones are currently hidden.' }, description: {
"en-US": '<p>Tabs can now be hidden by clicking their <i class="fa fa-times"></i> icon.</p><p>The Info Sidebar will still list all of your tabs, and tell you which ones are currently hidden.',
"ja": '<p><i class="fa fa-times"></i> アイコンをクリックすることで、タブを非表示にできます。</p><p>情報サイドバーには、全てのタブが一覧表示されており、現在非表示になっているタブを確認できます。'
},
interactive: false, interactive: false,
prepare() { prepare() {
$("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","block"); $("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","block");
@ -54,9 +85,15 @@ export default {
} }
}, },
{ {
title: { "en-US": "Tab menu" }, title: {
"en-US": "Tab menu",
"ja": "タブメニュー"
},
element: "#red-ui-workspace-tabs-menu", element: "#red-ui-workspace-tabs-menu",
description: { "en-US": '<p>The new tab menu also provides lots of new options for your tabs.</p>' }, description: {
"en-US": "<p>The new tab menu also provides lots of new options for your tabs.</p>",
"ja": "<p>新しいタブメニューには、タブに関する沢山の新しいオプションが提供されています。</p>"
},
interactive: false, interactive: false,
direction: "left", direction: "left",
prepare() { prepare() {
@ -67,10 +104,16 @@ export default {
} }
}, },
{ {
title: { "en-US": "Flow and Group level environment variables" }, title: {
"en-US": "Flow and Group level environment variables",
"ja": "フローとグループの環境変数"
},
element: "#red-ui-workspace-tabs > li.active", element: "#red-ui-workspace-tabs > li.active",
interactive: false, interactive: false,
description: { "en-US": "<p>Flows and Groups can now have their own environment variables that can be referenced by nodes inside them.</p>" }, description: {
"en-US": "<p>Flows and Groups can now have their own environment variables that can be referenced by nodes inside them.</p>",
"ja": "<p>フローとグループには、内部のノードから参照できる環境変数を設定できるようになりました。</p>"
}
}, },
{ {
prepare(done) { prepare(done) {
@ -78,20 +121,28 @@ export default {
setTimeout(done,700); setTimeout(done,700);
}, },
element: "#red-ui-tab-editor-tab-envProperties-link-button", element: "#red-ui-tab-editor-tab-envProperties-link-button",
description: { "en-US": "<p>Their edit dialogs have a new Environment Variables section.</p>" }, description: {
"en-US": "<p>Their edit dialogs have a new Environment Variables section.</p>",
"ja": "<p>編集ダイアログに環境変数セクションが追加されました。</p>"
}
}, },
{ {
element: ".node-input-env-container-row", element: ".node-input-env-container-row",
direction: "left", direction: "left",
description: { "en-US": '<p>The environment variables are listed in this table and new ones can be added by clicking the <i class="fa fa-plus"></i> button.</p>' }, description: {
"en-US": '<p>The environment variables are listed in this table and new ones can be added by clicking the <i class="fa fa-plus"></i> button.</p>',
"ja": '<p>この表に環境変数が一覧表示されており、<i class="fa fa-plus"></i>ボタンをクリックすることで新しい変数を追加できます。</p>'
},
complete(done) { complete(done) {
$("#node-dialog-cancel").trigger("click"); $("#node-dialog-cancel").trigger("click");
setTimeout(done,500); setTimeout(done,500);
} }
}, },
{ {
title: {"en-US":"Link Call node added"}, title: {
"en-US": "Link Call node added",
"ja": "Link Callードを追加"
},
prepare(done) { prepare(done) {
this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed"); this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed");
RED.actions.invoke("core:toggle-palette",true) RED.actions.invoke("core:toggle-palette",true)
@ -100,22 +151,34 @@ export default {
}, },
element: '[data-palette-type="link call"]', element: '[data-palette-type="link call"]',
direction: "right", direction: "right",
description: { "en-US": '<p>The <code>Link Call</code> node lets you call another flow that begins with a <code>Link In</code> node and get the result back when the message reaches a <code>Link Out</code> node.</p>' }, description: {
"en-US": "<p>The <code>Link Call</code> node lets you call another flow that begins with a <code>Link In</code> node and get the result back when the message reaches a <code>Link Out</code> node.</p>",
"ja": "<p><code>Link Call</code>ノードを用いることで、<code>Link In</code>ノードから始まるフローを呼び出し、<code>Link Out</code>ノードに到達した時に、結果を取得できます。</p>"
}
}, },
{ {
title: {"en-US":"MQTT nodes support dynamic connections"}, title: {
"en-US": "MQTT nodes support dynamic connections",
"ja": "MQTTードが動的接続をサポート"
},
prepare(done) { prepare(done) {
$('[data-palette-type="mqtt out"]')[0].scrollIntoView({block:"center"}) $('[data-palette-type="mqtt out"]')[0].scrollIntoView({block:"center"})
setTimeout(done,100); setTimeout(done,100);
}, },
element: '[data-palette-type="mqtt out"]', element: '[data-palette-type="mqtt out"]',
direction: "right", direction: "right",
description: { "en-US": '<p>The <code>MQTT</code> nodes now support creating their connections and subscriptions dynamically.</p>' }, description: {
"en-US": '<p>The <code>MQTT</code> nodes now support creating their connections and subscriptions dynamically.</p>',
"ja": '<p><code>MQTT</code>ノードは、動的な接続や購読ができるようになりました。</p>'
},
}, },
{ {
title: {"en-US":"File nodes renamed"}, title: {
"en-US": "File nodes renamed",
"ja": "ファイルノードの名前変更"
},
prepare(done) { prepare(done) {
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"}) $('[data-palette-type="file"]')[0].scrollIntoView({block:"center"});
setTimeout(done,100); setTimeout(done,100);
}, },
complete() { complete() {
@ -125,13 +188,19 @@ export default {
}, },
element: '[data-palette-type="file"]', element: '[data-palette-type="file"]',
direction: "right", direction: "right",
description: { "en-US": '<p>The file nodes have been renamed to make it clearer which node does what.</p>' }, description: {
"en-US": "<p>The file nodes have been renamed to make it clearer which node does what.</p>",
"ja": "<p>fileードの名前が変更され、どのードが何を行うかが明確になりました。</p>"
}
}, },
{ {
title: {"en-US":"Deep copy option on Change node"}, title: {
"en-US": "Deep copy option on Change node",
"ja": "Changeードのディープコピーオプション"
},
prepare(done) { prepare(done) {
var def = RED.nodes.getType('change') var def = RED.nodes.getType('change');
RED.editor.edit({id:"test",type:"change",rules:[{t:'set',p:'payload',pt:'msg', tot:'msg',to:"anotherProperty"}],_def:def, _:def._}) RED.editor.edit({id:"test",type:"change",rules:[{t:"set",p:"payload",pt:"msg", tot:"msg",to:"anotherProperty"}],_def:def, _:def._});
setTimeout(done,700); setTimeout(done,700);
}, },
complete(done) { complete(done) {
@ -139,13 +208,22 @@ export default {
setTimeout(done,500); setTimeout(done,500);
}, },
element: function() { element: function() {
return $(".node-input-rule-property-deepCopy").next() return $(".node-input-rule-property-deepCopy").next();
}, },
description: { "en-US": '<p>The Set rule has a new option to create a deep copy of the value. This ensures a complete copy is made, rather than using a reference.</p>' }, description: {
"en-US": "<p>The Set rule has a new option to create a deep copy of the value. This ensures a complete copy is made, rather than using a reference.</p>",
"ja": "<p>値を代入に、値のディープコピーを作成するオプションが追加されました。これによって参照ではなく、完全なコピーが作成されます。</p>"
}
}, },
{ {
title: { "en-US": "And that's not all..." }, title: {
description: { "en-US": "<p>There are many more smaller changes, including:</p><ul><li>Auto-complete suggestions in the <code>msg</code> TypedInput.</li><li>Support for <code>msg.resetTimeout</code> in the <code>Join</code> node.</li><li>Pushing messages to the front of the queue in the <code>Delay</code> node's rate limiting mode.</li><li>An optional second output on the <code>Delay</code> node for rate limited messages.</li></ul>" } "en-US": "And that's not all...",
"ja": "これが全てではありません..."
},
description: {
"en-US": "<p>There are many more smaller changes, including:</p><ul><li>Auto-complete suggestions in the <code>msg</code> TypedInput.</li><li>Support for <code>msg.resetTimeout</code> in the <code>Join</code> node.</li><li>Pushing messages to the front of the queue in the <code>Delay</code> node's rate limiting mode.</li><li>An optional second output on the <code>Delay</code> node for rate limited messages.</li></ul>",
"ja": "<p>以下の様な小さな変更が沢山あります:</p><ul><li><code>msg</code> TypedInputの自動補完提案</li><li><code>Join</code>ノードで<code>msg.resetTimeout</code>のサポート</li><li><code>Delay</code>ノードの流量制御モードにおいて先頭メッセージをキューに追加</li><li><code>Delay</code>ードで流量制限されたメッセージ向けの任意の2つ目の出力</li></ul>"
}
} }
] ]
} }

View File

@ -280,6 +280,18 @@ module.exports = function(RED) {
root: path.join(__dirname,"lib","debug"), root: path.join(__dirname,"lib","debug"),
dotfiles: 'deny' dotfiles: 'deny'
}; };
res.sendFile(req.params[0], options); try {
res.sendFile(
req.params[0],
options,
err => {
if (err) {
res.sendStatus(404);
}
}
)
} catch(err) {
res.sendStatus(404);
}
}); });
}; };

View File

@ -372,6 +372,7 @@ module.exports = function(RED) {
hit = false; hit = false;
for (var b in node.buffer) { // check if already in queue for (var b in node.buffer) { // check if already in queue
if (msg.topic === node.buffer[b].msg.topic) { if (msg.topic === node.buffer[b].msg.topic) {
if (node.outputs === 2) { send([null,node.buffer[b].msg]) }
node.buffer[b].done(); node.buffer[b].done();
node.buffer[b] = {msg, send, done}; // if so - replace existing entry node.buffer[b] = {msg, send, done}; // if so - replace existing entry
hit = true; hit = true;

View File

@ -851,7 +851,6 @@
"outputas": "Ausgabe", "outputas": "Ausgabe",
"breakchunks": "In Chunks aufteilen", "breakchunks": "In Chunks aufteilen",
"breaklines": "In Linien aufteilen", "breaklines": "In Linien aufteilen",
"filelabel": "file",
"sendError": "Nachricht bei Fehler senden (herkömmlicher Modus)", "sendError": "Nachricht bei Fehler senden (herkömmlicher Modus)",
"encoding": "Kodierung", "encoding": "Kodierung",
"deletelabel": "lösche __file__", "deletelabel": "lösche __file__",

View File

@ -29,3 +29,12 @@
<p>linkード間のリンクはlinkードを選択した場合にのみ表示されます。他のタブへのリンクがある場合には、仮想的なードを表示します。この仮想的ードをクリックすると、対応するタブに移動できます。</p> <p>linkード間のリンクはlinkードを選択した場合にのみ表示されます。他のタブへのリンクがある場合には、仮想的なードを表示します。この仮想的ードをクリックすると、対応するタブに移動できます。</p>
<p><b>注: </b>サブフローの外から中、もしくは、中から外へのリンクを作成することはできません。</p> <p><b>注: </b>サブフローの外から中、もしくは、中から外へのリンクを作成することはできません。</p>
</script> </script>
<script type="text/html" data-help-name="link call">
<p><code>link in</code> で始まり、応答を返すフローを呼び出します。</p>
<h3>詳細</h3>
<p>本ノードは、任意のタブ内に存在する <code>link in</code> ノードに接続できます。 接続先のフローは、`返却`モードが設定された <code>link out</code> ノードで終了する必要があります。</p>
<p>本ノードはメッセージを受信すると、メッセージを接続した <code>link in</code> ノードへ渡します。
その後、応答を待った後にメッセージを送信します。</o>
<p>もし、設定したタイムアウト(デフォルト30秒)以内に応答がない場合は、<code>catch</code> ノードを用いてエラーをログに記録することもできます。</p>
</script>

View File

@ -144,11 +144,16 @@
"filterCurrent": "現在のフロー", "filterCurrent": "現在のフロー",
"debugNodes": "debugード", "debugNodes": "debugード",
"clearLog": "ログを削除", "clearLog": "ログを削除",
"clearFilteredLog": "選択したメッセージを削除",
"filterLog": "ログのフィルタリング", "filterLog": "ログのフィルタリング",
"openWindow": "新しいウィンドウで開く", "openWindow": "新しいウィンドウで開く",
"copyPath": "パスをコピー", "copyPath": "パスをコピー",
"copyPayload": "値をコピー", "copyPayload": "値をコピー",
"pinPath": "展開を固定" "pinPath": "展開を固定",
"selectAll": "全てを選択",
"selectNone": "選択を外す",
"all": "全て",
"filtered": "選択したメッセージ"
}, },
"messageMenu": { "messageMenu": {
"collapseAll": "全パスを折りたたむ", "collapseAll": "全パスを折りたたむ",
@ -159,7 +164,15 @@
}, },
"link": { "link": {
"linkIn": "link in", "linkIn": "link in",
"linkOut": "link out" "linkOut": "link out",
"linkCall": "link call",
"linkOutReturn": "link return",
"outMode": "モード",
"sendToAll": "接続された全てのlinkードへ送信",
"returnToCaller": "link callードへ返却",
"error": {
"missingReturn": "返却するノードの情報が存在しません"
}
}, },
"tls": { "tls": {
"tls": "TLS設定", "tls": "TLS設定",
@ -282,7 +295,9 @@
"and": "回/", "and": "回/",
"rate": "流量", "rate": "流量",
"msgper": "メッセージ/", "msgper": "メッセージ/",
"queuemsg": "中間メッセージをキューに追加",
"dropmsg": "中間メッセージを削除", "dropmsg": "中間メッセージを削除",
"sendmsg": "2番目の出力で中間メッセージを送信",
"allowrate": "msg.rate(ミリ秒単位)で流量値を上書き", "allowrate": "msg.rate(ミリ秒単位)で流量値を上書き",
"label": { "label": {
"delay": "delay", "delay": "delay",
@ -401,7 +416,11 @@
"maximumPacketSize": "最大パケット長", "maximumPacketSize": "最大パケット長",
"receiveMaximum": "最大受信数", "receiveMaximum": "最大受信数",
"session": "セッション", "session": "セッション",
"delay": "遅延" "delay": "遅延",
"action": "動作",
"staticTopic": "1つのトピックを購読",
"dynamicTopic": "動的な購読",
"auto-connect": "自動接続"
}, },
"sections-label": { "sections-label": {
"birth-message": "接続時の送信メッセージ(Birthメッセージ)", "birth-message": "接続時の送信メッセージ(Birthメッセージ)",
@ -442,7 +461,10 @@
"invalid-topic": "不正なトピックが設定されています", "invalid-topic": "不正なトピックが設定されています",
"nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません", "nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません",
"invalid-json-string": "不正なJSON文字列", "invalid-json-string": "不正なJSON文字列",
"invalid-json-parse": "JSON文字列のパースに失敗しました" "invalid-json-parse": "JSON文字列のパースに失敗しました",
"invalid-action-action": "指定された動作が不正です",
"invalid-action-alreadyconnected": "接続する前にブローカから切断してください",
"invalid-action-badsubscription": "msg.topicが存在しないか不正です"
} }
}, },
"httpin": { "httpin": {
@ -478,6 +500,7 @@
"proxy-config": "プロキシ設定", "proxy-config": "プロキシ設定",
"use-proxyauth": "プロキシ認証を使用", "use-proxyauth": "プロキシ認証を使用",
"noproxy-hosts": "例外ホスト", "noproxy-hosts": "例外ホスト",
"senderr": "2xx以外の応答をcatchードへ送信",
"utf8": "UTF8文字列", "utf8": "UTF8文字列",
"binary": "バイナリバッファ", "binary": "バイナリバッファ",
"json": "JSONオブジェクト", "json": "JSONオブジェクト",
@ -703,13 +726,15 @@
"delete": "delete __property__", "delete": "delete __property__",
"move": "move __property__", "move": "move __property__",
"changeCount": "change: __count__ rules", "changeCount": "change: __count__ rules",
"regex": "正規表現を使用" "regex": "正規表現を使用",
"deepCopy": "値のディープコピー"
}, },
"action": { "action": {
"set": "値の代入", "set": "値の代入",
"change": "値の置換", "change": "値の置換",
"delete": "値の削除", "delete": "値の削除",
"move": "値の移動", "move": "値の移動",
"toValue": "対象の値",
"to": "対象の値", "to": "対象の値",
"search": "検索する文字列", "search": "検索する文字列",
"replace": "置換後の文字列" "replace": "置換後の文字列"
@ -851,6 +876,8 @@
}, },
"file": { "file": {
"label": { "label": {
"write": "write file",
"read": "read file",
"filename": "ファイル名", "filename": "ファイル名",
"action": "動作", "action": "動作",
"addnewline": "メッセージの入力のたびに改行を追加", "addnewline": "メッセージの入力のたびに改行を追加",
@ -858,7 +885,6 @@
"outputas": "出力形式", "outputas": "出力形式",
"breakchunks": "チャンクへ分割", "breakchunks": "チャンクへ分割",
"breaklines": "行へ分割", "breaklines": "行へ分割",
"filelabel": "file",
"sendError": "エラーメッセージを送信(互換モード)", "sendError": "エラーメッセージを送信(互換モード)",
"encoding": "文字コード", "encoding": "文字コード",
"deletelabel": "delete __file__", "deletelabel": "delete __file__",

View File

@ -771,7 +771,6 @@
"outputas": "출력형식", "outputas": "출력형식",
"breakchunks": "청크로 분할", "breakchunks": "청크로 분할",
"breaklines": "행으로 분할", "breaklines": "행으로 분할",
"filelabel": "file",
"sendError": "에러메세지를 송신(호환모드)", "sendError": "에러메세지를 송신(호환모드)",
"deletelabel": "delete __file__", "deletelabel": "delete __file__",
"utf8String": "UTF8문자열", "utf8String": "UTF8문자열",

View File

@ -816,7 +816,6 @@
"outputas": "Выход", "outputas": "Выход",
"breakchunks": "Разбить файл на части", "breakchunks": "Разбить файл на части",
"breaklines": "Разбить на строки", "breaklines": "Разбить на строки",
"filelabel": "файл",
"sendError": "Отправлять сообщение при ошибке (устаревший режим)", "sendError": "Отправлять сообщение при ошибке (устаревший режим)",
"encoding": "Кодировка", "encoding": "Кодировка",
"deletelabel": "удалить __file__", "deletelabel": "удалить __file__",

View File

@ -804,7 +804,6 @@
"outputas": "输出", "outputas": "输出",
"breakchunks": "分拆成块", "breakchunks": "分拆成块",
"breaklines": "分拆成行", "breaklines": "分拆成行",
"filelabel": "文件",
"sendError": "发生错误时发送消息(传统模式)", "sendError": "发生错误时发送消息(传统模式)",
"encoding": "编码", "encoding": "编码",
"deletelabel": "删除 __file__", "deletelabel": "删除 __file__",

View File

@ -809,7 +809,6 @@
"outputas": "輸出", "outputas": "輸出",
"breakchunks": "分拆成塊", "breakchunks": "分拆成塊",
"breaklines": "分拆成行", "breaklines": "分拆成行",
"filelabel": "文件",
"sendError": "發生錯誤時發送消息(傳統模式)", "sendError": "發生錯誤時發送消息(傳統模式)",
"encoding": "編碼", "encoding": "編碼",
"deletelabel": "刪除 __file__", "deletelabel": "刪除 __file__",

View File

@ -15,13 +15,13 @@
} }
], ],
"dependencies": { "dependencies": {
"acorn": "8.5.0", "acorn": "8.6.0",
"acorn-walk": "8.2.0", "acorn-walk": "8.2.0",
"ajv": "8.6.3", "ajv": "8.8.2",
"body-parser": "1.19.0", "body-parser": "1.19.0",
"cheerio": "1.0.0-rc.10", "cheerio": "1.0.0-rc.10",
"content-type": "1.0.4", "content-type": "1.0.4",
"cookie-parser": "1.4.5", "cookie-parser": "1.4.6",
"cookie": "0.4.1", "cookie": "0.4.1",
"cors": "2.8.5", "cors": "2.8.5",
"cronosjs": "1.7.1", "cronosjs": "1.7.1",
@ -29,7 +29,7 @@
"form-data": "4.0.0", "form-data": "4.0.0",
"fs-extra": "10.0.0", "fs-extra": "10.0.0",
"fs.notify": "0.0.4", "fs.notify": "0.0.4",
"got": "11.8.2", "got": "11.8.3",
"hash-sum": "2.0.0", "hash-sum": "2.0.0",
"hpagent": "0.1.2", "hpagent": "0.1.2",
"https-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.0",
@ -40,7 +40,7 @@
"multer": "1.4.3", "multer": "1.4.3",
"mustache": "4.2.0", "mustache": "4.2.0",
"on-headers": "1.0.2", "on-headers": "1.0.2",
"raw-body": "2.4.1", "raw-body": "2.4.2",
"tough-cookie": "4.0.0", "tough-cookie": "4.0.0",
"uuid": "8.3.2", "uuid": "8.3.2",
"ws": "7.5.1", "ws": "7.5.1",

View File

@ -21,6 +21,6 @@
"fs-extra": "10.0.0", "fs-extra": "10.0.0",
"semver": "7.3.5", "semver": "7.3.5",
"tar": "6.1.11", "tar": "6.1.11",
"uglify-js": "3.14.2" "uglify-js": "3.14.4"
} }
} }

View File

@ -439,8 +439,6 @@ class Flow {
} }
} }
return [env.name, env]; return [env.name, env];
return [env.name, env];
}); });
group._env = Object.fromEntries(entries); group._env = Object.fromEntries(entries);
} }
@ -457,24 +455,24 @@ class Flow {
const val const val
= ((value === "true") || = ((value === "true") ||
(value === true)); (value === true));
return { return [{
val: val val: val
}; }, null];
} }
if (type === "cred") { if (type === "cred") {
return { return [{
val: value val: value
}; }, null];
} }
try { try {
var val = redUtil.evaluateNodeProperty(value, type, node, null, null); var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
return { return [{
val: val val: val
}; }, null];
} }
catch (e) { catch (e) {
this.error(e); this.error(e);
return null; return [null, null];
} }
} }
} }
@ -488,7 +486,7 @@ class Flow {
return this.getGroupEnvSetting(node, parent, name); return this.getGroupEnvSetting(node, parent, name);
} }
} }
return null; return [null, name];
} }
@ -545,6 +543,9 @@ class Flow {
} }
} }
} }
else {
key = key.substring(8);
}
} }
return this.parent.getSetting(key); return this.parent.getSetting(key);
} }

View File

@ -373,10 +373,11 @@ class Subflow extends Flow {
const node = this.subflowInstance; const node = this.subflowInstance;
if (node.g) { if (node.g) {
const group = this.getGroupNode(node.g); const group = this.getGroupNode(node.g);
const result = this.getGroupEnvSetting(node, group, name); const [result, newName] = this.getGroupEnvSetting(node, group, name);
if (result) { if (result) {
return result.val; return result.val;
} }
name = newName;
} }

View File

@ -136,8 +136,6 @@ function getCurrentLocale() {
function init(settings) { function init(settings) {
if (!initPromise) { if (!initPromise) {
// Keep this as a 'when' promise as top-level red.js uses 'otherwise'
// and embedded users of NR may have copied that.
initPromise = new Promise((resolve,reject) => { initPromise = new Promise((resolve,reject) => {
i18n.use(MessageFileLoader); i18n.use(MessageFileLoader);
var opt = { var opt = {
@ -146,6 +144,8 @@ function init(settings) {
defaultNS: "runtime", defaultNS: "runtime",
ns: [], ns: [],
fallbackLng: defaultLang, fallbackLng: defaultLang,
keySeparator: ".",
nsSeparator: ":",
interpolation: { interpolation: {
unescapeSuffix: 'HTML', unescapeSuffix: 'HTML',
escapeValue: false, escapeValue: false,

View File

@ -526,10 +526,11 @@ function getSetting(node, name, flow_) {
if (flow) { if (flow) {
if (node && node.g) { if (node && node.g) {
const group = flow.getGroupNode(node.g); const group = flow.getGroupNode(node.g);
const result = flow.getGroupEnvSetting(node, group, name); const [result, newName] = flow.getGroupEnvSetting(node, group, name);
if (result) { if (result) {
return result.val; return result.val;
} }
name = newName;
} }
return flow.getSetting(name); return flow.getSetting(name);
} }
@ -842,6 +843,9 @@ function encodeObject(msg,opts) {
length: msg.msg.size length: msg.msg.size
} }
needsStringify = true; needsStringify = true;
} else if (msg.msg && msg.msg.constructor.name === "RegExp") {
msg.format = 'regexp';
msg.msg = msg.msg.toString();
} }
if (needsStringify || (msg.format === "Object")) { if (needsStringify || (msg.format === "Object")) {
msg.msg = safeJSONStringify(msg.msg, function(key, value) { msg.msg = safeJSONStringify(msg.msg, function(key, value) {
@ -907,6 +911,12 @@ function encodeObject(msg,opts) {
data: Object.fromEntries(Array.from(value.entries()).slice(0,debuglength)), data: Object.fromEntries(Array.from(value.entries()).slice(0,debuglength)),
length: value.size length: value.size
} }
} else if (value.constructor.name === "RegExp") {
value = {
__enc__: true,
type: "regexp",
data: value.toString()
}
} }
} else if (value === undefined) { } else if (value === undefined) {
value = { value = {

View File

@ -16,10 +16,10 @@
], ],
"dependencies": { "dependencies": {
"fs-extra": "10.0.0", "fs-extra": "10.0.0",
"i18next": "21.3.1", "i18next": "21.5.4",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
"jsonata": "1.8.5", "jsonata": "1.8.5",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"moment-timezone": "0.5.33" "moment-timezone": "0.5.34"
} }
} }

View File

@ -1275,6 +1275,52 @@ describe('Flow', function() {
} }
}); });
it("can access environment variable property using $parent", function (done) {
try {
after(function() {
delete process.env.V0;
delete process.env.V1;
})
process.env.V0 = "gv0";
process.env.V1 = "gv1";
var config = flowUtils.parseConfig([
{id:"t1",type:"tab",env:[
{"name": "V0", value: "v0", type: "str"}
]},
{id:"g1",type:"group",z:"t1",env:[
{"name": "V0", value: "v1", type: "str"},
{"name": "V1", value: "v2", type: "str"}
]},
{id:"g2",type:"group",z:"t1",g:"g1",env:[
{"name": "V1", value: "v3", type: "str"}
]},
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"${$parent.V0}",wires:[]},
{id:"2",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"${$parent.V0}",wires:[]},
{id:"3",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"${$parent.V1}",wires:[]},
{id:"4",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"${$parent.V1}",wires:[]},
{id:"5",x:10,y:10,z:"t1",type:"test",foo:"${$parent.V1}",wires:[]},
]);
var flow = Flow.create({getSetting:v=>process.env[v]},config,config.flows["t1"]);
flow.start();
var activeNodes = flow.getActiveNodes();
activeNodes["1"].foo.should.equal("gv0");
activeNodes["2"].foo.should.equal("v0");
activeNodes["3"].foo.should.equal("gv1");
activeNodes["4"].foo.should.equal("v2");
activeNodes["5"].foo.should.equal("gv1");
flow.stop().then(function() {
done();
});
}
catch (e) {
console.log(e.stack);
done(e);
}
});
}); });