mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
80 Commits
2.1.2
...
add-tls-op
Author | SHA1 | Date | |
---|---|---|---|
|
c9f03f1ac5 | ||
|
02bd292b8c | ||
|
e5f1029d0c | ||
|
cae247160f | ||
|
6692b1992c | ||
|
0937837b7f | ||
|
7cd3e49f04 | ||
|
173e75175e | ||
|
800006dd76 | ||
|
a824b6910a | ||
|
dcea382b38 | ||
|
d9f976baea | ||
|
1fa13efe19 | ||
|
33af5cd7c6 | ||
|
7cb8f97ef1 | ||
|
bf965a9cde | ||
|
17ffff685a | ||
|
ae76271cff | ||
|
8f3a96d615 | ||
|
30e750dfe5 | ||
|
682dff7c6f | ||
|
85415eb8a8 | ||
|
68a80b9244 | ||
|
c331da7323 | ||
|
04ffa06221 | ||
|
1f0690c6ec | ||
|
711467abcd | ||
|
9439cd0e3d | ||
|
314c19650d | ||
|
ed6afcd802 | ||
|
082d4fe8e1 | ||
|
cd23b44506 | ||
|
46b6b024b9 | ||
|
cb88cc35e5 | ||
|
75c0c44809 | ||
|
a091b82ba9 | ||
|
a3b8f022e6 | ||
|
279fcb7c51 | ||
|
49a9376073 | ||
|
96840ede56 | ||
|
7e7f481f99 | ||
|
3edbf52bc6 | ||
|
fba6e801fc | ||
|
720a163273 | ||
|
6ac0c0a367 | ||
|
300402d253 | ||
|
0d9bfae503 | ||
|
bfe0d3b8a3 | ||
|
5fdd9c0546 | ||
|
b6570a16b8 | ||
|
8e2d3ea16f | ||
|
bc2c81f058 | ||
|
3e0f080ea7 | ||
|
679e07189d | ||
|
a38ebef100 | ||
|
b8ad6475e1 | ||
|
0f0cb3ac6d | ||
|
d3efb9d7cc | ||
|
84a237d3f5 | ||
|
e6de52eede | ||
|
98aee964d7 | ||
|
570e5442e0 | ||
|
b77a2dc353 | ||
|
87af31de20 | ||
|
cfe201dbe1 | ||
|
6ccdab35e0 | ||
|
55b9f36b45 | ||
|
fbcb1130c9 | ||
|
d4f7a6d2bc | ||
|
8a19f71abe | ||
|
fb153757b5 | ||
|
4f175fc93e | ||
|
2d4ca7cec0 | ||
|
bf0ea89969 | ||
|
073f0c2a20 | ||
|
ba83be9062 | ||
|
2e7188ea4f | ||
|
5a012182d9 | ||
|
b55a8ef62a | ||
|
36f099d68b |
54
CHANGELOG.md
54
CHANGELOG.md
@@ -1,3 +1,57 @@
|
||||
#### 2.2.0-beta.1: Beta Release
|
||||
|
||||
|
||||
|
||||
#### 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
|
||||
|
||||
Runtime
|
||||
|
||||
- Update gen-publish script to update 'next' tag for main releases
|
||||
- Add environment variable to enable/disable tours (#3221) @hardillb
|
||||
- Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Refresh editor settings whenever a node is added or enabled (#3227) @knolleary
|
||||
- Revert spinner css change that made it shrink in some cases (#3229) @knolleary
|
||||
- Fix import notification message when importing config nodes (#3224) @knolleary
|
||||
- Handle changing types of TypedInput repeatedly (#3223) @knolleary
|
||||
|
||||
|
||||
#### 2.1.2: Maintenance Release
|
||||
|
||||
|
||||
|
26
package.json
26
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -26,9 +26,9 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"acorn": "8.5.0",
|
||||
"acorn": "8.6.0",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.6.3",
|
||||
"ajv": "8.8.2",
|
||||
"async-mutex": "0.3.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
@@ -37,7 +37,7 @@
|
||||
"clone": "2.1.2",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.1",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "2.0.1",
|
||||
@@ -46,11 +46,11 @@
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"got": "11.8.3",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "0.1.2",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"i18next": "21.3.1",
|
||||
"i18next": "21.5.4",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.1",
|
||||
@@ -60,22 +60,22 @@
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.6",
|
||||
"mime": "2.5.2",
|
||||
"moment-timezone": "0.5.33",
|
||||
"moment-timezone": "0.5.34",
|
||||
"mqtt": "4.2.8",
|
||||
"multer": "1.4.3",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^2.2.1",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.5.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.4.1",
|
||||
"raw-body": "2.4.2",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.11",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.14.2",
|
||||
"uglify-js": "3.14.4",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.1",
|
||||
"xml2js": "0.4.23"
|
||||
@@ -109,11 +109,11 @@
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "3.0.7",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "9.1.2",
|
||||
"mocha": "9.1.3",
|
||||
"node-red-node-test-helper": "^0.2.7",
|
||||
"nodemon": "2.0.13",
|
||||
"nodemon": "2.0.15",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.43.2",
|
||||
"sass": "1.44.0",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
|
@@ -141,7 +141,7 @@ function completeVerify(profile,done) {
|
||||
Users.authenticate(profile).then(function(user) {
|
||||
if (user) {
|
||||
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;
|
||||
done(null,user);
|
||||
});
|
||||
|
@@ -93,7 +93,7 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
|
||||
return logEntry.user !== username;
|
||||
});
|
||||
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});
|
||||
});
|
||||
} else {
|
||||
|
@@ -48,9 +48,10 @@ module.exports = {
|
||||
var prevLang = i18n.i.language;
|
||||
// Trigger a load from disk of the language if it is not the default
|
||||
i18n.i.changeLanguage(lang, function(){
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
i18n.i.changeLanguage(prevLang, function() {
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
});
|
||||
});
|
||||
i18n.i.changeLanguage(prevLang);
|
||||
}
|
||||
}
|
||||
|
@@ -228,6 +228,11 @@ module.exports = {
|
||||
if (theme.theme) {
|
||||
themeSettings.theme = theme.theme;
|
||||
}
|
||||
|
||||
if (theme.hasOwnProperty("tours")) {
|
||||
themeSettings.tours = theme.tours;
|
||||
}
|
||||
|
||||
return themeApp;
|
||||
},
|
||||
context: async function() {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.1.2",
|
||||
"@node-red/editor-client": "2.1.2",
|
||||
"@node-red/util": "2.2.0-beta.1",
|
||||
"@node-red/editor-client": "2.2.0-beta.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"clone": "2.1.2",
|
||||
@@ -28,7 +28,7 @@
|
||||
"mime": "2.5.2",
|
||||
"multer": "1.4.3",
|
||||
"mustache": "4.2.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.5.0",
|
||||
|
@@ -59,6 +59,8 @@
|
||||
"hideOtherFlows": "Hide other flows",
|
||||
"showAllFlows": "Show all flows",
|
||||
"hideAllFlows": "Hide all flows",
|
||||
"hiddenFlows": "List __count__ hidden flow",
|
||||
"hiddenFlows_plural": "List __count__ hidden flows",
|
||||
"showLastHiddenFlow": "Show last hidden flow",
|
||||
"listFlows": "List flows",
|
||||
"listSubflows": "List subflows",
|
||||
@@ -90,6 +92,7 @@
|
||||
"palette": {
|
||||
"show": "Show palette"
|
||||
},
|
||||
"edit": "Edit",
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"nodes": "Nodes",
|
||||
@@ -668,7 +671,8 @@
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows"
|
||||
"unusedSubflows": "Unused subflows",
|
||||
"hiddenFlows": "Hidden flows"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -1135,6 +1139,7 @@
|
||||
"defaultValue": "Default value"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "Take a tour",
|
||||
"start": "Start",
|
||||
"next": "Next"
|
||||
},
|
||||
|
@@ -54,7 +54,14 @@
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"addFlowToRight": "右側にフローを追加",
|
||||
"hideFlow": "フローを非表示",
|
||||
"hideOtherFlows": "他のフローを非表示",
|
||||
"showAllFlows": "全てのフローを表示",
|
||||
"hideAllFlows": "全てのフローを非表示",
|
||||
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
|
||||
"listFlows": "フロー一覧",
|
||||
"listSubflows": "サブフロー一覧",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
@@ -83,6 +90,7 @@
|
||||
"palette": {
|
||||
"show": "パレットを表示"
|
||||
},
|
||||
"edit": "編集",
|
||||
"settings": "設定",
|
||||
"userSettings": "ユーザ設定",
|
||||
"nodes": "ノード",
|
||||
@@ -105,6 +113,7 @@
|
||||
"editPalette": "パレットの管理",
|
||||
"other": "その他",
|
||||
"showTips": "ヒントを表示",
|
||||
"showWelcomeTours": "新バージョンのガイドツアーを表示",
|
||||
"help": "Node-REDウェブサイト",
|
||||
"projects": "プロジェクト",
|
||||
"projects-new": "新規",
|
||||
@@ -116,7 +125,20 @@
|
||||
"groupSelection": "選択部分をグループ化",
|
||||
"ungroupSelection": "選択部分をグループ解除",
|
||||
"groupMergeSelection": "選択部分をマージ",
|
||||
"groupRemoveSelection": "グループから削除"
|
||||
"groupRemoveSelection": "グループから削除",
|
||||
"arrange": "配置",
|
||||
"alignLeft": "左揃え",
|
||||
"alignCenter": "左右中央揃え",
|
||||
"alignRight": "右揃え",
|
||||
"alignTop": "上揃え",
|
||||
"alignMiddle": "上下中央揃え",
|
||||
"alignBottom": "下揃え",
|
||||
"distributeHorizontally": "左右に整列",
|
||||
"distributeVertically": "上下に整列",
|
||||
"moveToBack": "最背面へ移動",
|
||||
"moveToFront": "最前面へ移動",
|
||||
"moveBackwards": "背面へ移動",
|
||||
"moveForwards": "前面へ移動"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
@@ -451,7 +473,8 @@
|
||||
"global": "グローバル",
|
||||
"workspace": "ワークスペース",
|
||||
"selectAll": "全てのノードを選択",
|
||||
"selectAllConnected": "接続された全てのノードを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"selectAllConnected": "接続されたノードを選択",
|
||||
"addRemoveNode": "ノードの選択、選択解除",
|
||||
"editSelected": "選択したノードを編集",
|
||||
"deleteSelected": "選択したノードや接続を削除",
|
||||
@@ -461,10 +484,13 @@
|
||||
"moveNode": "選択したノードを移動(移動量大)",
|
||||
"toggleSidebar": "サイドバーの表示/非表示",
|
||||
"togglePalette": "パレットの表示/非表示",
|
||||
"copyNode": "選択したノードをコピー",
|
||||
"cutNode": "選択したノードを切り取り",
|
||||
"copyNode": "ノードをコピー",
|
||||
"cutNode": "ノードを切り取り",
|
||||
"pasteNode": "ノードを貼り付け",
|
||||
"copyGroupStyle": "グループ様式をコピー",
|
||||
"pasteGroupStyle": "グループ様式を貼り付け",
|
||||
"undoChange": "変更操作を戻す",
|
||||
"redoChange": "変更操作をやり直し",
|
||||
"searchBox": "ノードを検索",
|
||||
"managePalette": "パレットの管理",
|
||||
"actionList": "動作一覧"
|
||||
@@ -519,7 +545,8 @@
|
||||
"nodeEnabled_plural": "ノードを有効化しました:",
|
||||
"nodeDisabled": "ノードを無効化しました:",
|
||||
"nodeDisabled_plural": "ノードを無効化しました:",
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
|
||||
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
|
||||
},
|
||||
"editor": {
|
||||
"title": "パレットの管理",
|
||||
@@ -1108,6 +1135,11 @@
|
||||
"preview": "UIプレビュー",
|
||||
"defaultValue": "デフォルト値"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "ツアーを開始",
|
||||
"start": "開始",
|
||||
"next": "次へ"
|
||||
},
|
||||
"languages": {
|
||||
"de": "ドイツ語",
|
||||
"en-US": "英語",
|
||||
|
@@ -225,7 +225,7 @@
|
||||
"compact": "紧凑",
|
||||
"formatted": "已格式化",
|
||||
"copy": "导出到剪贴板",
|
||||
"export": "到处到库",
|
||||
"export": "导出到库",
|
||||
"exportAs": "导出为",
|
||||
"overwrite": "替换",
|
||||
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -38,6 +38,8 @@ RED.i18n = (function() {
|
||||
defaultNS: "editor",
|
||||
fallbackLng: ['en-US'],
|
||||
returnObjects: true,
|
||||
keySeparator: ".",
|
||||
nsSeparator: ":",
|
||||
interpolation: {
|
||||
unescapeSuffix: 'HTML',
|
||||
escapeValue: false,
|
||||
|
@@ -805,7 +805,6 @@ RED.nodes = (function() {
|
||||
var removedGroups = [];
|
||||
if (ws) {
|
||||
delete workspaces[id];
|
||||
allNodes.removeTab(id);
|
||||
delete linkTabMap[id];
|
||||
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
|
||||
var i;
|
||||
@@ -843,6 +842,7 @@ RED.nodes = (function() {
|
||||
for (i=removedGroups.length-1; i>=0; i--) {
|
||||
removeGroup(removedGroups[i]);
|
||||
}
|
||||
allNodes.removeTab(id);
|
||||
RED.events.emit('flows:remove',ws);
|
||||
}
|
||||
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
|
||||
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") {
|
||||
node.x = n.x;
|
||||
node.y = n.y;
|
||||
|
@@ -475,31 +475,33 @@ var RED = (function() {
|
||||
var typeList;
|
||||
var info;
|
||||
if (topic == "notification/node/added") {
|
||||
var addedTypes = [];
|
||||
msg.forEach(function(m) {
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
}
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
var addedTypes = [];
|
||||
msg.forEach(function(m) {
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
loadIconList();
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
loadIconList();
|
||||
})
|
||||
} else if (topic == "notification/node/removed") {
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
@@ -512,27 +514,29 @@ var RED = (function() {
|
||||
loadIconList();
|
||||
} else if (topic == "notification/node/enabled") {
|
||||
if (msg.types) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+msg.id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+msg.id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (topic == "notification/node/disabled") {
|
||||
if (msg.types) {
|
||||
@@ -586,7 +590,7 @@ var RED = (function() {
|
||||
{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-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"},
|
||||
null,
|
||||
|
@@ -125,7 +125,7 @@ RED.settings = (function () {
|
||||
load(done);
|
||||
}
|
||||
|
||||
var load = function(done) {
|
||||
var refreshSettings = function(done) {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
@@ -135,6 +135,23 @@ RED.settings = (function () {
|
||||
url: 'settings',
|
||||
success: function (data) {
|
||||
setProperties(data);
|
||||
done(null, data);
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { refreshSettings(done); });
|
||||
} else {
|
||||
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var load = function(done) {
|
||||
refreshSettings(function(err, data) {
|
||||
if (!err) {
|
||||
if (!RED.settings.user || RED.settings.user.anonymous) {
|
||||
RED.settings.remove("auth-tokens");
|
||||
}
|
||||
@@ -147,18 +164,8 @@ RED.settings = (function () {
|
||||
console.log("D3",d3.version);
|
||||
console.groupEnd();
|
||||
loadUserSettings(done);
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { load(done); });
|
||||
} else {
|
||||
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
function loadUserSettings(done) {
|
||||
@@ -234,6 +241,7 @@ RED.settings = (function () {
|
||||
init: init,
|
||||
load: load,
|
||||
loadUserSettings: loadUserSettings,
|
||||
refreshSettings: refreshSettings,
|
||||
set: set,
|
||||
get: get,
|
||||
remove: remove,
|
||||
|
@@ -21,7 +21,7 @@
|
||||
* value: String : the value to insert if selected
|
||||
* label: String|DOM Element : the label to display in the dropdown.
|
||||
* }
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
$.widget( "nodered.autoComplete", {
|
||||
@@ -62,7 +62,7 @@
|
||||
maxHeight: 200,
|
||||
class: "red-ui-autoComplete-container",
|
||||
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()}
|
||||
});
|
||||
this.menu.show({
|
||||
|
@@ -117,6 +117,8 @@ RED.tabs = (function() {
|
||||
menuOptions = options.menu()
|
||||
} else if (Array.isArray(options.menu)) {
|
||||
menuOptions = options.menu;
|
||||
} else if (typeof options.menu === 'function') {
|
||||
menuOptions = options.menu();
|
||||
}
|
||||
menu = RED.menu.init({options: menuOptions});
|
||||
menu.attr("id",options.id+"-menu");
|
||||
@@ -809,15 +811,18 @@ RED.tabs = (function() {
|
||||
event.preventDefault();
|
||||
removeTab(tab.id);
|
||||
});
|
||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||
}
|
||||
if (tab.hideable) {
|
||||
li.addClass("red-ui-tabs-closeable")
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
|
||||
closeLink.append('<i class="fa fa-times" />');
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
|
||||
closeLink.append('<i class="fa fa-eye" />');
|
||||
closeLink.append('<i class="fa fa-eye-slash" />');
|
||||
closeLink.on("click",function(event) {
|
||||
event.preventDefault();
|
||||
hideTab(tab.id);
|
||||
});
|
||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
link.attr("title",tab.label);
|
||||
// link.attr("title",tab.label);
|
||||
RED.popover.tooltip(link,function() { return tab.label})
|
||||
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
@@ -945,7 +951,6 @@ RED.tabs = (function() {
|
||||
renameTab: function(id,label) {
|
||||
tabs[id].label = label;
|
||||
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));
|
||||
updateTabWidths();
|
||||
},
|
||||
|
@@ -340,7 +340,7 @@
|
||||
if (child.depth !== parent.depth+1) {
|
||||
child.depth = parent.depth+1;
|
||||
// var labelPaddingWidth = ((child.gutter ? child.gutter[0].offsetWidth + 2 : 0) + (child.depth * 20));
|
||||
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
|
||||
var labelPaddingWidth = (((child.gutter&&!child.gutter.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*20));
|
||||
child.treeList.labelPadding.width(labelPaddingWidth+'px');
|
||||
if (child.element) {
|
||||
$(child.element).css({
|
||||
@@ -562,8 +562,9 @@
|
||||
}).appendTo(label)
|
||||
|
||||
}
|
||||
// var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
|
||||
var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (depth * 20)
|
||||
|
||||
var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*20);
|
||||
|
||||
item.treeList.labelPadding = $('<span>').css({
|
||||
display: "inline-block",
|
||||
"flex-shrink": 0,
|
||||
|
@@ -556,7 +556,7 @@
|
||||
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.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;
|
||||
}catch(err) {
|
||||
console.log(err.stack);
|
||||
@@ -805,6 +805,7 @@
|
||||
var that = this;
|
||||
var currentType = this.type();
|
||||
this.typeMap = {};
|
||||
var firstCall = (this.typeList === undefined);
|
||||
this.typeList = types.map(function(opt) {
|
||||
var result;
|
||||
if (typeof opt === 'string') {
|
||||
@@ -829,10 +830,14 @@
|
||||
}
|
||||
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
|
||||
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
|
||||
this.type(this.typeList[0].value);
|
||||
if (!firstCall) {
|
||||
this.type(this.typeList[0].value);
|
||||
}
|
||||
} else {
|
||||
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)) {
|
||||
this.selectTrigger.hide()
|
||||
@@ -923,7 +928,7 @@
|
||||
var previousType = this.typeMap[this.propertyType];
|
||||
previousValue = this.input.val();
|
||||
|
||||
if (this.typeChanged) {
|
||||
if (previousType && this.typeChanged) {
|
||||
if (this.options.debug) { console.log(this.identifier,"typeChanged",{previousType,previousValue}) }
|
||||
if (previousType.options && opt.hasValue !== true) {
|
||||
this.oldValues[previousType.value] = previousValue;
|
||||
|
@@ -554,6 +554,8 @@ RED.diff = (function() {
|
||||
color: "#DDAA99",
|
||||
defaults:{name:{value:""}}
|
||||
}
|
||||
} else if (node.type === "group") {
|
||||
def = RED.group.def;
|
||||
} else {
|
||||
def = {};
|
||||
}
|
||||
@@ -763,16 +765,15 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (node.hasOwnProperty('x')) {
|
||||
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;
|
||||
localChanges++;
|
||||
}
|
||||
}
|
||||
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;
|
||||
remoteChanges++;
|
||||
}
|
||||
@@ -790,7 +791,12 @@ RED.diff = (function() {
|
||||
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);
|
||||
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",
|
||||
exposeApi: true,
|
||||
@@ -811,7 +817,12 @@ RED.diff = (function() {
|
||||
if (remoteNode) {
|
||||
$('<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);
|
||||
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",
|
||||
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) {
|
||||
properties = properties.concat(Object.keys(def.defaults));
|
||||
}
|
||||
if (node.type !== 'tab') {
|
||||
if (node.type !== 'tab' && node.type !== "group") {
|
||||
properties = properties.concat(['inputLabels','outputLabels']);
|
||||
}
|
||||
if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) &&
|
||||
|
@@ -744,7 +744,16 @@ RED.editor = (function() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -56,8 +56,12 @@
|
||||
});
|
||||
}
|
||||
if (!isSameObj(old_env, new_env)) {
|
||||
node.env = new_env;
|
||||
editState.changes.env = node.env;
|
||||
if (new_env.length === 0) {
|
||||
delete node.env;
|
||||
} else {
|
||||
node.env = new_env;
|
||||
}
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
|
@@ -105,6 +105,7 @@ RED.search = (function() {
|
||||
val = extractFlag(val,"unused",flags);
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
// uses:<node-id>
|
||||
val = extractValue(val,"uses",flags);
|
||||
|
||||
@@ -150,7 +151,15 @@ RED.search = (function() {
|
||||
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")) {
|
||||
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
|
||||
(isConfigNode && node.node.users.length === 0)
|
||||
|
@@ -379,7 +379,7 @@ RED.sidebar.help = (function() {
|
||||
var currentVersionParts = RED.settings.version.split(".");
|
||||
var tourVersionParts = tour.version.split(".");
|
||||
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>'
|
||||
|
@@ -175,6 +175,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
n.d = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
n.dirtyStatus = true;
|
||||
n.changed = true;
|
||||
RED.events.emit("nodes:change",n);
|
||||
groupHistoryEvent.events.push(historyEvent);
|
||||
@@ -203,6 +204,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
n.d = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
n.dirtyStatus = true;
|
||||
n.changed = true;
|
||||
RED.events.emit("nodes:change",n);
|
||||
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.uknownNodes"), value: "type:unknown"},
|
||||
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
|
||||
{label:RED._("sidebar.info.search.hiddenFlows"), value:"is:hidden"},
|
||||
]
|
||||
});
|
||||
|
||||
@@ -563,7 +566,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
}
|
||||
}
|
||||
function getGutter(n) {
|
||||
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
|
||||
var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
|
||||
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
@@ -364,6 +364,8 @@ RED.tourGuide = (function() {
|
||||
if (step.fallback) {
|
||||
focus.one("mouseenter", function(evt) {
|
||||
setTimeout(function() {
|
||||
var pos = targetElement[0].getBoundingClientRect();
|
||||
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
|
||||
focus.css({
|
||||
width: (4*dimension)+"px",
|
||||
height: (4*dimension)+"px"
|
||||
|
@@ -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');
|
||||
} 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);
|
||||
} 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 {
|
||||
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);
|
||||
} 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);
|
||||
} 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')) {
|
||||
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')) {
|
||||
|
@@ -3675,7 +3675,11 @@ RED.view = (function() {
|
||||
nodeEl = document.getElementById(d.id);
|
||||
}
|
||||
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";
|
||||
} else {
|
||||
nodeEl.__statusGroup__.style.display = "inline";
|
||||
@@ -4421,6 +4425,9 @@ RED.view = (function() {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
movingSet.add(n);
|
||||
if (targets.length === 1) {
|
||||
RED.view.reveal(n.id);
|
||||
}
|
||||
});
|
||||
updateSelection();
|
||||
redraw();
|
||||
@@ -4957,7 +4964,7 @@ RED.view = (function() {
|
||||
counts.push(RED._("clipboard.group",{count:newGroupCount}));
|
||||
}
|
||||
if (newConfigNodeCount > 0) {
|
||||
counts.push(RED._("clipboard.configNode",{count:newNodeCount}));
|
||||
counts.push(RED._("clipboard.configNode",{count:newConfigNodeCount}));
|
||||
}
|
||||
if (new_subflows.length > 0) {
|
||||
counts.push(RED._("clipboard.subflow",{count:new_subflows.length}));
|
||||
@@ -5029,6 +5036,7 @@ RED.view = (function() {
|
||||
delete node.d;
|
||||
}
|
||||
node.dirty = true;
|
||||
node.dirtyStatus = true;
|
||||
node.changed = true;
|
||||
RED.events.emit("nodes:change",node);
|
||||
}
|
||||
|
@@ -218,55 +218,64 @@ RED.workspaces = (function() {
|
||||
scrollable: true,
|
||||
addButton: "core:add-flow",
|
||||
addButtonCaption: RED._("workspace.addFlow"),
|
||||
menu: [
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-flows",
|
||||
label: RED._("workspace.listFlows"),
|
||||
onselect: "core:list-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-subflows",
|
||||
label: RED._("workspace.listSubflows"),
|
||||
onselect: "core:list-subflows"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
onselect: "core:add-flow-to-right"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||
label: RED._("workspace.hideFlow"),
|
||||
onselect: "core:hide-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-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"),
|
||||
onselect: "core:show-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-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"),
|
||||
onselect: "core:show-last-hidden-flow"
|
||||
menu: function() {
|
||||
var menuItems = [
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-flows",
|
||||
label: RED._("workspace.listFlows"),
|
||||
onselect: "core:list-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-subflows",
|
||||
label: RED._("workspace.listSubflows"),
|
||||
onselect: "core:list-subflows"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
onselect: "core:add-flow-to-right"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||
label: RED._("workspace.hideFlow"),
|
||||
onselect: "core:hide-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-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"),
|
||||
onselect: "core:show-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-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"),
|
||||
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;
|
||||
}
|
||||
@@ -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.invoke("core:search","type:tab ");
|
||||
})
|
||||
@@ -450,7 +461,7 @@ RED.workspaces = (function() {
|
||||
var changes = { disabled: workspace.disabled };
|
||||
workspace.disabled = 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);
|
||||
}
|
||||
var historyEvent = {
|
||||
@@ -536,6 +547,9 @@ RED.workspaces = (function() {
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
}
|
||||
},
|
||||
isHidden: function(id) {
|
||||
return hideStack.includes(id)
|
||||
},
|
||||
show: function(id,skipStack,unhideOnly) {
|
||||
if (!workspace_tabs.contains(id)) {
|
||||
var sf = RED.nodes.subflow(id);
|
||||
|
@@ -197,6 +197,7 @@ $view-select-mode-background: $secondary-background-selected;
|
||||
$view-grid-color: #eee;
|
||||
|
||||
$node-label-color: #333;
|
||||
$node-port-label-color: #888;
|
||||
$node-border: #999;
|
||||
$node-border-unknown: #f33;
|
||||
$node-border-placeholder: #aaa;
|
||||
|
@@ -47,7 +47,7 @@
|
||||
|
||||
.red-ui-flow-port-label {
|
||||
stroke-width: 0;
|
||||
fill: $secondary-text-color;
|
||||
fill: $node-port-label-color;
|
||||
font-size: 16px;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
|
@@ -187,7 +187,7 @@
|
||||
ul.red-ui-menu-dropdown {
|
||||
background: $header-menu-background;
|
||||
border: 1px solid $header-menu-background;
|
||||
width: 250px !important;
|
||||
width: 260px !important;
|
||||
margin-top: 0;
|
||||
li a {
|
||||
color: $header-menu-color;
|
||||
|
@@ -137,10 +137,10 @@
|
||||
padding: 0;
|
||||
border: 1px solid $form-input-border-color;
|
||||
}
|
||||
.ui-spinner input[type=text] {
|
||||
.ui-spinner input {
|
||||
background: $form-input-background;
|
||||
margin: 0 17px 0 0;
|
||||
padding: 8px;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
|
@@ -389,7 +389,19 @@ i.red-ui-tab-icon {
|
||||
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 {
|
||||
display: none;
|
||||
background: $tab-background-inactive;
|
||||
|
@@ -1,14 +1,23 @@
|
||||
export default {
|
||||
steps: [
|
||||
{
|
||||
title: "Create your first flow",
|
||||
title: {
|
||||
'en-US': 'Create your first flow',
|
||||
'ja': 'はじめてのフローを作成'
|
||||
},
|
||||
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'
|
||||
},
|
||||
{
|
||||
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: {
|
||||
type: "dom-event",
|
||||
event: "click",
|
||||
@@ -18,7 +27,10 @@ export default {
|
||||
{
|
||||
element: '.red-ui-palette-node[data-palette-type="inject"]',
|
||||
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',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
@@ -38,7 +50,10 @@ export default {
|
||||
{
|
||||
element: '.red-ui-palette-node[data-palette-type="debug"]',
|
||||
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',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
@@ -57,7 +72,10 @@ export default {
|
||||
},
|
||||
{
|
||||
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',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
@@ -69,7 +87,10 @@ export default {
|
||||
},
|
||||
{
|
||||
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,
|
||||
wait: {
|
||||
type: "dom-event",
|
||||
|
@@ -3,48 +3,79 @@ export default {
|
||||
steps: [
|
||||
{
|
||||
titleIcon: "fa fa-map-o",
|
||||
title: { "en-US": "Welcome to Node-RED 2.1!" },
|
||||
description: { "en-US": "Let's take a moment to discover the new features in this release." }
|
||||
title: {
|
||||
"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" },
|
||||
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>" }
|
||||
title: {
|
||||
"en-US": "A new Tour Guide",
|
||||
"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() {
|
||||
$("#red-ui-header-button-sidemenu").trigger("click");
|
||||
$("#menu-item-edit-menu").parent().addClass("open")
|
||||
$("#menu-item-edit-menu").parent().addClass("open");
|
||||
},
|
||||
complete() {
|
||||
$("#menu-item-edit-menu").parent().removeClass("open")
|
||||
$("#menu-item-edit-menu").parent().removeClass("open");
|
||||
},
|
||||
element: "#menu-item-edit-menu-submenu",
|
||||
interactive: false,
|
||||
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>"+
|
||||
"<p>The menu now displays keyboard shortcuts for the options.</p>" }
|
||||
|
||||
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>" +
|
||||
"<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() {
|
||||
$("#red-ui-header-button-sidemenu").trigger("click");
|
||||
$("#menu-item-arrange-menu").parent().addClass("open")
|
||||
$("#menu-item-arrange-menu").parent().addClass("open");
|
||||
},
|
||||
complete() {
|
||||
$("#menu-item-arrange-menu").parent().removeClass("open")
|
||||
$("#menu-item-arrange-menu").parent().removeClass("open");
|
||||
},
|
||||
element: "#menu-item-arrange-menu-submenu",
|
||||
interactive: false,
|
||||
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",
|
||||
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,
|
||||
prepare() {
|
||||
$("#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",
|
||||
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,
|
||||
direction: "left",
|
||||
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",
|
||||
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) {
|
||||
@@ -78,20 +121,28 @@ export default {
|
||||
setTimeout(done,700);
|
||||
},
|
||||
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",
|
||||
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) {
|
||||
$("#node-dialog-cancel").trigger("click");
|
||||
setTimeout(done,500);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: {"en-US":"Link Call node added"},
|
||||
title: {
|
||||
"en-US": "Link Call node added",
|
||||
"ja": "Link Callノードを追加"
|
||||
},
|
||||
prepare(done) {
|
||||
this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed");
|
||||
RED.actions.invoke("core:toggle-palette",true)
|
||||
@@ -100,22 +151,34 @@ export default {
|
||||
},
|
||||
element: '[data-palette-type="link call"]',
|
||||
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) {
|
||||
$('[data-palette-type="mqtt out"]')[0].scrollIntoView({block:"center"})
|
||||
setTimeout(done,100);
|
||||
},
|
||||
element: '[data-palette-type="mqtt out"]',
|
||||
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) {
|
||||
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"})
|
||||
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"});
|
||||
setTimeout(done,100);
|
||||
},
|
||||
complete() {
|
||||
@@ -125,13 +188,19 @@ export default {
|
||||
},
|
||||
element: '[data-palette-type="file"]',
|
||||
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) {
|
||||
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._})
|
||||
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._});
|
||||
setTimeout(done,700);
|
||||
},
|
||||
complete(done) {
|
||||
@@ -139,13 +208,22 @@ export default {
|
||||
setTimeout(done,500);
|
||||
},
|
||||
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..." },
|
||||
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>" }
|
||||
title: {
|
||||
"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>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -353,14 +353,16 @@
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
var payloadType = node.payloadType;
|
||||
|
||||
if (node.payloadType == null) {
|
||||
if (node.payload == "") {
|
||||
node.payloadType = "date";
|
||||
payloadType = "date";
|
||||
} else {
|
||||
node.payloadType = "str";
|
||||
payloadType = "str";
|
||||
}
|
||||
} else if (node.payloadType === 'string' || node.payloadType === 'none') {
|
||||
node.payloadType = "str";
|
||||
payloadType = "str";
|
||||
}
|
||||
|
||||
$("#inject-time-type-select").on("change", function() {
|
||||
@@ -557,7 +559,7 @@
|
||||
var payload = {
|
||||
p:'payload',
|
||||
v: node.payload ? node.payload : '',
|
||||
vt:node.payloadType ? node.payloadType : 'date'
|
||||
vt:payloadType ? payloadType : 'date'
|
||||
};
|
||||
var topic = {
|
||||
p:'topic',
|
||||
@@ -573,7 +575,7 @@
|
||||
if (newProp.v === undefined) {
|
||||
if (prop.p === 'payload') {
|
||||
newProp.v = node.payload ? node.payload : '';
|
||||
newProp.vt = node.payloadType ? node.payloadType : 'date';
|
||||
newProp.vt = payloadType ? payloadType : 'date';
|
||||
} else if (prop.p === 'topic' && prop.vt === "str") {
|
||||
newProp.v = node.topic ? node.topic : '';
|
||||
}
|
||||
|
@@ -280,6 +280,18 @@ module.exports = function(RED) {
|
||||
root: path.join(__dirname,"lib","debug"),
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@@ -372,6 +372,7 @@ module.exports = function(RED) {
|
||||
hit = false;
|
||||
for (var b in node.buffer) { // check if already in queue
|
||||
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] = {msg, send, done}; // if so - replace existing entry
|
||||
hit = true;
|
||||
|
@@ -298,18 +298,14 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
||||
}
|
||||
if (Object.keys(this.credentials).length != 0) {
|
||||
if (this.authType === "basic") {
|
||||
// Workaround for https://github.com/sindresorhus/got/issues/1169
|
||||
var cred = ""
|
||||
if (this.credentials.user) {
|
||||
// opts.username = this.credentials.user;
|
||||
cred = this.credentials.user
|
||||
}
|
||||
if (this.credentials.password) {
|
||||
// opts.password = this.credentials.password;
|
||||
cred += ":" + this.credentials.password
|
||||
// Workaround for https://github.com/sindresorhus/got/issues/1169 (fixed in got v12)
|
||||
// var cred = ""
|
||||
if (this.credentials.user || this.credentials.password) {
|
||||
// cred = `${this.credentials.user}:${this.credentials.password}`;
|
||||
opts.headers.Authorization = "Basic " + Buffer.from(`${this.credentials.user}:${this.credentials.password}`).toString("base64");
|
||||
}
|
||||
// build own basic auth header
|
||||
opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64");
|
||||
// opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64");
|
||||
} else if (this.authType === "digest") {
|
||||
let digestCreds = this.credentials;
|
||||
let sentCreds = false;
|
||||
|
@@ -23,9 +23,17 @@
|
||||
</select>
|
||||
<span data-i18n="tcpin.label.port"></span> <input type="text" id="node-input-port" style="width:65px">
|
||||
</div>
|
||||
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
|
||||
<div class="form-row hidden" id="node-input-host-row" style="padding-left:110px;">
|
||||
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
|
||||
</div>
|
||||
<div class="form-row" id="node-input-tls-enable">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width:auto; vertical-align:top;">
|
||||
<label for="node-input-usetls" style="width:auto" data-i18n="httpin.use-tls"></label>
|
||||
<div id="node-row-tls" class="hide">
|
||||
<label style="width:auto; margin-left:20px; margin-right:10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.output"></span></label>
|
||||
@@ -42,7 +50,7 @@
|
||||
</div>
|
||||
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
@@ -58,17 +66,18 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp in',{
|
||||
category: 'network',
|
||||
color:"Silver",
|
||||
color: "Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
server: {value:"server",required:true},
|
||||
host: {value:"",validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
server: {value:"server", required:true},
|
||||
host: {value:"", validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||
port: {value:"", required:true, validate:RED.validators.number()},
|
||||
datamode:{value:"stream"},
|
||||
datatype:{value:"buffer"},
|
||||
newline:{value:""},
|
||||
topic: {value:""},
|
||||
base64: {/*deprecated*/ value:false,required:true}
|
||||
base64: {/*deprecated*/ value:false, required:true},
|
||||
tls: {type:"tls-config", value:'', required:false}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
@@ -77,7 +86,7 @@
|
||||
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
return this.name ? "node_label_italic" : "";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var updateOptions = function() {
|
||||
@@ -103,6 +112,27 @@
|
||||
$("#node-input-server").change(updateOptions);
|
||||
$("#node-input-datatype").change(updateOptions);
|
||||
$("#node-input-datamode").change(updateOptions);
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-input-usetls").is(':checked')) {
|
||||
$("#node-row-tls").show();
|
||||
} else {
|
||||
$("#node-row-tls").hide();
|
||||
}
|
||||
}
|
||||
if (this.tls) {
|
||||
$('#node-input-usetls').prop('checked', true);
|
||||
} else {
|
||||
$('#node-input-usetls').prop('checked', false);
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-usetls").is(':checked')) {
|
||||
$("#node-input-tls").val("_ADD_");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -123,6 +153,15 @@
|
||||
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" style="width: 60%;">
|
||||
</div>
|
||||
|
||||
<div class="form-row" id="node-input-tls-enable">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
|
||||
<div id="node-row-tls" class="hide">
|
||||
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row hidden" id="node-input-end-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-end" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
@@ -144,14 +183,15 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp out',{
|
||||
category: 'network',
|
||||
color:"Silver",
|
||||
color: "Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
host: {value:"",validate:function(v) { return (this.beserver != "client")||v.length > 0;} },
|
||||
port: {value:"",validate:function(v) { return (this.beserver == "reply")||RED.validators.number()(v); } },
|
||||
beserver: {value:"client",required:true},
|
||||
base64: {value:false,required:true},
|
||||
end: {value:false,required:true},
|
||||
name: {value:""}
|
||||
beserver: {value:"client", required:true},
|
||||
base64: {value:false, required:true},
|
||||
end: {value:false, required:true},
|
||||
tls: {type:"tls-config", value:'', required:false}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
@@ -170,18 +210,42 @@
|
||||
$("#node-input-port-row").hide();
|
||||
$("#node-input-host-row").hide();
|
||||
$("#node-input-end-row").hide();
|
||||
$("#node-input-tls-enable").hide();
|
||||
} else if (sockettype == "client"){
|
||||
$("#node-input-port-row").show();
|
||||
$("#node-input-host-row").show();
|
||||
$("#node-input-end-row").show();
|
||||
$("#node-input-tls-enable").show();
|
||||
} else {
|
||||
$("#node-input-port-row").show();
|
||||
$("#node-input-host-row").hide();
|
||||
$("#node-input-end-row").show();
|
||||
$("#node-input-tls-enable").show();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-beserver").change(updateOptions);
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-input-usetls").is(':checked')) {
|
||||
$("#node-row-tls").show();
|
||||
} else {
|
||||
$("#node-row-tls").hide();
|
||||
}
|
||||
}
|
||||
if (this.tls) {
|
||||
$('#node-input-usetls').prop('checked', true);
|
||||
} else {
|
||||
$('#node-input-usetls').prop('checked', false);
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-usetls").is(':checked')) {
|
||||
$("#node-input-tls").val("_ADD_");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -194,15 +258,23 @@
|
||||
<span data-i18n="tcpin.label.port"></span>
|
||||
<input type="text" id="node-input-port" style="width:60px">
|
||||
</div>
|
||||
<div class="form-row" id="node-input-tls-enable">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
|
||||
<div id="node-row-tls" class="hide">
|
||||
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-out"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
|
||||
<label for="node-input-ret"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
|
||||
<select type="text" id="node-input-ret" style="width:54%;">
|
||||
<option value="buffer" data-i18n="tcpin.output.buffer"></option>
|
||||
<option value="string" data-i18n="tcpin.output.string"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-out"> </label>
|
||||
<label for="node-input-out"><i class="fa fa-sign-out fa-rotate-90"></i> <span data-i18n="tcpin.label.close"></span></label>
|
||||
<select type="text" id="node-input-out" style="width:54%;">
|
||||
<option value="time" data-i18n="tcpin.return.timeout"></option>
|
||||
<option value="char" data-i18n="tcpin.return.character"></option>
|
||||
@@ -213,6 +285,9 @@
|
||||
<input type="text" id="node-input-splitc" style="width:50px;">
|
||||
<span id="node-units"></span>
|
||||
</div>
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:162px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional">
|
||||
</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">
|
||||
@@ -222,14 +297,16 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp request',{
|
||||
category: 'network',
|
||||
color:"Silver",
|
||||
color: "Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
server: {value:""},
|
||||
port: {value:"",validate:RED.validators.regex(/^(\d*|)$/)},
|
||||
out: {value:"time",required:true},
|
||||
port: {value:"", validate:RED.validators.regex(/^(\d*|)$/)},
|
||||
out: {value:"time", required:true},
|
||||
ret: {value:"buffer"},
|
||||
splitc: {value:"0",required:true},
|
||||
name: {value:""}
|
||||
splitc: {value:"0", required:true},
|
||||
newline: {value:""},
|
||||
tls: {type:"tls-config", value:'', required:false}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
@@ -246,6 +323,14 @@
|
||||
$("#node-input-ret").val("buffer");
|
||||
this.ret = "buffer";
|
||||
}
|
||||
$("#node-input-ret").on("change", function() {
|
||||
if ($("#node-input-ret").val() === "string" && $("#node-input-out").val() === "sit") { $("#node-row-newline").show(); }
|
||||
else { $("#node-row-newline").hide(); }
|
||||
});
|
||||
$("#node-input-out").on("change", function() {
|
||||
if ($("#node-input-ret").val() === "string" && $("#node-input-out").val() === "sit") { $("#node-row-newline").show(); }
|
||||
else { $("#node-row-newline").hide(); }
|
||||
});
|
||||
$("#node-input-out").on('focus', function () { previous = this.value; }).on("change", function() {
|
||||
$("#node-input-splitc").show();
|
||||
if (previous === null) { previous = $("#node-input-out").val(); }
|
||||
@@ -272,6 +357,27 @@
|
||||
$("#node-input-splitc").hide();
|
||||
}
|
||||
});
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-input-usetls").is(':checked')) {
|
||||
$("#node-row-tls").show();
|
||||
} else {
|
||||
$("#node-row-tls").hide();
|
||||
}
|
||||
}
|
||||
if (this.tls) {
|
||||
$('#node-input-usetls').prop('checked', true);
|
||||
} else {
|
||||
$('#node-input-usetls').prop('checked', false);
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-usetls").is(':checked')) {
|
||||
$("#node-input-tls").val("_ADD_");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@@ -16,13 +16,46 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||
var socketTimeout = RED.settings.socketTimeout||null;
|
||||
let reconnectTime = RED.settings.socketReconnectTime || 10000;
|
||||
let socketTimeout = RED.settings.socketTimeout || null;
|
||||
const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
|
||||
const Denque = require('denque');
|
||||
var net = require('net');
|
||||
const net = require('net');
|
||||
const tls = require('tls');
|
||||
|
||||
var connectionPool = {};
|
||||
let connectionPool = {};
|
||||
|
||||
function normalizeConnectArgs(listArgs) {
|
||||
const args = net._normalizeArgs(listArgs);
|
||||
const options = args[0];
|
||||
const cb = args[1];
|
||||
|
||||
// If args[0] was options, then normalize dealt with it.
|
||||
// If args[0] is port, or args[0], args[1] is host, port, we need to
|
||||
// find the options and merge them in, normalize's options has only
|
||||
// the host/port/path args that it knows about, not the tls options.
|
||||
// This means that options.host overrides a host arg.
|
||||
if (listArgs[1] !== null && typeof listArgs[1] === 'object') {
|
||||
ObjectAssign(options, listArgs[1]);
|
||||
} else if (listArgs[2] !== null && typeof listArgs[2] === 'object') {
|
||||
ObjectAssign(options, listArgs[2]);
|
||||
}
|
||||
|
||||
return cb ? [options, cb] : [options];
|
||||
}
|
||||
|
||||
function getAllowUnauthorized() {
|
||||
const allowUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0';
|
||||
|
||||
if (allowUnauthorized) {
|
||||
process.emitWarning(
|
||||
'Setting the NODE_TLS_REJECT_UNAUTHORIZED ' +
|
||||
'environment variable to \'0\' makes TLS connections ' +
|
||||
'and HTTPS requests insecure by disabling ' +
|
||||
'certificate verification.');
|
||||
}
|
||||
return allowUnauthorized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue `item` in `queue`
|
||||
@@ -53,13 +86,14 @@ module.exports = function(RED) {
|
||||
this.topic = n.topic;
|
||||
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
|
||||
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
|
||||
this.base64 = n.base64;
|
||||
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
||||
this.closing = false;
|
||||
this.connected = false;
|
||||
var node = this;
|
||||
var count = 0;
|
||||
if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); }
|
||||
|
||||
if (!node.server) {
|
||||
var buffer = null;
|
||||
@@ -70,13 +104,25 @@ module.exports = function(RED) {
|
||||
node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
|
||||
node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
|
||||
var id = RED.util.generateId();
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
|
||||
});
|
||||
client.setKeepAlive(true,120000);
|
||||
var connOpts = {host: node.host};
|
||||
if (n.tls) {
|
||||
var connOpts = tlsNode.addTLSOptions({host: node.host});
|
||||
client = tls.connect(node.port, connOpts, function() {
|
||||
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("status.connected", {host: node.host, port: node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
|
||||
});
|
||||
}
|
||||
else {
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
|
||||
});
|
||||
}
|
||||
client.setKeepAlive(true, 120000);
|
||||
connectionPool[id] = client;
|
||||
|
||||
client.on('data', function (data) {
|
||||
@@ -89,7 +135,7 @@ module.exports = function(RED) {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0; i<parts.length-1; i+=1) {
|
||||
msg = {topic:node.topic, payload:parts[i]};
|
||||
msg = {topic:node.topic, payload:parts[i] + node.newline.trimEnd()};
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
@@ -150,7 +196,13 @@ module.exports = function(RED) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
var server = net.createServer(function (socket) {
|
||||
let srv = net;
|
||||
let connOpts;
|
||||
if (n.tls) {
|
||||
srv = tls;
|
||||
connOpts = tlsNode.addTLSOptions({});
|
||||
}
|
||||
var server = srv.createServer(connOpts, function (socket) {
|
||||
socket.setKeepAlive(true,120000);
|
||||
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
|
||||
var id = RED.util.generateId();
|
||||
@@ -177,7 +229,7 @@ module.exports = function(RED) {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0; i<parts.length-1; i+=1) {
|
||||
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
|
||||
msg = {topic:node.topic, payload:parts[i] + node.newline.trimEnd(), ip:socket.remoteAddress, port:socket.remotePort};
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
@@ -269,8 +321,9 @@ module.exports = function(RED) {
|
||||
this.closing = false;
|
||||
this.connected = false;
|
||||
var node = this;
|
||||
if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); }
|
||||
|
||||
if (!node.beserver||node.beserver=="client") {
|
||||
if (!node.beserver || node.beserver == "client") {
|
||||
var reconnectTimeout;
|
||||
var client = null;
|
||||
var end = false;
|
||||
@@ -278,11 +331,24 @@ module.exports = function(RED) {
|
||||
var setupTcpClient = function() {
|
||||
node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
|
||||
node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
if (n.tls) {
|
||||
// connOpts = tlsNode.addTLSOptions(connOpts);
|
||||
// client = tls.connect(connOpts, function() {
|
||||
var connOpts = tlsNode.addTLSOptions({host: node.host});
|
||||
client = tls.connect(node.port, connOpts, function() {
|
||||
// buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("status.connected", {host: node.host, port: node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
}
|
||||
else {
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
}
|
||||
client.setKeepAlive(true,120000);
|
||||
client.on('error', function (err) {
|
||||
node.log(RED._("tcpin.errors.error",{error:err.toString()}));
|
||||
@@ -368,7 +434,13 @@ module.exports = function(RED) {
|
||||
else {
|
||||
var connectedSockets = [];
|
||||
node.status({text:RED._("tcpin.status.connections",{count:0})});
|
||||
var server = net.createServer(function (socket) {
|
||||
let srv = net;
|
||||
let connOpts;
|
||||
if (n.tls) {
|
||||
srv = tls;
|
||||
connOpts = tlsNode.addTLSOptions({});
|
||||
}
|
||||
var server = srv.createServer(connOpts, function (socket) {
|
||||
socket.setKeepAlive(true,120000);
|
||||
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
|
||||
node.log(RED._("tcpin.status.connection-from",{host:socket.remoteAddress, port:socket.remotePort}));
|
||||
@@ -445,7 +517,11 @@ module.exports = function(RED) {
|
||||
this.port = Number(n.port);
|
||||
this.out = n.out;
|
||||
this.ret = n.ret || "buffer";
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
|
||||
this.splitc = n.splitc;
|
||||
if (n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
}
|
||||
|
||||
if (this.out === "immed") { this.splitc = -1; this.out = "time"; }
|
||||
if (this.out !== "char") { this.splitc = Number(this.splitc); }
|
||||
@@ -500,12 +576,48 @@ module.exports = function(RED) {
|
||||
}
|
||||
else { buf = Buffer.alloc(65536); } // set it to 64k... hopefully big enough for most TCP packets.... but only hopefully
|
||||
|
||||
clients[connection_id].client = net.Socket();
|
||||
var connOpts = {host:host, port:port};
|
||||
if (n.tls) {
|
||||
connOpts = tlsNode.addTLSOptions(connOpts);
|
||||
const allowUnauthorized = getAllowUnauthorized();
|
||||
|
||||
let options = {
|
||||
rejectUnauthorized: !allowUnauthorized,
|
||||
ciphers: tls.DEFAULT_CIPHERS,
|
||||
checkServerIdentity: tls.checkServerIdentity,
|
||||
minDHSize: 1024,
|
||||
...connOpts
|
||||
};
|
||||
|
||||
if (!options.keepAlive) { options.singleUse = true; }
|
||||
|
||||
const context = options.secureContext || tls.createSecureContext(options);
|
||||
|
||||
clients[connection_id].client = new tls.TLSSocket(options.socket, {
|
||||
allowHalfOpen: options.allowHalfOpen,
|
||||
pipe: !!options.path,
|
||||
secureContext: context,
|
||||
isServer: false,
|
||||
requestCert: false, // true,
|
||||
rejectUnauthorized: false, // options.rejectUnauthorized !== false,
|
||||
session: options.session,
|
||||
ALPNProtocols: options.ALPNProtocols,
|
||||
requestOCSP: options.requestOCSP,
|
||||
enableTrace: options.enableTrace,
|
||||
pskCallback: options.pskCallback,
|
||||
highWaterMark: options.highWaterMark,
|
||||
onread: options.onread,
|
||||
signal: options.signal,
|
||||
});
|
||||
}
|
||||
else {
|
||||
clients[connection_id].client = net.Socket();
|
||||
}
|
||||
if (socketTimeout !== null) { clients[connection_id].client.setTimeout(socketTimeout);}
|
||||
|
||||
if (host && port) {
|
||||
clients[connection_id].connecting = true;
|
||||
clients[connection_id].client.connect(port, host, function() {
|
||||
clients[connection_id].client.connect(connOpts, function() {
|
||||
//node.log(RED._("tcpin.errors.client-connected"));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
if (clients[connection_id] && clients[connection_id].client) {
|
||||
@@ -528,17 +640,32 @@ module.exports = function(RED) {
|
||||
else {
|
||||
node.warn(RED._("tcpin.errors.no-host"));
|
||||
}
|
||||
|
||||
var chunk = "";
|
||||
clients[connection_id].client.on('data', function(data) {
|
||||
if (node.out === "sit") { // if we are staying connected just send the buffer
|
||||
if (clients[connection_id]) {
|
||||
const msg = clients[connection_id].lastMsg || {};
|
||||
msg.payload = RED.util.cloneMessage(data);
|
||||
if (node.ret === "string") {
|
||||
try { msg.payload = msg.payload.toString(); }
|
||||
catch(e) { node.error("Failed to create string", msg); }
|
||||
try {
|
||||
if (node.newline && node.newline !== "" ) {
|
||||
chunk += msg.payload.toString();
|
||||
let parts = chunk.split(node.newline);
|
||||
for (var p=0; p<parts.length-1; p+=1) {
|
||||
let m = RED.util.cloneMessage(msg);
|
||||
m.payload = parts[p] + node.newline.trimEnd();
|
||||
nodeSend(m);
|
||||
}
|
||||
chunk = parts[parts.length-1];
|
||||
}
|
||||
else {
|
||||
msg.payload = msg.payload.toString();
|
||||
nodeSend(msg);
|
||||
}
|
||||
}
|
||||
catch(e) { node.error(RED._("tcpin.errors.bad-string"), msg); }
|
||||
}
|
||||
nodeSend(msg);
|
||||
else { nodeSend(msg); }
|
||||
}
|
||||
}
|
||||
// else if (node.splitc === 0) {
|
||||
@@ -675,7 +802,13 @@ module.exports = function(RED) {
|
||||
//node.warn(RED._("tcpin.errors.connect-timeout"));
|
||||
if (clients[connection_id].client) {
|
||||
clients[connection_id].connecting = true;
|
||||
clients[connection_id].client.connect(port, host, function() {
|
||||
|
||||
var connOpts = {host:host, port:port};
|
||||
if (n.tls) {
|
||||
connOpts = tlsNode.addTLSOptions(connOpts);
|
||||
}
|
||||
|
||||
clients[connection_id].client.connect(connOpts, function() {
|
||||
clients[connection_id].connected = true;
|
||||
clients[connection_id].connecting = false;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
|
@@ -25,7 +25,7 @@
|
||||
<dd>Optional nutzbare Nachrichten-Eigenschaft.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Der <span style="background-color:Gainsboro">inject</span>-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
|
||||
<p>Der inject-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
|
||||
Der voreingestellte Payload ist die aktuelle Zeit als Zeitstempel in Millisekunden
|
||||
seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC).</p>
|
||||
<p>Der Node unterstützt auch die Injektion von Zeichenfolgen, Zahlenwerten, Booleschen Werten,
|
||||
@@ -34,7 +34,7 @@
|
||||
Er kann auch in regelmäßigen Intervallen oder nach einem Zeitplan injizieren.</p>
|
||||
<p>Er kann auch so eingestellt werden, dass er jedes Mal einen Wert injiziert, wenn der Flow gestartet wird.</p>
|
||||
<p>Das maximal einstellbare Intervall beträgt etwa 596 Stunden bzw. 24 Tage.
|
||||
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein <span style="background-color:Gainsboro">scheduler</span>-Node verwendet werden,
|
||||
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein scheduler-Node verwendet werden,
|
||||
der mit Stromausfällen und Neustarts besser umgehen kann.</p>
|
||||
<p><b>Hinweis</b>: Die Optionen <i>"Intervall zwischen Uhrzeiten"</i> und <i>"Täglicher Zeitpunkt"</i>
|
||||
verwenden das Standard-Cron-System.</p>
|
||||
|
@@ -23,10 +23,10 @@
|
||||
<p>JavaScript-Objekte und -Arrays können nach Bedarf ein- und ausgeblendet werden.
|
||||
Binäre Puffer-Objekte (buffer objects) können nach Möglichkeit als Rohdaten oder als Zeichenfolge (string) angezeigt werden.</p>
|
||||
<p>Neben der eigentlichen Nachricht werden im Debug-Tab auch der Empfangszeitpunkt,
|
||||
der empfangende <span style="background-color:Gainsboro">debug</span>-Node, sowie Name und Typ der Nachricht protokolliert.
|
||||
Durch Klicken auf die Node-ID wird der entsprechende <span style="background-color:Gainsboro">debug</span>-Node im Arbeitsbereich angezeigt.</p>
|
||||
<p>Die Schaltfläche des <span style="background-color:Gainsboro">debug</span>-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
|
||||
Es ist empfehlenswert, alle nicht verwendeten <span style="background-color:Gainsboro">debug</span>-Nodes zu deaktivieren oder gleich zu entfernen.</p>
|
||||
<p>Der <span style="background-color:Gainsboro">debug</span>-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
|
||||
als kurze Statustexte (max. 32 Zeichen) unter dem <span style="background-color:Gainsboro">debug</span>-Node angezeigt werden.</p>
|
||||
der empfangende debug-Node, sowie Name und Typ der Nachricht protokolliert.
|
||||
Durch Klicken auf die Node-ID wird der entsprechende debug-Node im Arbeitsbereich angezeigt.</p>
|
||||
<p>Die Schaltfläche des debug-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
|
||||
Es ist empfehlenswert, alle nicht verwendeten debug-Nodes zu deaktivieren oder gleich zu entfernen.</p>
|
||||
<p>Der debug-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
|
||||
als kurze Statustexte (max. 32 Zeichen) unter dem debug-Node angezeigt werden.</p>
|
||||
</script>
|
||||
|
@@ -18,11 +18,11 @@
|
||||
<p>Anstoß eines weiteren Flows, wenn ein anderer Node seine Nachrichtenbearbeitung abgeschlossen hat.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Wenn ein Node die Bearbeitung seiner Nachrichten abgeschlossen hat,
|
||||
kann der <span style="background-color:Gainsboro">complete</span>-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
|
||||
kann der complete-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
|
||||
<p>Der Node kann z.B. mit einem anderen Node ohne Ausgang verknüpft werden
|
||||
(z.B. E-Mail-Sende-Node), um den Flow fortzusetzen.</p>
|
||||
<p>Im Node werden dazu die zu überwachenden Nodes des selben Flows ausgewählt.
|
||||
Im Gegensatz zum <span style="background-color:Gainsboro">catch</span>-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
|
||||
Im Gegensatz zum catch-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
|
||||
<p>Nicht alle Nodes können diesen Node anstoßen.
|
||||
Es hängt davon ab, ob die auslösenden Knoten diese Funktion unterstützen,
|
||||
welche erst mit Node-RED 1.0 eingeführt wurde.</p>
|
||||
|
@@ -29,13 +29,13 @@
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Wenn ein Node bei der Verarbeitung einer Nachricht einen Fehler verursacht, wird der Flow in der Regel angehalten.
|
||||
Der <span style="background-color:Gainsboro">catch</span>-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
|
||||
Der catch-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
|
||||
<p>Der Node fängt standardmäßig die Fehler aller Nodes im selben Flow ab.
|
||||
Alternativ kann er auch an bestimmte Nodes gebunden werden.</p>
|
||||
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen <span style="background-color:Gainsboro">catch</span>-Nodes die Fehlermeldung.</p>
|
||||
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem <span style="background-color:Gainsboro">catch</span>-Node
|
||||
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen catch-Nodes die Fehlermeldung.</p>
|
||||
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem catch-Node
|
||||
innerhalb des Subflows abgefangen.
|
||||
Wenn im Subflow keine <span style="background-color:Gainsboro">catch</span>-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
|
||||
Wenn im Subflow keine catch-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
|
||||
in der sich die Subflow-Instanz befindet.</p>
|
||||
<p>Wenn die Nachricht bereits über eine <code>error</code>-Eigenschaft verfügt, wird sie nach <code>_error</code> kopiert.</p>
|
||||
</script>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<script type="text/html" data-help-name="link in">
|
||||
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Der Node kann mit jedem beliebigen <span style="background-color:Gainsboro">link out</span>-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
<p>Der Node kann mit jedem beliebigen link out-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
|
||||
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
|
||||
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
|
||||
@@ -28,7 +28,7 @@
|
||||
<script type="text/html" data-help-name="link out">
|
||||
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Der Node kann mit jedem beliebigen <span style="background-color:Gainsboro">link in</span>-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
<p>Der Node kann mit jedem beliebigen link in-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
|
||||
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
|
||||
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
|
||||
|
@@ -47,7 +47,7 @@
|
||||
<li><code>node.error("Fehlermeldungstext")</code></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>Der <span style="background-color:Gainsboro">catch</span>-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
|
||||
<p>Der catch-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
|
||||
Er wird aufgerufen, indem <code>msg</code> als zweites Argument an <code>node.error</code> übergeben wird:</p>
|
||||
<pre>node.error("Fehlermeldungstext" ,msg);</pre>
|
||||
<h4><b>Zugriff auf Node-Informationen</b></h4>
|
||||
|
@@ -27,7 +27,7 @@
|
||||
<ol>
|
||||
<li><b>value rules</b>: Regeln werden hinsichtlich einer eingestellten Eigenschaft ausgewertet</li>
|
||||
<li><b>sequence rules</b>: Regeln beziehen sich auf Nachrichtensequenzen,
|
||||
wie sie beispielsweise durch den <span style="background-color:Gainsboro">split</span>-Node erzeugt werden</li>
|
||||
wie sie beispielsweise durch den split-Node erzeugt werden</li>
|
||||
<li>Ein <b>JSONata-Ausdruck</b> kann die gesamte Eingangsnachricht auswerten und einen <code>true</code>-Wert zurückliefern,
|
||||
um eine Regelerfüllung zu signalisieren</li>
|
||||
<li>Die <b>ansonsten</b>-Regel wird angewendet, wenn keine vorhergehende Regel übereinstimmt</li>
|
||||
|
@@ -25,9 +25,9 @@
|
||||
<dt class="optional">payload <span class="property-type">string</span></dt>
|
||||
<dd>Wird an auszuführenden Befehl angehängt, sofern im Node aktiviert.</dd>
|
||||
<dt class="optional">kill <span class="property-type">string</span></dt>
|
||||
<dd>Typ des Kill-Signals, das an den zu beendenden <span style="background-color:Gainsboro">exec</span>-Node-Prozess gesendet wird.</dd>
|
||||
<dd>Typ des Kill-Signals, das an den zu beendenden exec-Node-Prozess gesendet wird.</dd>
|
||||
<dt class="optional">pid <span class="property-type">number | string</span></dt>
|
||||
<dd>Prozess-ID des zu beendenden <span style="background-color:Gainsboro">exec</span>-Node-Prozesses.</dd>
|
||||
<dd>Prozess-ID des zu beendenden exec-Node-Prozesses.</dd>
|
||||
</dl>
|
||||
<h3>Ausgangsdaten</h3>
|
||||
<ol class="node-ports">
|
||||
@@ -75,7 +75,7 @@
|
||||
<p>Die zurückgegebenen Daten (Payload) sind in der Regel eine <i>Zeichenfolge (string)</i>,
|
||||
außer es werden nicht UTF-8-Zeichen wie bei einem <i>binären Puffer (buffer)</i> erkannt.</p>
|
||||
<p>Bei einem aktiven Node werden Status und die PID angezeigt.
|
||||
Änderungen können mittels <span style="background-color:Gainsboro">status</span>-Node gelesen werden.</p>
|
||||
Änderungen können mittels status-Node gelesen werden.</p>
|
||||
<h4><b>Prozesse beenden</b></h4>
|
||||
<p>Durch Senden von <code>msg.kill</code> wird ein einzelner aktiver Prozess beendet.
|
||||
<code>msg.kill</code> sollte als Zeichenfolge (string) den Signaltyp enthalten,
|
||||
|
@@ -94,7 +94,7 @@
|
||||
"label": {
|
||||
"source": "Fehler abfangen von",
|
||||
"selectAll": "Alles auswählen",
|
||||
"uncaught": "Fehler ignorieren, die von anderen <span style=\"background-color:Gainsboro\">catch</span>-Nodes behandelt wurden"
|
||||
"uncaught": "Fehler ignorieren, die von anderen catch-Nodes behandelt wurden"
|
||||
},
|
||||
"scope": {
|
||||
"all": "allen Nodes",
|
||||
@@ -475,12 +475,12 @@
|
||||
"json": "Ein parsed JSON-Objekt",
|
||||
"tip": {
|
||||
"in": "Die URL ist relativ zu ",
|
||||
"res": "Die an diesen Node gesendeten Nachrichten <b>müssen</b> von einem <span style=\"background-color:Gainsboro\">http in</span>-Node stammen",
|
||||
"res": "Die an diesen Node gesendeten Nachrichten <b>müssen</b> von einem http in-Node stammen",
|
||||
"req": "Tipp: Wenn die JSON-Syntax-Analyse fehlschlägt, wird die abgerufene Zeichenfolge zurückgegeben, wie sie ist."
|
||||
},
|
||||
"httpreq": "http request",
|
||||
"errors": {
|
||||
"not-created": "<span style=\"background-color:Gainsboro\">http in</span>-Node kann nicht erstellt werden, wenn httpNodeRoot auf 'false' gesetzt ist.",
|
||||
"not-created": "http in-Node kann nicht erstellt werden, wenn httpNodeRoot auf 'false' gesetzt ist.",
|
||||
"missing-path": "Fehlender Pfad",
|
||||
"no-response": "Kein Antwort-Objekt",
|
||||
"json-error": "JSON-Parse-Fehler",
|
||||
@@ -684,7 +684,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"invalid-expr": "Ungültiger JSONata-Ausdruck: __error__",
|
||||
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">switch</span>-Node"
|
||||
"too-many": "Zu viele anstehende Nachrichten im switch-Node"
|
||||
}
|
||||
},
|
||||
"change": {
|
||||
@@ -851,7 +851,6 @@
|
||||
"outputas": "Ausgabe",
|
||||
"breakchunks": "In Chunks aufteilen",
|
||||
"breaklines": "In Linien aufteilen",
|
||||
"filelabel": "file",
|
||||
"sendError": "Nachricht bei Fehler senden (herkömmlicher Modus)",
|
||||
"encoding": "Kodierung",
|
||||
"deletelabel": "lösche __file__",
|
||||
@@ -940,8 +939,8 @@
|
||||
"afterTimeout": "Bei Zeitablauf nach erster Nachricht von",
|
||||
"seconds": "Sekunden",
|
||||
"complete": "Nach Nachricht mit <code>msg.complete</code>-Eigenschaft",
|
||||
"tip": "Dieser Modus setzt voraus, dass dieser Node entweder mit einem <span style=\"background-color:Gainsboro\">split</span>-Node kombiniert ist oder dass die empfangenen Nachrichten über eine ordnungsgemäß konfigurierte <code>msg.parts</code>-Eigenschaft verfügen.",
|
||||
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">join</span>-Node",
|
||||
"tip": "Dieser Modus setzt voraus, dass dieser Node entweder mit einem split-Node kombiniert ist oder dass die empfangenen Nachrichten über eine ordnungsgemäß konfigurierte <code>msg.parts</code>-Eigenschaft verfügen.",
|
||||
"too-many": "Zu viele anstehende Nachrichten im join-Node",
|
||||
"merge": {
|
||||
"topics-label": "Zusammengeführte Topics",
|
||||
"topics": "Topics",
|
||||
@@ -970,9 +969,9 @@
|
||||
"ascending": "aufsteigend",
|
||||
"descending": "absteigend",
|
||||
"as-number": "als Zahlenwert",
|
||||
"invalid-exp": "Ungültiger JSONata-Ausdruck in <span style=\"background-color:Gainsboro\">sort</span>-Node: __message__",
|
||||
"too-many": "Zu viele anstehende Nachrichten in <span style=\"background-color:Gainsboro\">sort</span>-Node",
|
||||
"clear": "Anstehende Nachricht in <span style=\"background-color:Gainsboro\">sort</span>-Node löschen"
|
||||
"invalid-exp": "Ungültiger JSONata-Ausdruck in sort-Node: __message__",
|
||||
"too-many": "Zu viele anstehende Nachrichten in sort-Node",
|
||||
"clear": "Anstehende Nachricht in sort-Node löschen"
|
||||
},
|
||||
"batch": {
|
||||
"batch": "batch",
|
||||
@@ -997,7 +996,7 @@
|
||||
"topics-label": "Topics",
|
||||
"topic": "Topic"
|
||||
},
|
||||
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">batch</span>-Node",
|
||||
"too-many": "Zu viele anstehende Nachrichten im batch-Node",
|
||||
"unexpected": "Unerwarteter Modus",
|
||||
"no-parts": "Keine parts-Eigenschaft in Nachricht"
|
||||
},
|
||||
|
@@ -94,8 +94,8 @@
|
||||
<script type="text/html" data-help-name="mqtt-broker">
|
||||
<p>Konfiguration der Verbindung zu einem MQTT-Broker.</p>
|
||||
<p>Diese Konfiguration erstellt eine einzelne Verbindung zu einem Broker,
|
||||
welche anschließend von den <span style="background-color:Gainsboro">mqtt in</span>- und
|
||||
<span style="background-color:Gainsboro">mqtt out</span>-Nodes verwendet werden.</p>
|
||||
welche anschließend von den mqtt in- und
|
||||
mqtt out-Nodes verwendet werden.</p>
|
||||
<p>Der Node generiert eine beliebige Client-ID, falls sie nicht vorgegeben ist und der
|
||||
Node eine bereinigte Sitzung (clean session) verwenden soll.
|
||||
Wenn eine Client-ID vorgegeben wird, muss sie für den Broker eindeutig sein, zu dem die Verbindung hergestellt werden soll.</p>
|
||||
|
@@ -36,7 +36,7 @@
|
||||
<dt>res <span class="property-type">object</span></dt>
|
||||
<dd>HTTP-Antwortobjekt.<br/>
|
||||
Diese Eigenschaft sollte nicht direkt verwendet werden.
|
||||
Im <span style="background-color:Gainsboro">http response</span>-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
|
||||
Im http response-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
|
||||
Diese Eigenschaft muss an der Nachricht angehängt bleiben, die an den Antwort-Node übergeben wird.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
@@ -50,12 +50,12 @@
|
||||
<p>Wenn der Inhaltstyp der Anforderung ermittelt werden kann, wird der Hauptteil als passender Typ analysiert.
|
||||
Z.B. <code>application/json</code> wird zu einem JavaScript-Objekt analysiert.</p>
|
||||
<p><b>Hinweis</b>: Dieser Node sendet keine Antwort an die Anforderung.
|
||||
Der Flow muss einen <span style="background-color:Gainsboro">http response</span>-Node enthalten,
|
||||
Der Flow muss einen http response-Node enthalten,
|
||||
um die Anforderung zu vervollständigen.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="http response">
|
||||
<p>Senden von Antworten auf Anforderungen, die von einem <span style="background-color:Gainsboro">http in</span>-Node empfangen wurden.</p>
|
||||
<p>Senden von Antworten auf Anforderungen, die von einem http in-Node empfangen wurden.</p>
|
||||
<h3>Eingangsdaten</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string</span></dt>
|
||||
|
@@ -34,17 +34,17 @@
|
||||
</ul>
|
||||
</dd>
|
||||
<dt>schemaError <span class="property-type">array</span></dt>
|
||||
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den <span style="background-color:Gainsboro">catch</span>-Node eine <code>schemaError</code>-Eigenschaft erstellt,
|
||||
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den catch-Node eine <code>schemaError</code>-Eigenschaft erstellt,
|
||||
die ein Array von Fehlern enthält.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Standardmäßig verarbeitet der Node <code>msg.payload</code>,
|
||||
kann aber auch eine beliebige Nachrichteneigenschaft konvertieren.</p>
|
||||
<p>Die Konvertierungsrichtung kann im Node auch vorgegeben werden, um eine bestimmte Ziel-Kodierung sicherzustellen.
|
||||
Dies kann z.B. zusammen mit dem <span style="background-color:Gainsboro">http in</span>-Node benutzt werden, um sicherzustellen,
|
||||
Dies kann z.B. zusammen mit dem http in-Node benutzt werden, um sicherzustellen,
|
||||
dass die Nutzdaten (Payload) ein analysiertes (parsed) Objekt ist,
|
||||
auch wenn eine eingehende Anfrage seinen Inhaltstyp nicht korrekt eingestellt hat,
|
||||
damit der <span style="background-color:Gainsboro">http in</span>-Node die Konvertierung durchführen kann.</p>
|
||||
damit der http in-Node die Konvertierung durchführen kann.</p>
|
||||
<p>Wenn der Node auf Zeichenfolgen-Eingang (string) eingestellt ist und es einen String empfängt,
|
||||
werden keine weiteren Prüfungen der Eigenschaft durchgeführt.
|
||||
Der Node prüft weder, ob die Zeichenfolge (string) ein gültiges JSON enthält, noch wird er ihn neu formatieren,
|
||||
|
@@ -32,7 +32,7 @@
|
||||
<dl class="message-properties">
|
||||
<dt>parts <span class="property-type">object</span></dt>
|
||||
<dd>Diese Eigenschaft enthält Informationen darüber, wie die Nachricht von der ursprünglichen Nachricht abgeteilt wurde.
|
||||
Bei Übergabe an ein <span style="background-color:Gainsboro">join</span>-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
|
||||
Bei Übergabe an ein join-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
|
||||
Diese Eigenschaft hat die folgenden Eigenschaften:
|
||||
<ul>
|
||||
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
|
||||
@@ -48,7 +48,7 @@
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Dieser Node macht es einfach, einen Flow zu erstellen, der gemeinsame Aktionen über eine Sequenz von Nachrichten ausführt,
|
||||
bevor die Sequenz mittels <span style="background-color:Gainsboro">join</span>-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
|
||||
bevor die Sequenz mittels join-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
|
||||
<p>Der Node verwendet die <code>msg.parts</code>-Eigenschaft, um die einzelnen Sequenzteile nachzuverfolgen.</p>
|
||||
<h4><b>Streaming-Modus</b></h4>
|
||||
<p>Der Node kann auch zum Aufbereiten eines Nachrichtenstroms verwendet werden.
|
||||
@@ -59,7 +59,7 @@
|
||||
so wird es im Node aufbewahrt und der nächsten empfangenen Nachricht vorangestellt.</p>
|
||||
<p>In diesem Modus wird die <code>msg.parts.count</code>-Eigenschaft nicht gesetzt,
|
||||
da die Anzahl der zu erwartenden Nachrichten im Stream unbekannt ist.
|
||||
Das bedeutet, dass ein nachfolgender <span style="background-color:Gainsboro">join</span>-Node nicht im Automatikmodus verwendet werden kann.</p>
|
||||
Das bedeutet, dass ein nachfolgender join-Node nicht im Automatikmodus verwendet werden kann.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="join">
|
||||
@@ -67,7 +67,7 @@
|
||||
<p>Es sind drei Modi verfügbar:</p>
|
||||
<dl>
|
||||
<dt>Automatisch</dt>
|
||||
<dd>In Kombination mit dem <span style="background-color:Gainsboro">split</span>-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
|
||||
<dd>In Kombination mit dem split-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
|
||||
<dt>Manuell</dt>
|
||||
<dd>Die Nachrichtensequenzen können auf verschiedene Weisen verbunden werden.</dd>
|
||||
<dt>Sequenz reduzieren</dt>
|
||||
@@ -77,7 +77,7 @@
|
||||
<dl class="message-properties">
|
||||
<dt class="optional">parts <span class="property-type">object</span></dt>
|
||||
<dd>Zur automatischen Verbindung einer Nachrichtensequenz sollten alle über diese Eigenschaft verfügen.
|
||||
Der <span style="background-color:Gainsboro">split</span>-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
|
||||
Der split-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
|
||||
Sie hat die folgenden Eigenschaften:
|
||||
<ul>
|
||||
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
|
||||
@@ -98,7 +98,7 @@
|
||||
<h4><b>Automatischer Modus</b></h4>
|
||||
<p>Der automatische Modus verwendet die <code>parts</code>-Eigenschaften der eingehenden Nachrichten,
|
||||
um die Sequenz in richtiger Reihenfolge zu verknüpften.
|
||||
Dies ermöglicht die Aufteilung des <span style="background-color:Gainsboro">split</span>-Nodes automatisch rückgängig zu machen.</p>
|
||||
Dies ermöglicht die Aufteilung des split-Nodes automatisch rückgängig zu machen.</p>
|
||||
|
||||
<h4><b>Manueller Modus</b></h4>
|
||||
<p>Im manuellen Modus werden Nachrichtensequenzen auf verschiedenen Arten zusammengefügt:</p>
|
||||
|
@@ -26,8 +26,8 @@
|
||||
<p>Für Zahlenwerte kann die numerische Sortierreihenfolge festgelegt werden.</p>
|
||||
<p>Der Sortierschlüssel kann ein Elementwert oder ein JSONata-Ausdruck beim Sortieren einer Nachrichteneigenschaft
|
||||
bzw. eine Nachrichteneigenschaft oder ein JSONata-Ausdruck beim Sortieren einer Nachrichtensequenz sein.<p>
|
||||
<p>Zum Sortieren einer Nachrichtensequenz benötigt der <span style="background-color:Gainsboro">sort</span>-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
|
||||
Diese Eigenschaft wird vom <span style="background-color:Gainsboro">split</span>-Node erzeugt und kann aber auch manuell erzeugt werden.
|
||||
<p>Zum Sortieren einer Nachrichtensequenz benötigt der sort-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
|
||||
Diese Eigenschaft wird vom split-Node erzeugt und kann aber auch manuell erzeugt werden.
|
||||
Sie hat die folgenden Eigenschaften:</p>
|
||||
<p>
|
||||
<ul>
|
||||
|
@@ -58,5 +58,5 @@
|
||||
aber typischerweise 64k (Linux/Mac) oder 41k (Windows).</p>
|
||||
<p>Bei Aufteilung in mehrere Nachrichten besitzt jede eine <code>parts</code>-Eigenschaft,
|
||||
welche eine komplette Nachrichten-Sequenz bildet.</p>
|
||||
<p>Fehler sollten mittels <span style="background-color:Gainsboro">catch</span>-Nodes abgefangen und behandelt werden.</p>
|
||||
<p>Fehler sollten mittels catch-Nodes abgefangen und behandelt werden.</p>
|
||||
</script>
|
||||
|
@@ -579,7 +579,9 @@
|
||||
"server": "Server",
|
||||
"return": "Return",
|
||||
"ms": "ms",
|
||||
"chars": "chars"
|
||||
"chars": "chars",
|
||||
"close": "Close",
|
||||
"optional": "(optional)"
|
||||
},
|
||||
"type": {
|
||||
"listen": "Listen on",
|
||||
@@ -596,7 +598,7 @@
|
||||
"return": {
|
||||
"timeout": "after a fixed timeout of",
|
||||
"character": "when character received is",
|
||||
"number": "a fixed number of chars",
|
||||
"number": "after a fixed number of characters",
|
||||
"never": "never - keep connection open",
|
||||
"immed": "immediately - don't wait for reply"
|
||||
},
|
||||
@@ -616,11 +618,11 @@
|
||||
"timeout": "timeout closed socket port __port__",
|
||||
"cannot-listen": "unable to listen on port __port__, error: __error__",
|
||||
"error": "error: __error__",
|
||||
|
||||
"socket-error": "socket error from __host__:__port__",
|
||||
"no-host": "Host and/or port not set",
|
||||
"connect-timeout": "connect timeout",
|
||||
"connect-fail": "connect failed"
|
||||
"connect-fail": "connect failed",
|
||||
"bad-string": "failed to convert to string"
|
||||
}
|
||||
},
|
||||
"udp": {
|
||||
|
@@ -29,3 +29,12 @@
|
||||
<p>linkノード間のリンクはlinkノードを選択した場合にのみ表示されます。他のタブへのリンクがある場合には、仮想的なノードを表示します。この仮想的ノードをクリックすると、対応するタブに移動できます。</p>
|
||||
<p><b>注: </b>サブフローの外から中、もしくは、中から外へのリンクを作成することはできません。</p>
|
||||
</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>
|
||||
|
@@ -144,11 +144,16 @@
|
||||
"filterCurrent": "現在のフロー",
|
||||
"debugNodes": "debugノード",
|
||||
"clearLog": "ログを削除",
|
||||
"clearFilteredLog": "選択したメッセージを削除",
|
||||
"filterLog": "ログのフィルタリング",
|
||||
"openWindow": "新しいウィンドウで開く",
|
||||
"copyPath": "パスをコピー",
|
||||
"copyPayload": "値をコピー",
|
||||
"pinPath": "展開を固定"
|
||||
"pinPath": "展開を固定",
|
||||
"selectAll": "全てを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"all": "全て",
|
||||
"filtered": "選択したメッセージ"
|
||||
},
|
||||
"messageMenu": {
|
||||
"collapseAll": "全パスを折りたたむ",
|
||||
@@ -159,7 +164,15 @@
|
||||
},
|
||||
"link": {
|
||||
"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設定",
|
||||
@@ -282,7 +295,9 @@
|
||||
"and": "回/",
|
||||
"rate": "流量",
|
||||
"msgper": "メッセージ/",
|
||||
"queuemsg": "中間メッセージをキューに追加",
|
||||
"dropmsg": "中間メッセージを削除",
|
||||
"sendmsg": "2番目の出力で中間メッセージを送信",
|
||||
"allowrate": "msg.rate(ミリ秒単位)で流量値を上書き",
|
||||
"label": {
|
||||
"delay": "delay",
|
||||
@@ -401,7 +416,11 @@
|
||||
"maximumPacketSize": "最大パケット長",
|
||||
"receiveMaximum": "最大受信数",
|
||||
"session": "セッション",
|
||||
"delay": "遅延"
|
||||
"delay": "遅延",
|
||||
"action": "動作",
|
||||
"staticTopic": "1つのトピックを購読",
|
||||
"dynamicTopic": "動的な購読",
|
||||
"auto-connect": "自動接続"
|
||||
},
|
||||
"sections-label": {
|
||||
"birth-message": "接続時の送信メッセージ(Birthメッセージ)",
|
||||
@@ -442,7 +461,10 @@
|
||||
"invalid-topic": "不正なトピックが設定されています",
|
||||
"nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません",
|
||||
"invalid-json-string": "不正なJSON文字列",
|
||||
"invalid-json-parse": "JSON文字列のパースに失敗しました"
|
||||
"invalid-json-parse": "JSON文字列のパースに失敗しました",
|
||||
"invalid-action-action": "指定された動作が不正です",
|
||||
"invalid-action-alreadyconnected": "接続する前にブローカから切断してください",
|
||||
"invalid-action-badsubscription": "msg.topicが存在しないか不正です"
|
||||
}
|
||||
},
|
||||
"httpin": {
|
||||
@@ -478,6 +500,7 @@
|
||||
"proxy-config": "プロキシ設定",
|
||||
"use-proxyauth": "プロキシ認証を使用",
|
||||
"noproxy-hosts": "例外ホスト",
|
||||
"senderr": "2xx以外の応答をcatchノードへ送信",
|
||||
"utf8": "UTF8文字列",
|
||||
"binary": "バイナリバッファ",
|
||||
"json": "JSONオブジェクト",
|
||||
@@ -703,13 +726,15 @@
|
||||
"delete": "delete __property__",
|
||||
"move": "move __property__",
|
||||
"changeCount": "change: __count__ rules",
|
||||
"regex": "正規表現を使用"
|
||||
"regex": "正規表現を使用",
|
||||
"deepCopy": "値のディープコピー"
|
||||
},
|
||||
"action": {
|
||||
"set": "値の代入",
|
||||
"change": "値の置換",
|
||||
"delete": "値の削除",
|
||||
"move": "値の移動",
|
||||
"toValue": "対象の値",
|
||||
"to": "対象の値",
|
||||
"search": "検索する文字列",
|
||||
"replace": "置換後の文字列"
|
||||
@@ -851,6 +876,8 @@
|
||||
},
|
||||
"file": {
|
||||
"label": {
|
||||
"write": "write file",
|
||||
"read": "read file",
|
||||
"filename": "ファイル名",
|
||||
"action": "動作",
|
||||
"addnewline": "メッセージの入力のたびに改行を追加",
|
||||
@@ -858,7 +885,6 @@
|
||||
"outputas": "出力形式",
|
||||
"breakchunks": "チャンクへ分割",
|
||||
"breaklines": "行へ分割",
|
||||
"filelabel": "file",
|
||||
"sendError": "エラーメッセージを送信(互換モード)",
|
||||
"encoding": "文字コード",
|
||||
"deletelabel": "delete __file__",
|
||||
|
@@ -771,7 +771,6 @@
|
||||
"outputas": "출력형식",
|
||||
"breakchunks": "청크로 분할",
|
||||
"breaklines": "행으로 분할",
|
||||
"filelabel": "file",
|
||||
"sendError": "에러메세지를 송신(호환모드)",
|
||||
"deletelabel": "delete __file__",
|
||||
"utf8String": "UTF8문자열",
|
||||
|
@@ -816,7 +816,6 @@
|
||||
"outputas": "Выход",
|
||||
"breakchunks": "Разбить файл на части",
|
||||
"breaklines": "Разбить на строки",
|
||||
"filelabel": "файл",
|
||||
"sendError": "Отправлять сообщение при ошибке (устаревший режим)",
|
||||
"encoding": "Кодировка",
|
||||
"deletelabel": "удалить __file__",
|
||||
|
@@ -804,7 +804,6 @@
|
||||
"outputas": "输出",
|
||||
"breakchunks": "分拆成块",
|
||||
"breaklines": "分拆成行",
|
||||
"filelabel": "文件",
|
||||
"sendError": "发生错误时发送消息(传统模式)",
|
||||
"encoding": "编码",
|
||||
"deletelabel": "删除 __file__",
|
||||
|
@@ -809,7 +809,6 @@
|
||||
"outputas": "輸出",
|
||||
"breakchunks": "分拆成塊",
|
||||
"breaklines": "分拆成行",
|
||||
"filelabel": "文件",
|
||||
"sendError": "發生錯誤時發送消息(傳統模式)",
|
||||
"encoding": "編碼",
|
||||
"deletelabel": "刪除 __file__",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -15,13 +15,13 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"acorn": "8.5.0",
|
||||
"acorn": "8.6.0",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.6.3",
|
||||
"ajv": "8.8.2",
|
||||
"body-parser": "1.19.0",
|
||||
"cheerio": "1.0.0-rc.10",
|
||||
"content-type": "1.0.4",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cookie": "0.4.1",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
@@ -29,7 +29,7 @@
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"got": "11.8.3",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "0.1.2",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
@@ -40,7 +40,7 @@
|
||||
"multer": "1.4.3",
|
||||
"mustache": "4.2.0",
|
||||
"on-headers": "1.0.2",
|
||||
"raw-body": "2.4.1",
|
||||
"raw-body": "2.4.2",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.1",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,11 +16,11 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.1.2",
|
||||
"@node-red/util": "2.2.0-beta.1",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "10.0.0",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.11",
|
||||
"uglify-js": "3.14.2"
|
||||
"uglify-js": "3.14.4"
|
||||
}
|
||||
}
|
||||
|
@@ -439,8 +439,6 @@ class Flow {
|
||||
}
|
||||
}
|
||||
return [env.name, env];
|
||||
|
||||
return [env.name, env];
|
||||
});
|
||||
group._env = Object.fromEntries(entries);
|
||||
}
|
||||
@@ -457,24 +455,24 @@ class Flow {
|
||||
const val
|
||||
= ((value === "true") ||
|
||||
(value === true));
|
||||
return {
|
||||
return [{
|
||||
val: val
|
||||
};
|
||||
}, null];
|
||||
}
|
||||
if (type === "cred") {
|
||||
return {
|
||||
return [{
|
||||
val: value
|
||||
};
|
||||
}, null];
|
||||
}
|
||||
try {
|
||||
var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
|
||||
return {
|
||||
return [{
|
||||
val: val
|
||||
};
|
||||
}, null];
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e);
|
||||
return null;
|
||||
return [null, null];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -488,7 +486,7 @@ class Flow {
|
||||
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);
|
||||
}
|
||||
|
@@ -373,10 +373,11 @@ class Subflow extends Flow {
|
||||
const node = this.subflowInstance;
|
||||
if (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) {
|
||||
return result.val;
|
||||
}
|
||||
name = newName;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "2.1.2",
|
||||
"@node-red/util": "2.1.2",
|
||||
"@node-red/registry": "2.2.0-beta.1",
|
||||
"@node-red/util": "2.2.0-beta.1",
|
||||
"async-mutex": "0.3.2",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.17.1",
|
||||
|
@@ -136,8 +136,6 @@ function getCurrentLocale() {
|
||||
|
||||
function init(settings) {
|
||||
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) => {
|
||||
i18n.use(MessageFileLoader);
|
||||
var opt = {
|
||||
@@ -146,6 +144,8 @@ function init(settings) {
|
||||
defaultNS: "runtime",
|
||||
ns: [],
|
||||
fallbackLng: defaultLang,
|
||||
keySeparator: ".",
|
||||
nsSeparator: ":",
|
||||
interpolation: {
|
||||
unescapeSuffix: 'HTML',
|
||||
escapeValue: false,
|
||||
|
12
packages/node_modules/@node-red/util/lib/util.js
vendored
12
packages/node_modules/@node-red/util/lib/util.js
vendored
@@ -526,10 +526,11 @@ function getSetting(node, name, flow_) {
|
||||
if (flow) {
|
||||
if (node && 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) {
|
||||
return result.val;
|
||||
}
|
||||
name = newName;
|
||||
}
|
||||
return flow.getSetting(name);
|
||||
}
|
||||
@@ -842,6 +843,9 @@ function encodeObject(msg,opts) {
|
||||
length: msg.msg.size
|
||||
}
|
||||
needsStringify = true;
|
||||
} else if (msg.msg && msg.msg.constructor.name === "RegExp") {
|
||||
msg.format = 'regexp';
|
||||
msg.msg = msg.msg.toString();
|
||||
}
|
||||
if (needsStringify || (msg.format === "Object")) {
|
||||
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)),
|
||||
length: value.size
|
||||
}
|
||||
} else if (value.constructor.name === "RegExp") {
|
||||
value = {
|
||||
__enc__: true,
|
||||
type: "regexp",
|
||||
data: value.toString()
|
||||
}
|
||||
}
|
||||
} else if (value === undefined) {
|
||||
value = {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -16,10 +16,10 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"fs-extra": "10.0.0",
|
||||
"i18next": "21.3.1",
|
||||
"i18next": "21.5.4",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.5",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"moment-timezone": "0.5.33"
|
||||
"moment-timezone": "0.5.34"
|
||||
}
|
||||
}
|
||||
|
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",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "2.1.2",
|
||||
"@node-red/runtime": "2.1.2",
|
||||
"@node-red/util": "2.1.2",
|
||||
"@node-red/nodes": "2.1.2",
|
||||
"@node-red/editor-api": "2.2.0-beta.1",
|
||||
"@node-red/runtime": "2.2.0-beta.1",
|
||||
"@node-red/util": "2.2.0-beta.1",
|
||||
"@node-red/nodes": "2.2.0-beta.1",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.17.1",
|
||||
|
5
packages/node_modules/node-red/red.js
vendored
5
packages/node_modules/node-red/red.js
vendored
@@ -194,6 +194,11 @@ if (process.env.NODE_RED_ENABLE_PROJECTS) {
|
||||
settings.editorTheme.projects.enabled = !/^false$/i.test(process.env.NODE_RED_ENABLE_PROJECTS);
|
||||
}
|
||||
|
||||
if (process.env.NODE_RED_ENABLE_TOURS) {
|
||||
settings.editorTheme = settings.editorTheme || {};
|
||||
settings.editorTheme.tours = !/^false$/i.test(process.env.NODE_RED_ENABLE_TOURS);
|
||||
}
|
||||
|
||||
|
||||
var defaultServerSettings = {
|
||||
"x-powered-by": false
|
||||
|
@@ -9,29 +9,36 @@ const LATEST = "2";
|
||||
function generateScript() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const packages = [
|
||||
"node-red-util",
|
||||
"node-red-runtime",
|
||||
"node-red-registry",
|
||||
"node-red-nodes",
|
||||
"node-red-editor-client",
|
||||
"node-red-editor-api",
|
||||
"@node-red/util",
|
||||
"@node-red/runtime",
|
||||
"@node-red/registry",
|
||||
"@node-red/nodes",
|
||||
"@node-red/editor-client",
|
||||
"@node-red/editor-api",
|
||||
"node-red"
|
||||
];
|
||||
const rootPackage = require(path.join(__dirname,"..","package.json"));
|
||||
const version = rootPackage.version;
|
||||
|
||||
const versionParts = version.split(".");
|
||||
let updateNextToLatest = false;
|
||||
let tagArg = "";
|
||||
if (versionParts[0] !== LATEST) {
|
||||
tagArg = `--tag v${versionParts[0]}-maintenance`
|
||||
} else if (/-/.test(version)) {
|
||||
tagArg = "--tag next"
|
||||
} else {
|
||||
updateNextToLatest = true;
|
||||
}
|
||||
|
||||
const lines = [];
|
||||
|
||||
packages.forEach(name => {
|
||||
lines.push(`npm publish ${name}-${version}.tgz ${tagArg}\n`);
|
||||
const tarName = name.replace(/@/,"").replace(/\//,"-")
|
||||
lines.push(`npm publish ${tarName}-${version}.tgz ${tagArg}\n`);
|
||||
if (updateNextToLatest) {
|
||||
lines.push(`npm dist-tag add ${name}@${version} next\n`);
|
||||
}
|
||||
})
|
||||
resolve(lines.join(""))
|
||||
});
|
||||
|
@@ -84,9 +84,17 @@ describe('TCP Request Node', function() {
|
||||
n2.on("input", msg => {
|
||||
try {
|
||||
if (typeof result === 'object') {
|
||||
msg.should.have.properties(Object.assign({}, result, {payload: Buffer.from(result.payload)}));
|
||||
if (flow[0].ret === "string") {
|
||||
msg.should.have.properties(Object.assign({}, result, {payload: result.payload}));
|
||||
} else {
|
||||
msg.should.have.properties(Object.assign({}, result, {payload: Buffer.from(result.payload)}));
|
||||
}
|
||||
} else {
|
||||
msg.should.have.property('payload', Buffer.from(result));
|
||||
if (flow[0].ret === "string") {
|
||||
msg.should.have.property('payload', result);
|
||||
} else {
|
||||
msg.should.have.property('payload', Buffer.from(result));
|
||||
}
|
||||
}
|
||||
done();
|
||||
} catch(err) {
|
||||
@@ -245,10 +253,41 @@ describe('TCP Request Node', function() {
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection, and not split return strings', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", ret:"string", newline:"", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo",
|
||||
topic: 'boo'
|
||||
}, {
|
||||
payload: "bar<A>\nfoo",
|
||||
topic: 'boo'
|
||||
}], {
|
||||
payload: "ACK:foobar<A>\nfoo",
|
||||
topic: 'boo'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection, and split return strings', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", ret:"string", newline:"<A>\\n", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo",
|
||||
topic: 'boo'
|
||||
}, {
|
||||
payload: "bar<A>\nfoo",
|
||||
topic: 'boo'
|
||||
}], {
|
||||
payload: "ACK:foobar<A>",
|
||||
topic: 'boo'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data to/from server:port from msg', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
testTCPMany(flow, [
|
||||
{
|
||||
payload: "f",
|
||||
host: "localhost",
|
||||
port: port
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user