Compare commits

..

95 Commits

Author SHA1 Message Date
Nick O'Leary
a40e5dbcd4 Add check that node sends object rather than primitive type
Fixes #3876
2022-10-04 11:49:49 +01:00
Nick O'Leary
93c1600980 Merge pull request #3886 from kazuhitoyokoi/master2
Limit number of ports in function node
2022-10-04 11:00:18 +01:00
Nick O'Leary
c3d1e6181f Merge pull request #3894 from hardillb/http-response-status-number
Ensure statusCode is a number
2022-10-04 10:28:04 +01:00
Ben Hardill
4115c13a65 Ensure statusCode is a number
Fixes #3893

Used parseInt instead of the suggested fix so that we don't end up
with statusCode = 200.5
2022-09-19 19:43:06 +01:00
Kazuhito Yokoi
ce31edc803 Fix handling of max and min values in function outputs 2022-09-18 02:22:52 +09:00
Kazuhito Yokoi
199caccbc3 Change the maximum number of ports to 500 2022-09-17 00:25:46 +09:00
Nick O'Leary
f060309002 Merge pull request #3872 from node-red-hitachi/fix-Japanese-editor-message-for-JSONata
Fix Japanese translation for JSONata editor
2022-09-15 21:25:30 +01:00
Nick O'Leary
fc3d86e6ff Merge pull request #3882 from kazuhitoyokoi/master-addenvinfo2template
Add information about environment variable to template node
2022-09-15 21:24:32 +01:00
Kazuhito Yokoi
7507a7b459 Limit number of ports in function node 2022-09-16 02:10:14 +09:00
Kazuhito Yokoi
d657817211 Add information about environment variable to template node 2022-09-13 22:08:22 +09:00
Hiroyasu Nishiyama
954649007c merge master 2022-09-13 10:52:48 +09:00
Nick O'Leary
b0d9903fe2 Merge pull request #3873 from node-red-hitachi/fix-describe-arg
Remove done from describe
2022-09-12 19:29:14 +01:00
Nick O'Leary
6375f3c445 Merge pull request #3841 from Steve-Mcl/fix-search-type-with-spaces
Fix search type with spaces
2022-09-12 19:27:09 +01:00
Nick O'Leary
2328f418be Merge pull request #3871 from node-red-hitachi/fix-extended-function-error-handling-of-jsonata-editor
Fix error hanndling of JSONata expression editor for extended functions
2022-09-12 19:26:15 +01:00
Nick O'Leary
22b6564847 Merge pull request #3880 from kazuhitoyokoi/master-replacedot4function
Remove dot from variable name for external module in function node
2022-09-12 19:25:39 +01:00
Nick O'Leary
25c8bfefe2 Merge pull request #3868 from Steve-Mcl/func-types-monaco-util-promisify
add function node monaco types util and promisify
2022-09-12 19:25:07 +01:00
Nick O'Leary
30f4524821 Merge pull request #3866 from kazuhitoyokoi/master-fixbutton4addsshkey
Add button type to the adding SSH key button
2022-09-12 19:18:49 +01:00
Nick O'Leary
9e4c3a7200 Merge pull request #3879 from kazuhitoyokoi/master-fixradiobutton4project
Check radio button as default in project dialog
2022-09-12 19:18:15 +01:00
Nick O'Leary
5b7e84c1b0 Merge pull request #3869 from Steve-Mcl/fix-mqtt-birth-bad-topic-crash
Prevent invalid mqtt birth topic crashing node-red
2022-09-12 19:17:43 +01:00
Nick O'Leary
e6097e4968 Merge pull request #3874 from node-red-hitachi/support-clone-in-monaco
Add $clone as supported function
2022-09-12 19:16:18 +01:00
Kazuhito Yokoi
0f2829097b Remove dot from variable name for external module in function node 2022-09-10 12:17:18 +09:00
Kazuhito Yokoi
e2a9f940e2 Check radio button as default in project dialog 2022-09-09 01:05:53 +09:00
Hiroyasu Nishiyama
3eb2b2ac5d add $clone as supported function 2022-09-06 18:52:13 +09:00
Hiroyasu Nishiyama
ce7b0a3b5e remove done from describe 2022-09-06 18:05:50 +09:00
Hiroyasu Nishiyama
7bd7c99dd4 Fix Japanese translation for JSONata editor 2022-09-06 16:53:38 +09:00
Hiroyasu Nishiyama
b0d12c4125 Fix error hanndling of JSONata expression editor for extennded functions 2022-09-06 15:38:49 +09:00
Kazuhito Yokoi
745607b5bc Add button type to buttons on node properties 2022-09-04 23:21:34 +09:00
Kazuhito Yokoi
cc5a770b16 Add button type to buttons on projects dialog 2022-09-04 21:58:02 +09:00
Steve-Mcl
fbde0091de fix node-red crash with invalid mqtt birth topic
fixes #3865
2022-09-04 11:08:41 +01:00
Steve-Mcl
a533943a40 add function node monaco types util and promisify
fixes #3851
2022-09-04 01:50:54 +01:00
Stephen McLaughlin
e11f17672c Update packages/node_modules/@node-red/editor-client/src/js/ui/palette.js 2022-09-03 22:01:54 +01:00
Stephen McLaughlin
c038c99f9d Update packages/node_modules/@node-red/editor-client/src/js/ui/search.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-09-03 21:54:41 +01:00
Stephen McLaughlin
5f159c1fbd Update packages/node_modules/@node-red/editor-client/src/js/ui/search.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-09-03 21:54:21 +01:00
Kazuhito Yokoi
cd8ca8981b Add button type to the adding SSH key button 2022-09-03 21:03:08 +09:00
Nick O'Leary
a5d7f7acce Merge pull request #3842 from hardillb/fix-broken-headers-tests
Add missing property to node object HTTPRequest
2022-09-02 20:46:22 +01:00
Nick O'Leary
a032c2e326 Merge pull request #3840 from Steve-Mcl/fix-mqtt-session-time
ensure sessionExpiry(Interval) is applied
2022-09-02 20:45:41 +01:00
Nick O'Leary
9d770ed436 Merge pull request #3857 from kazuhitoyokoi/master-fixeditablelist4httprequest
Support sortable list on property UI of http request and http response nodes
2022-09-02 20:45:08 +01:00
Nick O'Leary
ae753940f3 Merge pull request #3852 from kazuhitoyokoi/master-addjpn
Add Japanese translation for v3.0.2
2022-09-02 20:44:45 +01:00
Kazuhito Yokoi
d0d22c333c Add Japanese translation for v3.0.2 2022-08-28 02:04:13 +09:00
Kazuhito Yokoi
266ba17ebb Use sortable list in http response node and proxy setting 2022-08-18 11:52:56 +09:00
Kazuhito Yokoi
0d0d5bafb0 Make pre-defined header list sortable in http request node 2022-08-18 01:29:07 +09:00
Ben Hardill
58b951e134 Make port number dynamic in test 2022-08-14 15:09:48 +01:00
Ben Hardill
30956b5441 Add missing property to node object HTTPRequest
Also add tests for broken headers
2022-08-14 15:02:39 +01:00
Steve-Mcl
9540cfe749 fix flags search without val 2022-08-13 18:09:11 +01:00
Steve-Mcl
31b17faa2a fix MQTT test fail due to birth sent before connection done 2022-08-12 18:23:07 +01:00
Steve-Mcl
5c6b8e9e50 opportunistic tidy up MQTT tests 2022-08-12 18:21:36 +01:00
Steve-Mcl
5a36e8fb11 add tests for MQTT v5 (sessionExpiry property) 2022-08-12 18:20:11 +01:00
Steve-Mcl
7d4c857a43 ensure sessionExpiry(Interval) is applied 2022-08-12 15:47:15 +01:00
Steve-Mcl
598bcf675f fix searching by type when type name has a space 2022-08-12 15:45:12 +01:00
Nick O'Leary
5365786386 Merge pull request #3830 from node-red/release-302
Bump for 3.0.2
2022-08-04 14:13:26 +01:00
Nick O'Leary
c9b0a7c2dd Bump for 3.0.2 2022-08-04 13:50:31 +01:00
Nick O'Leary
371d8042d6 Merge pull request #3776 from hardillb/relaxed-http-req-headers
Allow HTTP Headers not in spec
2022-08-04 13:36:24 +01:00
Nick O'Leary
be343cb21e Merge pull request #3812 from bonanitech/workspace-chart-bottom
Fix workspace chart bottom property
2022-08-04 13:12:21 +01:00
Nick O'Leary
e9eabd6881 Merge pull request #3802 from Dennis14e/patch-de-2
Update german translation
2022-08-04 13:10:52 +01:00
Nick O'Leary
abccdc7f21 Update packages/node_modules/@node-red/nodes/locales/en-US/messages.json 2022-08-04 13:10:05 +01:00
Nick O'Leary
4ae914f729 Merge pull request #3801 from kazuhitoyokoi/master-subflowcolor
Support color reset to the default in subflow and group
2022-08-04 13:02:04 +01:00
Nick O'Leary
86ac955b79 Merge pull request #3817 from node-red/fix-regex-name-handle
Allow generateNodeNames to handle names containing regex control chars
2022-08-04 12:58:06 +01:00
Nick O'Leary
9734691cac Merge pull request #3808 from bonanitech/overflow-auto
Hide scrollbars until they're needed
2022-08-04 12:57:53 +01:00
Nick O'Leary
d94f3a477d Merge pull request #3818 from node-red/fix-subflow-module-node-lookup
Register subflow module instance node with parent flow
2022-08-04 12:57:21 +01:00
Nick O'Leary
d53cd209f7 Merge pull request #3816 from node-red/import-junction-fix
Include junctions/groups when exporting subflows plus related fixes
2022-08-04 12:57:06 +01:00
Nick O'Leary
65cacb39d2 Merge pull request #3820 from node-red/remove-console-log-subflow-js
remove console.log
2022-08-04 12:56:48 +01:00
Stephen McLaughlin
b008a6a2aa remove console.log
fixes #3819
2022-08-04 11:05:27 +01:00
Nick O'Leary
5c29feec63 Register subflow module instance node with parent flow
Fixes #3798
2022-08-02 00:05:21 +01:00
Nick O'Leary
d8e350d603 Allow generateNodeNames to handle names containing regex control characters
Fixes #3813
2022-08-01 21:05:52 +01:00
Nick O'Leary
14a3366850 Include junctins/groups when exporting subflows plus related fixes
Fixes #3805
2022-08-01 20:54:05 +01:00
Mauricio Bonani
5ea0c6fca1 Fix workspace chart bottom property 2022-07-29 09:49:59 -04:00
Mauricio Bonani
f454c29b8c Hide scrollbars until they're needed 2022-07-28 10:56:38 -04:00
Dennis Neufeld
fe5132be1d Update german translation 2 2022-07-24 16:31:01 +02:00
Dennis Neufeld
b50ba3e0e4 Update german translation 2022-07-23 18:53:39 +02:00
Kazuhito Yokoi
4fb40f9077 Support color reset to the default in subflow 2022-07-23 21:39:07 +09:00
Nick O'Leary
dc7fef6395 Merge pull request #3797 from node-red/301
Update changelog and bump for 3.0.1
2022-07-22 10:27:46 +01:00
Nick O'Leary
da65bf7292 Update changelog and bump for 3.0.1 2022-07-22 09:50:37 +01:00
Nick O'Leary
17d9c2577e Merge pull request #3794 from Steve-Mcl/fix-code-editor-theme-from-theme
Allow codeEditor theme to be set even if `codeEditor` is not set in settings.js
2022-07-21 16:27:41 +01:00
Steve-Mcl
bc7852c1cc Allow codeEditor theme to be set missing from settings.js 2022-07-21 14:44:29 +01:00
Nick O'Leary
51d8792f62 Merge pull request #3793 from Steve-Mcl/sys-info-amendments
Sys info (diagnostics report) amendments
2022-07-21 11:39:50 +01:00
Nick O'Leary
bfdbeb0964 Merge pull request #3791 from Steve-Mcl/allow-editor-create-no-title-no-mode
Allow `mode` and `title` to be omitted in `options` argument for `createEditor`
2022-07-21 11:39:02 +01:00
Nick O'Leary
ede82ad0d5 Merge pull request #3789 from Steve-Mcl/fix-focus-issues
Fix focus issues
2022-07-21 11:38:38 +01:00
Nick O'Leary
f50dcb9e40 Merge pull request #3788 from node-red/fix-typedinput-submit
Ensure all typedInput buttons have button type set
2022-07-21 11:37:52 +01:00
Nick O'Leary
676c5e5df5 Merge pull request #3787 from node-red/fix-search-unused
Do not flag hasUsers=false nodes as unused in search
2022-07-21 11:37:39 +01:00
Nick O'Leary
d52be76c8a Merge pull request #3786 from node-red/fix-quick-add-pos
Properly position quick-add dialog in all cases
2022-07-21 11:37:26 +01:00
Nick O'Leary
c6a517c88c Merge pull request #3785 from node-red/ts-pos
Ensure quick-add dialog does not obscure ghost node when shifted
2022-07-21 11:37:10 +01:00
Nick O'Leary
96eb8719b8 Merge pull request #3784 from node-red/remove-hasown
Remove use of Object.hasOwn
2022-07-21 11:36:56 +01:00
Steve-Mcl
bcd31610f6 update tests for sys info diagnostics ammendments 2022-07-21 10:07:40 +01:00
Steve-Mcl
a4d66622a5 add a handful of missing settings to basic report 2022-07-21 09:30:49 +01:00
Steve-Mcl
af4f07cb26 include flows stop/start state 2022-07-21 09:29:51 +01:00
Steve-Mcl
f7120b32f5 Allow mode and title to be empty
fixes #3774
2022-07-20 13:58:03 +01:00
Steve-Mcl
273404e24d focus search input when opened via context menu 2022-07-20 12:30:52 +01:00
Steve-Mcl
1b53b5b927 focus stack when re-showing nested editor 2022-07-20 12:30:15 +01:00
Steve-Mcl
7c5413e568 ensure red-ui-editor-stack is focusable 2022-07-20 12:29:16 +01:00
Nick O'Leary
39b2fe45a5 Ensure all typedInput buttons have button type set
Fixes #3780

Otherwise they act as type="submit" and the browser will click on them
when enter is pressed in an input
2022-07-20 11:11:44 +01:00
Nick O'Leary
8d3c5d09f6 Do not flag hasUsers=false nodes as unused in search
Fixes #3777
2022-07-20 10:47:57 +01:00
Nick O'Leary
5944fdb5dc Properly position quick-add dialog in all cases
Fixes #3781
2022-07-20 10:40:20 +01:00
Nick O'Leary
e120bad779 Ensure quick-add dialog does not obscure ghost node when shifted 2022-07-20 10:37:40 +01:00
Nick O'Leary
d546a4a15b Remove use of Object.hasOwn
Fixes #3778
2022-07-20 10:14:06 +01:00
Ben Hardill
660a2e0ed6 Allow HTTP Headers not in spec
potential fix for #3772
2022-07-16 19:51:35 +01:00
73 changed files with 887 additions and 622 deletions

View File

@@ -1,3 +1,37 @@
#### 3.0.2: Maintenance Release
Editor
- Fix workspace chart bottom property (#3812) @bonanitech
- Update german translation (#3802) @Dennis14e
- Support color reset to the default in subflow and group (#3801) @kazuhitoyokoi
- Allow generateNodeNames to handle names containing regex control chars (#3817) @knolleary
- Hide scrollbars until they're needed (#3808) @bonanitech
- Include junctions/groups when exporting subflows plus related fixes (#3816) @knolleary
- remove console.log (#3820) @Steve-Mcl
Runtime
- Register subflow module instance node with parent flow (#3818) @knolleary
Nodes
- HTTP Request: Allow HTTP Headers not in spec (#3776) @hardillb
#### 3.0.1: Maintenance Release
Editor
- Allow codeEditor theme to be set even if `codeEditor` is not set in settings.js (#3794) @Steve-Mcl
- Sys info (diagnostics report) amendments (#3793) @Steve-Mcl
- Allow `mode` and `title` to be omitted in `options` argument for `createEditor` (#3791) @Steve-Mcl
- Fix focus issues (#3789) @Steve-Mcl
- Ensure all typedInput buttons have button type set (#3788) @knolleary
- Do not flag hasUsers=false nodes as unused in search (#3787) @knolleary
- Properly position quick-add dialog in all cases (#3786) @knolleary
- Ensure quick-add dialog does not obscure ghost node when shifted (#3785) @knolleary
- Remove use of Object.hasOwn (#3784) @knolleary
#### 3.0.0: Milestone Release
Editor

View File

@@ -152,7 +152,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/history.js",
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/utils-domselection.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -40,7 +40,7 @@
"cookie-parser": "1.4.6",
"cors": "2.8.5",
"cronosjs": "1.7.1",
"denque": "2.0.1",
"denque": "2.1.0",
"express": "4.18.1",
"express-session": "1.17.3",
"form-data": "4.0.0",
@@ -49,7 +49,7 @@
"hash-sum": "2.0.0",
"hpagent": "1.0.0",
"https-proxy-agent": "5.0.1",
"i18next": "21.8.14",
"i18next": "21.8.16",
"iconv-lite": "0.6.3",
"is-utf8": "0.2.1",
"js-yaml": "4.1.0",
@@ -76,7 +76,7 @@
"semver": "7.3.7",
"tar": "6.1.11",
"tough-cookie": "4.0.0",
"uglify-js": "3.16.2",
"uglify-js": "3.16.3",
"uuid": "8.3.2",
"ws": "7.5.6",
"xml2js": "0.4.23"
@@ -85,7 +85,7 @@
"bcrypt": "5.0.1"
},
"devDependencies": {
"dompurify": "2.3.9",
"dompurify": "2.3.10",
"grunt": "1.5.3",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.4.3",
@@ -114,7 +114,7 @@
"node-red-node-test-helper": "^0.3.0",
"nodemon": "2.0.19",
"proxy": "^1.0.2",
"sass": "1.53.0",
"sass": "1.54.2",
"should": "13.2.3",
"sinon": "11.1.2",
"stoppable": "^1.1.0",

View File

@@ -327,9 +327,8 @@ module.exports = {
themeContext.header.url = themePlugin.header.url || themeContext.header.url
}
}
if(theme.codeEditor) {
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
}
theme.codeEditor = theme.codeEditor || {}
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
}
activeThemeInitialised = true;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/util": "3.1.0-beta.0",
"@node-red/editor-client": "3.1.0-beta.0",
"@node-red/util": "3.0.2",
"@node-red/editor-client": "3.0.2",
"bcryptjs": "2.4.3",
"body-parser": "1.20.0",
"clone": "2.1.2",

View File

@@ -105,7 +105,7 @@
"search": "Flows durchsuchen",
"searchInput": "Flows durchsuchen",
"subflows": "Subflow",
"createSubflow": "Subflow",
"createSubflow": "Hinzufügen",
"selectionToSubflow": "Auswahl in Subflow umwandeln",
"flows": "Flow",
"add": "Hinzufügen",
@@ -152,7 +152,8 @@
"zoom-in": "Vergrößern",
"search-flows": "Flows durchsuchen",
"search-prev": "Vorherige",
"search-next": "Nächste"
"search-next": "Nächste",
"search-counter": "\"__term__\" __result__ von __count__"
},
"user": {
"loggedInAs": "Angemeldet als __name__",
@@ -168,7 +169,11 @@
}
},
"notification": {
"warning": "<strong>Warnung:</strong> __message__",
"state": {
"flowsStopped": "Flows gestoppt",
"flowsStarted": "Flows gestartet"
},
"warning": "<strong>Warnung</strong>: __message__",
"warnings": {
"undeployedChanges": "Node hat nicht übernommene (deploy) Änderungen",
"nodeActionDisabled": "Node-Aktionen deaktiviert",
@@ -177,15 +182,15 @@
"missing-modules": "<p>Flows angehalten aufgrund fehlender Module</p>",
"safe-mode": "<p>Flows sind im abgesicherten Modus gestoppt.</p><p>Flows können bearbeitet und übernommen (deploy) werden, um sie neu zu starten.</p>",
"restartRequired": "Node-RED muss neu gestartet werden, damit die Module nach Upgrade aktiviert werden",
"credentials_load_failed": "<p>Flows gestoppt, da die Berechtigungen nicht entschlüsselt werden konnten.</p><p>Die Datei mit dem Flow-Berechtigungen ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p>",
"credentials_load_failed_reset": "<p>Die Berechtigungen konnten nicht entschlüsselt werden.</p><p>Die Datei mit den Flow-Berechtigungen ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p><p>Die Datei mit den Flow-Berechtigungen wird bei der nächsten Übernahme (deploy) zurückgesetzt. Alle vorhandenen Flow-Berechtigungen werden gelöscht.</p>",
"credentials_load_failed": "<p>Flows gestoppt, da die Credentials nicht entschlüsselt werden konnten.</p><p>Die Datei mit den Flow-Credentials ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p>",
"credentials_load_failed_reset": "<p>Die Credentials konnten nicht entschlüsselt werden.</p><p>Die Datei mit den Flow-Credentials ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p><p>Die Datei mit den Flow-Credentials wird bei der nächsten Übernahme (deploy) zurückgesetzt. Alle vorhandenen Flow-Credentials werden gelöscht.</p>",
"missing_flow_file": "<p>Die Flow-Datei des Projekts wurde nicht gefunden.</p><p>Das Projekt ist nicht mit einer Flow-Datei konfiguriert.</p>",
"missing_package_file": "<p>Die Paket-Datei des Projekts wurde nicht gefunden.</p><p>In dem Projekt fehlt die 'package.json'-Datei.</p>",
"project_empty": "<p>Das Projekt ist leer.</p><p>Soll ein Standardsatz an Projektdateien erstellen werden?<br/>Andernfalls müssen die Dateien manuell außerhalb des Editors dem Projekt hinzugefügt werden.</p>",
"project_not_found": "<p>Das Projekt '__project__' wurde nicht gefunden.</p>",
"git_merge_conflict": "<p>Der automatische Merge der Änderungen ist fehlgeschlagen.</p><p>Die Merge-Konflikte müssen behoben und die Ergebnisse ins Repository übertragen werden (commit).</p>"
},
"error": "<strong>Fehler:</strong> __message__",
"error": "<strong>Fehler</strong>: __message__",
"errors": {
"lostConnection": "Verbindung zum Server verloren. Verbindung wird erneut hergestellt ...",
"lostConnectionReconnect": "Verbindung zum Server verloren. Wiederherstellung der Verbindung in __time__s.",
@@ -203,7 +208,7 @@
"pull": "Projekt '__project__' erneut geladen",
"revert": "Änderungen im Projekt '__project__' rückgängig gemacht",
"merge-complete": "Git-Merge abgeschlossen",
"setupCredentials": "Berechtigungen einrichten",
"setupCredentials": "Credentials einrichten",
"setupProjectFiles": "Projektdateien einrichten",
"no": "Nein, Danke",
"createDefault": "Standardprojektdateien erstellen",
@@ -211,7 +216,7 @@
},
"label": {
"manage-project-dep": "Projektabhängigkeiten verwalten",
"setup-cred": "Berechtigungen einrichten",
"setup-cred": "Credentials einrichten",
"setup-project": "Projektdateien einrichten",
"create-default-package": "Standardpaketdatei erstellen",
"no-thanks": "Nein, Danke",
@@ -295,6 +300,10 @@
"modifiedFlowsDesc": "Übernimmt nur Flows, die geänderte Nodes enthalten",
"modifiedNodes": "Geänderte Nodes",
"modifiedNodesDesc": "Übernimmt nur Nodes, die sich geändert haben",
"startFlows": "Start",
"startFlowsDesc": "Flows starten",
"stopFlows": "Stop",
"stopFlowsDesc": "Flows stoppen",
"restartFlows": "Flows neustarten",
"restartFlowsDesc": "Startet die aktuell übernommenen Flows (ohne vorheriges Deploy)",
"successfulDeploy": "Erfolgreich übernommen (deploy)",
@@ -376,7 +385,7 @@
"confirmDelete": "Sind Sie sicher mit dem Löschen dieses Subflows?",
"info": "Beschreibung",
"category": "Kategorie",
"module": "Module",
"module": "Modul",
"license": "Lizenz",
"licenseNone": "Keine",
"licenseOther": "Andere",
@@ -434,7 +443,7 @@
"icon": "Icon",
"inputType": "Eingangstyp",
"selectType": "Wähle Typen ...",
"loadCredentials": "Lade Node-Berechtigungen",
"loadCredentials": "Lade Node-Credentials",
"inputs": {
"input": "Eingang",
"select": "Auswahl",
@@ -450,7 +459,7 @@
"json": "JSON",
"bin": "buffer",
"env": "Umgebungsvariable",
"cred": "Berechtigung"
"cred": "Credentials"
},
"menu": {
"input": "Eingang",
@@ -470,7 +479,7 @@
"errors": {
"scopeChange": "Wenn Sie den Geltungsbereich (scope) ändern, wird er für Nodes in anderen Flows nicht verfügbar sein",
"invalidProperties": "Ungültige Eigenschaften:",
"credentialLoadFailed": "Laden der Node-Berechtigungen fehlgeschlagen"
"credentialLoadFailed": "Laden der Node-Credentials fehlgeschlagen"
}
},
"keyboard": {
@@ -683,7 +692,8 @@
"showHelp": "Hilfe zeigen",
"showInOutline": "Zeige im Editor",
"showTopics": "Zeige Hilfethemen",
"noHelp": "Kein Hilfethema ausgewählt"
"noHelp": "Kein Hilfethema ausgewählt",
"changeLog": "Änderungsprotokoll"
},
"config": {
"name": "Konfigurations-Node",
@@ -737,7 +747,7 @@
"addToProject": "Zu Projekt hinzufügen",
"files": "Dateien",
"flow": "Flow",
"credentials": "Berechtigungen",
"credentials": "Credentials",
"package": "Paket",
"packageCreate": "Datei wird erstellt beim Speichern der Änderungen",
"fileNotExist": "Datei existiert nicht",
@@ -750,7 +760,7 @@
"changeTheEncryptionKey": "Schlüssel ändern",
"currentKey": "Aktueller Schlüssel",
"newKey": "Neuer Schlüssel",
"credentialsAlert": "Dadurch werden alle vorhandenen Berechtigungen gelöscht",
"credentialsAlert": "Dadurch werden alle vorhandenen Credentials gelöscht",
"versionControl": "Versionsverwaltung (Git)",
"branches": "Branches",
"noBranches": "Keine Branches",
@@ -886,7 +896,7 @@
"date": "timestamp",
"jsonata": "JSONata",
"env": "Umgebungsvariable",
"cred": "Berechtigung"
"cred": "Credentials"
}
},
"editableList": {
@@ -1026,7 +1036,7 @@
"passphrase": "Passphrase",
"ssh-key-desc": "Bevor Sie ein Repository über SSH lokal klonen können, müssen Sie einen SSH-Schlüssel hinzufügen, um auf diesen zugreifen zu können",
"ssh-key-add": "SSH-Schlüssel hinzufügen",
"credential-key": "Schlüssel für Berechtigungen",
"credential-key": "Schlüssel für Credentials",
"cant-get-ssh-key": "Fehler! Der ausgewählte SSH-Schlüsselpfad kann nicht abgerufen werden",
"already-exists2": "bereits vorhanden",
"git-error": "Git-Fehler",
@@ -1038,27 +1048,27 @@
"create": "Erstellen Sie Ihre Projektdateien",
"desc0": "Ein Projekt enthält Ihre Flow-Dateien, eine README-Datei und die 'package.json'-Datei.",
"desc1": "Es kann alle anderen Dateien enthalten, die im Git-Repository verwaltet werden sollen.",
"desc2": "Ihre vorhandenen Flow- und Berechtigungs-Dateien werden in das Projekt kopiert.",
"desc2": "Ihre vorhandenen Flow- und Credential-Dateien werden in das Projekt kopiert.",
"flow-file": "Flow-Datei",
"credentials-file": "Datei mit Berechtigungen"
"credentials-file": "Datei mit Credentials"
},
"encryption-config": {
"setup": "Einrichtung der Verschlüsselung Ihrer Datei mit den Berechtigungen",
"desc0": "Die Datei mit den Flow-Berechtigungen kann verschlüsselt werden, um ihren Inhalt zu schützen.",
"desc1": "Wenn Sie diese Berechtigungen in einem öffentlichen Repository speichern möchten, müssen Sie sie mit einen geheimen Schlüsselausdruck verschlüsseln.",
"desc2": "Die Datei mit den Flow-Berechtigungen ist derzeit nicht verschlüsselt.",
"setup": "Einrichtung der Verschlüsselung Ihrer Datei mit den Credentials",
"desc0": "Die Datei mit den Flow-Credentials kann verschlüsselt werden, um ihren Inhalt zu schützen.",
"desc1": "Wenn Sie diese Credentials in einem öffentlichen Repository speichern möchten, müssen Sie sie mit einen geheimen Schlüsselausdruck verschlüsseln.",
"desc2": "Die Datei mit den Flow-Credentials ist derzeit nicht verschlüsselt.",
"desc3": "D.h. ihr Inhalt (z.B. Passwörter und Zugriffs-Tokens) kann von jedem mit Zugriff auf die Datei gelesen werden.",
"desc4": "Wenn Sie diese Berechtigungen in einen öffentlichen Repository speichern möchten, müssen Sie diese verschlüsseln, indem Sie einen geheimen Schlüsselausdruck eingeben.",
"desc5": "Ihre Datei mit den Flow-Berechtigungen wird derzeit mit dem Eintrag 'credentialSecret' Ihrer Einstellungsdatei als Schlüssel verschlüsselt.",
"desc6": "Die Datei mit den Flow-Berechtigungen wird derzeit mit einem vom System generierten Schlüssel verschlüsselt. Sie sollten einen neuen geheimen Schlüssel für dieses Projekt vorgeben.",
"desc4": "Wenn Sie diese Credentials in einen öffentlichen Repository speichern möchten, müssen Sie diese verschlüsseln, indem Sie einen geheimen Schlüsselausdruck eingeben.",
"desc5": "Ihre Datei mit den Flow-Credentials wird derzeit mit dem Eintrag 'credentialSecret' Ihrer Einstellungsdatei als Schlüssel verschlüsselt.",
"desc6": "Die Datei mit den Flow-Credentials wird derzeit mit einem vom System generierten Schlüssel verschlüsselt. Sie sollten einen neuen geheimen Schlüssel für dieses Projekt vorgeben.",
"desc7": "Der Schlüssel wird separat von den Projektdateien gespeichert. Sie müssen den Schlüssel angeben, damit dieses Projekt auch in einem anderen Node-RED-System verwendet werden kann.",
"credentials": "Berechtigung",
"credentials": "Credentials",
"enable": "Verschlüsselung aktivieren",
"disable": "Verschlüsselung deaktivieren",
"disabled": "deaktiviert",
"copy": "Vorhandenen Schlüssel ersetzen",
"use-custom": "Eigenen Schlüssel verwenden",
"desc8": "Die Datei mit den Berechtigungen wird nicht verschlüsselt, und ihr Inhalt kann leicht gelesen werden",
"desc8": "Die Datei mit den Credentials wird nicht verschlüsselt und ihr Inhalt kann leicht gelesen werden",
"create-project-files": "Projektdateien erstellen",
"create-project": "Projekt erstellen",
"already-exists": "bereits vorhanden",
@@ -1083,12 +1093,12 @@
"desc": "Beschreibung",
"opt": "Optional",
"flow-file": "Flow-Datei",
"credentials": "Berechtigungen",
"credentials": "Credentials",
"enable-encryption": "Verschlüsselung aktivieren",
"disable-encryption": "Verschlüsselung deaktivieren",
"encryption-key": "Schlüssel",
"desc0": "Eine Floskel, mit der Sie Ihre Berechtigungen schützen",
"desc1": "Die Datei mit den Berechtigungen wird nicht verschlüsselt, und ihr Inhalt kann leicht gelesen werden",
"desc0": "Eine Ausdruck, mit der Sie Ihre Credentials schützen",
"desc1": "Die Datei mit den Credentials wird nicht verschlüsselt und ihr Inhalt kann leicht gelesen werden",
"git-url": "Git-Repository-URL",
"protocols": "https://, ssh:// oder file://",
"auth-failed": "Authentifizierung fehlgeschlagen",
@@ -1098,7 +1108,7 @@
"passphrase": "Passphrase",
"desc2": "Bevor Sie ein Repository über SSH klonen können, müssen Sie einen SSH-Schlüssel hinzufügen, um auf diesen zu zugreifen",
"add-ssh-key": "Einen SSH-Schlüssel hinzufügen",
"credentials-encryption-key": "Schlüssel für Berechtigungen",
"credentials-encryption-key": "Schlüssel für Credentials",
"already-exists-2": "bereits vorhanden",
"git-error": "Git-Fehler",
"con-failed": "Verbindung fehlgeschlagen",
@@ -1156,7 +1166,8 @@
"tourGuide": {
"takeATour": "Tour starten",
"start": "Start",
"next": "Nächste"
"next": "Nächste",
"welcomeTours": "Welcome Tours"
},
"diagnostics": {
"title": "System-Informationen"

View File

@@ -936,6 +936,9 @@
"invalid-expr": "Invalid JSONata expression:\n __message__",
"invalid-msg": "Invalid example JSON message:\n __message__",
"context-unsupported": "Cannot test context functions\n $flowContext or $globalContext",
"env-unsupported": "Cannot test $env function",
"moment-unsupported": "Cannot test $moment function",
"clone-unsupported": "Cannot test $clone function",
"eval": "Error evaluating expression:\n __message__"
}
},

View File

@@ -935,8 +935,11 @@
"errors": {
"invalid-expr": "不正なJSONata式:\n __message__",
"invalid-msg": "不正なJSONメッセージ例:\n __message__",
"context-unsupported": "$flowContext や $globalContextの\nコンテキスト機能をテストできません",
"eval": "表現評価エラー:\n __message__"
"context-unsupported": "$flowContext や $globalContextの\nコンテキスト関数をテストできません",
"env-unsupported": "$env関数はテストできません",
"moment-unsupported": "$moment関数はテストできません",
"clone-unsupported": "$clone関数はテストできません",
"eval": "式評価エラー:\n __message__"
}
},
"monaco": {
@@ -1168,8 +1171,7 @@
"takeATour": "ツアーを開始",
"start": "開始",
"next": "次へ",
"welcomeTours": "ウェルカムツアー",
"tours": "ツアー"
"welcomeTours": "ウェルカムツアー"
},
"diagnostics": {
"title": "システム情報"

View File

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

View File

@@ -868,14 +868,7 @@ RED.nodes = (function() {
var node;
if (allNodes.hasTab(id)) {
removedNodes = allNodes.getNodes(id).filter(n => {
if (n.type === 'junction') {
removedJunctions.push(n)
return false
} else {
return true
}
})
removedNodes = allNodes.getNodes(id).slice()
}
for (i in configNodes) {
if (configNodes.hasOwnProperty(i)) {
@@ -885,6 +878,7 @@ RED.nodes = (function() {
}
}
}
removedJunctions = RED.nodes.junctions(id)
for (i=0;i<removedNodes.length;i++) {
var result = removeNode(removedNodes[i].id);
@@ -1331,7 +1325,6 @@ RED.nodes = (function() {
} else {
nodeSet = [sf];
}
console.log(nodeSet);
return createExportableNodeSet(nodeSet);
}
/**
@@ -1367,6 +1360,10 @@ RED.nodes = (function() {
exportedConfigNodes[n.id] = true;
}
});
subflowSet = subflowSet.concat(RED.nodes.junctions(subflowId))
subflowSet = subflowSet.concat(RED.nodes.groups(subflowId))
var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes);
nns = exportableSubflow.concat(nns);
}

View File

@@ -766,7 +766,7 @@ var RED = (function() {
$('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header);
$('<div id="red-ui-main-container" class="red-ui-sidebar-closed hide">'+
'<div id="red-ui-workspace"></div>'+
'<div id="red-ui-editor-stack"></div>'+
'<div id="red-ui-editor-stack" tabindex="-1"></div>'+
'<div id="red-ui-palette"></div>'+
'<div id="red-ui-sidebar"></div>'+
'<div id="red-ui-sidebar-separator"></div>'+

View File

@@ -160,7 +160,7 @@
this.element.css("maxHeight",null);
}
if (this.options.height !== 'auto') {
this.uiContainer.css("overflow-y","scroll");
this.uiContainer.css("overflow-y","auto");
if (!isNaN(this.options.height)) {
this.uiHeight = this.options.height;
}

View File

@@ -90,10 +90,10 @@
optEl.append(generateSpans(srcMatch));
optEl.appendTo(element);
}
matches.push({
value: optVal,
label: element,
i: (valMatch.found ? valMatch.index : srcMatch.index)
matches.push({
value: optVal,
label: element,
i: (valMatch.found ? valMatch.index : srcMatch.index)
});
}
})
@@ -501,7 +501,7 @@
this.options.types = this.options.types||Object.keys(allOptions);
}
this.selectTrigger = $('<button class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
this.selectTrigger = $('<button type="button" class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
$('<i class="red-ui-typedInput-icon fa fa-caret-down"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
this.selectLabel = $('<span class="red-ui-typedInput-type-label"></span>').appendTo(this.selectTrigger);
@@ -570,7 +570,7 @@
})
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectTrigger = $('<button type="button" tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
// RED.popover.tooltip(this.optionSelectLabel,function() {
// return that.optionValue;
@@ -591,7 +591,7 @@
that.uiSelect.addClass('red-ui-typedInput-focus');
});
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
this.optionExpandButton = $('<button type="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.typeField.val() || this.options.default||this.typeList[0].value);

View File

@@ -44,14 +44,10 @@ RED.contextMenu = (function () {
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
const offset = $("#red-ui-workspace-chart").offset()
let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()
let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()
if (RED.view.snapGrid) {
const gridSize = RED.view.gridSize()
addX = gridSize * Math.floor(addX / gridSize)
addY = gridSize * Math.floor(addY / gridSize)
}
// addX/addY must be the position in the workspace accounting for both scroll and scale
// The +5 is because we display the contextMenu -5,-5 to actual click position
let addX = (options.x + 5 - offset.left + $("#red-ui-workspace-chart").scrollLeft()) / RED.view.scale()
let addY = (options.y + 5 - offset.top + $("#red-ui-workspace-chart").scrollTop()) / RED.view.scale()
const menuItems = [
{ onselect: 'core:show-action-list', onpostselect: function () { } },
@@ -67,6 +63,10 @@ RED.contextMenu = (function () {
splice: isSingleLink ? selection.links[0] : undefined,
// spliceMultiple: isMultipleLinks
})
},
onpostselect: function() {
// ensure quick add dialog search input has focus
$('#red-ui-type-search-input').trigger('focus')
}
},
(hasLinks) ? { // has least 1 wire selected
@@ -144,7 +144,7 @@ RED.contextMenu = (function () {
($(window).width() -MENU_WIDTH)) {
direction = "left";
}
menu = RED.menu.init({
direction: direction,
onpreselect: function() {

View File

@@ -1105,6 +1105,10 @@ RED.editor = (function() {
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
RED.sidebar.help.show(editing_node.type, false);
//ensure focused element is NOT body (for keyboard scope to operate correctly)
if (document.activeElement.tagName === 'BODY') {
$('#red-ui-editor-stack').trigger('focus')
}
}
}
}

View File

@@ -100,7 +100,7 @@ RED.editor.codeEditor.monaco = (function() {
"node-red-util": {package: "node-red", module: "util", path: "node-red/util.d.ts" },
"node-red-func": {package: "node-red", module: "func", path: "node-red/func.d.ts" },
}
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"] ];
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"] , knownModules["util"] ];
const modulesCache = {};
@@ -764,7 +764,7 @@ RED.editor.codeEditor.monaco = (function() {
if(!options.stateId && options.stateId !== false) {
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title).split("/").pop());
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title || "").split("/").pop());
}
var el = options.element || $("#"+options.id)[0];
var toolbarRow = $("<div>").appendTo(el);

View File

@@ -76,6 +76,9 @@ RED.editor.colorPicker = RED.colorPicker = (function() {
var focusTarget = colorInput;
colorInput.on("change", function (e) {
var color = colorInput.val();
if (options.defaultValue && !color.match(/^([a-z]+|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3})$/)) {
color = options.defaultValue;
}
colorHiddenInput.val(color).trigger('change');
refreshDisplay(color);
});

View File

@@ -255,6 +255,9 @@
var currentExpression = expressionEditor.getValue();
var expr;
var usesContext = false;
var usesEnv = false;
var usesMoment = false;
var usesClone = false;
var legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
$(".red-ui-editor-type-expression-legacy").toggle(legacyMode);
try {
@@ -267,6 +270,18 @@
usesContext = true;
return null;
});
expr.assign("env", function(name) {
usesEnv = true;
return null;
});
expr.assign("moment", function(name) {
usesMoment = true;
return null;
});
expr.assign("clone", function(name) {
usesClone = true;
return null;
});
} catch(err) {
testResultEditor.setValue(RED._("expressionEditor.errors.invalid-expr",{message:err.message}),-1);
return;
@@ -284,6 +299,18 @@
testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
return;
}
if (usesEnv) {
testResultEditor.setValue(RED._("expressionEditor.errors.env-unsupported"),-1);
return;
}
if (usesMoment) {
testResultEditor.setValue(RED._("expressionEditor.errors.moment-unsupported"),-1);
return;
}
if (usesClone) {
testResultEditor.setValue(RED._("expressionEditor.errors.clone-unsupported"),-1);
return;
}
var formattedResult;
if (result !== undefined) {

View File

@@ -235,6 +235,7 @@
RED.editor.colorPicker.create({
id: "red-ui-editor-node-color",
value: color,
defaultValue: "#DDAA99",
palette: recommendedColors,
sortPalette: function (a, b) {return a.l - b.l;}
}).appendTo(colorRow);

View File

@@ -101,6 +101,7 @@ RED.group = (function() {
RED.editor.colorPicker.create({
id:"node-input-style-stroke",
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
defaultValue: "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
@@ -112,6 +113,7 @@ RED.group = (function() {
RED.editor.colorPicker.create({
id:"node-input-style-fill",
value: style.fill || defaultGroupStyle.fill ||"none",
defaultValue: "none",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
@@ -129,6 +131,7 @@ RED.group = (function() {
RED.editor.colorPicker.create({
id:"node-input-style-color",
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
defaultValue: "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,

View File

@@ -267,7 +267,7 @@ RED.keyboard = (function() {
return resolveKeyEvent(evt);
}
if (Object.keys(handler).length > 0) {
// check if there's a potential combined handler initiated by this keyCode
// check if there's a potential combined handler initiated by this keyCode
for (let h in handler) {
if (matchHandlerToEvent(evt,handler[h]) > -1) {
partialState = handler;
@@ -298,21 +298,21 @@ RED.keyboard = (function() {
return resolveKeyEvent(evt);
}
}
document.addEventListener("keydown", function(event) {
d3.select(window).on("keydown",function() {
if (!handlersActive) {
return;
}
if (metaKeyCodes[event.keyCode]) {
if (metaKeyCodes[d3.event.keyCode]) {
return;
}
var handler = resolveKeyEvent(event);
var handler = resolveKeyEvent(d3.event);
if (handler && handler.ondown) {
if (typeof handler.ondown === "string") {
RED.actions.invoke(handler.ondown);
} else {
handler.ondown();
}
event.preventDefault();
d3.event.preventDefault();
}
});

View File

@@ -175,9 +175,19 @@ RED.palette = (function() {
$('<button type="button" onclick="RED.workspaces.show(\''+type.substring(8).replace(/'/g,"\\'")+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-pencil"></i></button>').appendTo(popOverContent)
}
var safeType = type.replace(/'/g,"\\'");
const safeType = type.replace(/'/g,"\\'");
const wrapStr = function (str) {
if(str.indexOf(' ') >= 0) {
return '"' + str + '"'
}
return str
}
$('<button type="button" onclick="RED.search.show(\'type:'+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>').appendTo(popOverContent)
$('<button type="button"; return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>')
.appendTo(popOverContent)
.on('click', function() {
RED.search.show('type:' + wrapStr(safeType))
})
$('<button type="button" onclick="RED.sidebar.help.show(\''+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
@@ -299,7 +309,7 @@ RED.palette = (function() {
RED.view.focus();
},
stop: function() {
document.querySelectorAll(".red-ui-flow-link-splice").forEach(n => { n.classList.remove("red-ui-flow-link-splice") })
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
@@ -358,26 +368,26 @@ RED.palette = (function() {
var mx = mouseX / RED.view.scale();
var my = mouseY / RED.view.scale();
for (var i=0;i<nodes.length;i++) {
var node = nodes[i];
if (node.classList.contains('red-ui-flow-link-background') && !node.classList.contains('red-ui-flow-link-link')) {
var length = node.getTotalLength();
var node = d3.select(nodes[i]);
if (node.classed('red-ui-flow-link-background') && !node.classed('red-ui-flow-link-link')) {
var length = nodes[i].getTotalLength();
for (var j=0;j<length;j+=10) {
var p = node.getPointAtLength(j);
var p = nodes[i].getPointAtLength(j);
var d2 = ((p.x-mx)*(p.x-mx))+((p.y-my)*(p.y-my));
if (d2 < 200 && d2 < bestDistance) {
bestDistance = d2;
bestLink = node;
bestLink = nodes[i];
}
}
}
}
if (activeSpliceLink && activeSpliceLink !== bestLink) {
activeSpliceLink.parentNode.classList.remove('red-ui-flow-link-splice');
d3.select(activeSpliceLink.parentNode).classed('red-ui-flow-link-splice',false);
}
if (bestLink) {
bestLink.parentNode.classList.add('red-ui-flow-link-splice');
d3.select(bestLink.parentNode).classed('red-ui-flow-link-splice',true)
} else {
document.querySelectorAll(".red-ui-flow-link-splice").forEach(n => { n.classList.remove("red-ui-flow-link-splice") })
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
}
if (activeSpliceLink !== bestLink) {
if (bestLink) {

View File

@@ -545,7 +545,7 @@ RED.projects = (function() {
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.clone-project.ssh-key-desc")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
e.preventDefault();
dialog.dialog( "close" );
RED.userSettings.show('gitconfig');
@@ -1171,11 +1171,11 @@ RED.projects = (function() {
row = $('<div class="form-row button-group"></div>').appendTo(container);
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
var openProject = $('<button type="button" data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button type="button" data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button type="button" data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button type="button" data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button type="button" data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
row.find(".red-ui-projects-dialog-screen-create-type").on("click", function(evt) {
evt.preventDefault();
container.find(".red-ui-projects-dialog-screen-create-type").removeClass('selected');
@@ -1271,7 +1271,7 @@ RED.projects = (function() {
var credentialsLeftBox = $('<div class="red-ui-projects-dialog-credentials-box-left">').appendTo(credentialsBox);
var credentialsEnabledBox = $('<div class="form-row red-ui-projects-dialog-credentials-box-enabled"></div>').appendTo(credentialsLeftBox);
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="enabled"> <i class="fa fa-lock"></i> <span>'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="enabled" checked> <i class="fa fa-lock"></i> <span>'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
var credentialsDisabledBox = $('<div class="form-row red-ui-projects-dialog-credentials-box-disabled disabled"></div>').appendTo(credentialsLeftBox);
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="disabled"> <i class="fa fa-unlock"></i> <span>'+RED._("projects.encryption-config.disable")+'</span></label>').appendTo(credentialsDisabledBox);
@@ -1397,7 +1397,7 @@ RED.projects = (function() {
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.create.desc2")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
e.preventDefault();
$('#red-ui-projects-dialog-cancel').trigger("click");
RED.userSettings.show('gitconfig');
@@ -1631,14 +1631,14 @@ RED.projects = (function() {
function deleteProject(row,name,done) {
var cover = $('<div class="red-ui-projects-dialog-project-list-entry-delete-confirm"></div>').on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
cover.remove();
done(true);
});
$('<button class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
@@ -1822,7 +1822,7 @@ RED.projects = (function() {
header.addClass("selectable");
var tools = $('<div class="red-ui-projects-dialog-project-list-entry-tools"></div>').appendTo(header);
$('<button class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
.appendTo(tools)
.on("click", function(e) {
e.stopPropagation();

View File

@@ -106,38 +106,51 @@ RED.search = (function() {
return val;
}
function search(val) {
var results = [];
var typeFilter;
var m = /(?:^| )type:([^ ]+)/.exec(val);
if (m) {
val = val.replace(/(?:^| )type:[^ ]+/,"");
typeFilter = m[1];
function extractType(val, flags) {
// extracts: type:XYZ & type:"X Y Z"
const regEx = /(?:type):\s*(?:"([^"]+)"|([^" ]+))/;
let m
while ((m = regEx.exec(val)) !== null) {
// avoid infinite loops with zero-width matches
if (m.index === regEx.lastIndex) {
regEx.lastIndex++;
}
val = val.replace(m[0]," ").trim()
const flag = m[2] || m[1] // quoted entries in capture group 1, unquoted in capture group 2
flags.type = flags.type || [];
flags.type.push(flag);
}
var flags = {};
return val;
}
function search(val) {
const results = [];
const flags = {};
val = extractFlag(val,"invalid",flags);
val = extractFlag(val,"unused",flags);
val = extractFlag(val,"config",flags);
val = extractFlag(val,"subflow",flags);
val = extractFlag(val,"hidden",flags);
val = extractFlag(val,"modified",flags);
val = extractValue(val,"flow",flags);// flow:active or flow:<flow-id>
val = extractValue(val,"flow",flags);// flow:current or flow:<flow-id>
val = extractValue(val,"uses",flags);// uses:<node-id>
val = extractType(val,flags);// type:<node-type>
val = val.trim();
var hasFlags = Object.keys(flags).length > 0;
const hasFlags = Object.keys(flags).length > 0;
const hasTypeFilter = flags.type && flags.type.length > 0
if (flags.flow && flags.flow.indexOf("current") >= 0) {
let idx = flags.flow.indexOf("current");
flags.flow[idx] = RED.workspaces.active();//convert active to flow ID
flags.flow[idx] = RED.workspaces.active();//convert 'current' to active flow ID
}
if (flags.flow && flags.flow.length) {
flags.flow = [ ...new Set(flags.flow) ]; //deduplicate
}
if (val.length > 0 || typeFilter || hasFlags) {
if (val.length > 0 || hasFlags) {
val = val.toLowerCase();
var i;
var j;
var list = [];
var nodes = {};
let i;
let j;
let list = [];
const nodes = {};
let keys = [];
if (flags.uses) {
keys = flags.uses;
@@ -145,10 +158,10 @@ RED.search = (function() {
keys = Object.keys(index);
}
for (i=0;i<keys.length;i++) {
var key = keys[i];
var kpos = keys[i].indexOf(val);
if (kpos > -1) {
var ids = Object.keys(index[key]||{});
const key = keys[i];
const kpos = val ? keys[i].indexOf(val) : -1;
if (kpos > -1 || (val === "" && hasFlags)) {
const ids = Object.keys(index[key]||{});
for (j=0;j<ids.length;j++) {
var node = index[key][ids[j]];
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
@@ -156,7 +169,7 @@ RED.search = (function() {
continue;
}
if (flags.hasOwnProperty("invalid")) {
var nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
const nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
if (flags.invalid === nodeIsValid) {
continue;
}
@@ -186,8 +199,8 @@ RED.search = (function() {
}
}
if (flags.hasOwnProperty("unused")) {
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0)
const isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0 && node.node._def.hasUsers !== false)
if (flags.unused !== isUnused) {
continue;
}
@@ -197,12 +210,16 @@ RED.search = (function() {
continue;
}
}
if (!typeFilter || node.node.type === typeFilter) {
nodes[node.node.id] = nodes[node.node.id] = {
let typeIndex = -1
if(hasTypeFilter) {
typeIndex = flags.type.indexOf(node.node.type)
}
if (!hasTypeFilter || typeIndex > -1) {
nodes[node.node.id] = nodes[node.node.id] || {
node: node.node,
label: node.label
};
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
nodes[node.node.id].index = Math.min(nodes[node.node.id].index || Infinity, typeIndex > -1 ? typeIndex : kpos);
}
}
}
@@ -538,7 +555,7 @@ RED.search = (function() {
$(previousActiveElement).trigger("focus");
}
previousActiveElement = null;
}
}
if(!keepSearchToolbar) {
clearActiveSearch();
}
@@ -630,7 +647,7 @@ RED.search = (function() {
$("#red-ui-sidebar-shade").on('mousedown',hide);
$("#red-ui-view-searchtools-close").on("click", function close() {
clearActiveSearch();
clearActiveSearch();
updateSearchToolbar();
});
$("#red-ui-view-searchtools-close").trigger("click");

View File

@@ -506,6 +506,13 @@ RED.subflow = (function() {
RED.nodes.groups(id).forEach(function(n) {
removedGroups.push(n);
})
var removedJunctions = RED.nodes.junctions(id)
for (var i=0;i<removedJunctions.length;i++) {
var removedEntities = RED.nodes.removeJunction(removedJunctions[i])
removedLinks = removedLinks.concat(removedEntities.links)
}
var removedConfigNodes = [];
for (var i=0;i<removedNodes.length;i++) {
var removedEntities = RED.nodes.remove(removedNodes[i].id);
@@ -536,6 +543,7 @@ RED.subflow = (function() {
nodes:removedNodes,
links:removedLinks,
groups: removedGroups,
junctions: removedJunctions,
subflows: [activeSubflow]
}
}
@@ -932,7 +940,6 @@ RED.subflow = (function() {
function buildEnvUIRow(row, tenv, ui, node) {
console.log(tenv, ui)
ui.label = ui.label||{};
if ((tenv.type === "cred" || (tenv.parent && tenv.parent.type === "cred")) && !ui.type) {
ui.type = "cred";

View File

@@ -50,7 +50,7 @@ RED.sidebar.help = (function() {
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
var helpPanel = $("<div>").css({
"overflow-y": "scroll"
"overflow-y": "auto"
}).appendTo(stackContainer);
panels = RED.panels.create({

View File

@@ -98,7 +98,7 @@ RED.sidebar.info = (function() {
propertiesPanelContent = $("<div>").css({
"flex":"1 1 auto",
"overflow-y":"scroll",
"overflow-y":"auto",
}).appendTo(propertiesPanel);

View File

@@ -27,24 +27,26 @@ RED.touch.radialMenu = (function() {
function createRadial(obj,pos,options) {
isActive = true;
try {
touchMenu = $('<div>', {class: 'red-ui-editor-radial-menu'}).appendTo('body')
.on('touchstart',function(evt) {
touchMenu = d3.select("body").append("div").classed("red-ui-editor-radial-menu",true)
.on('touchstart',function() {
hide();
evt.preventDefault();
d3.event.preventDefault();
});
var menu = $('<div>').appendTo(touchMenu).css({
var menu = touchMenu.append("div")
.style({
top: (pos[1]-80)+"px",
left:(pos[0]-80)+"px",
});
var menuOpts = [];
var createMenuOpt = function(x,y,opt) {
opt.el = $('<div>', {class: 'red-ui-editor-radial-menu-opt'}).appendTo(menu)
.css({
opt.el = menu.append("div").classed("red-ui-editor-radial-menu-opt",true)
.style({
top: (y+80-25)+"px",
left:(x+80-25)+"px"
})
.toggleClass("red-ui-editor-radial-menu-opt-disabled",!!opt.disabled)
.classed("red-ui-editor-radial-menu-opt-disabled",!!opt.disabled)
opt.el.html(opt.name);
@@ -52,16 +54,16 @@ RED.touch.radialMenu = (function() {
opt.y = y;
menuOpts.push(opt);
opt.el.on('touchstart',function(evt) {
opt.el.toggleClass("red-ui-editor-radial-menu-opt-active",true)
evt.preventDefault();
evt.stopPropagation();
opt.el.on('touchstart',function() {
opt.el.classed("red-ui-editor-radial-menu-opt-active",true)
d3.event.preventDefault();
d3.event.stopPropagation();
});
opt.el.on('touchend',function(evt) {
opt.el.on('touchend',function() {
hide();
opt.onselect();
evt.preventDefault();
evt.stopPropagation();
d3.event.preventDefault();
d3.event.stopPropagation();
});
}
@@ -86,8 +88,8 @@ RED.touch.radialMenu = (function() {
}
obj.on('touchend.radial',function() {
obj.off('touchend.radial');
obj.off('touchmenu.radial');
obj.on('touchend.radial',null);
obj.on('touchmenu.radial',null);
if (activeOption) {
try {
@@ -101,9 +103,9 @@ RED.touch.radialMenu = (function() {
}
});
obj.on('touchmove.radial',function(evt) {
obj.on('touchmove.radial',function() {
try {
var touch0 = evt.touches.item(0);
var touch0 = d3.event.touches.item(0);
var p = [touch0.pageX - pos[0],touch0.pageY-pos[1]];
for (var i=0;i<menuOpts.length;i++) {
var opt = menuOpts[i];
@@ -117,7 +119,7 @@ RED.touch.radialMenu = (function() {
if (opt === activeOption) {
activeOption = null;
}
opt.el.toggleClass("selected",false);
opt.el.classed("selected",false);
}
}
}

View File

@@ -269,8 +269,8 @@ RED.typeSearch = (function() {
moveCallback = opts.move;
RED.events.emit("type-search:open");
//shade.show();
if ($("#red-ui-main-container").height() - opts.y - 150 < 0) {
opts.y = opts.y - 235;
if ($("#red-ui-main-container").height() - opts.y - 195 < 0) {
opts.y = opts.y - 275;
}
dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
searchResultsDiv.slideDown(300);

View File

@@ -1,61 +0,0 @@
/**
* Modelled after `d3.selection` this provides a way to keep a mapping of
* DOM Nodes with a data collection.
*
* The goal here is not to reproduce d3 functionality as-is, but to provide an
* api that is specific to what we need to do
*
* const domSelection = RED.utils.domSelection(container, selector, createNode, eachNode)
*
* - container - a DOM Node that is the container of the DOM Nodes to track
* - selector - CSS selector to get the DOM nodes to track
* - createNode - function called when a DOM node must be created for a piece of data.
* `this` is the data item. Should return the DOM Node. It will
* get added to the container.
* - eachNode - function called for each DOM node/data item in the selection
*
* DomSelection.refresh(data) - called whenever the selection should be refreshed.
* Data is expected to be an array of objects that contain an 'id' property
*
*/
RED.utils.domSelection = (function() {
class DomSelection {
constructor(container, selector, createNode, eachNode) {
this.container = container
this.selector = selector
this.createNode = createNode
this.eachNode = eachNode
this.data = []
}
refresh(data) {
const domNodes = this.container.querySelectorAll(this.selector)
const domItems = new Map()
const dataLength = data.length
const domLength = domNodes.length
for (let i = 0; i < domLength; i++) {
const domNode = domNodes[i]
if (domNode.__data__) {
domItems.set(domNode.__data__.id, domNode)
}
}
for (let i = 0; i < dataLength; i++) {
const datum = data[i]
let domNode = domItems.get(datum.id)
if (!domNode) {
domNode = this.createNode.call(datum)
this.container.appendChild(domNode)
domNode.__data__ = datum
} else {
domItems.delete(datum.id)
}
this.eachNode.call(datum, domNode)
}
for (const remainingDomNodes of domItems) {
remainingDomNodes[1].remove()
}
}
}
return (container, selector, createNode, eachNode) => new DomSelection(container, selector, createNode, eachNode)
})()

View File

@@ -1397,17 +1397,6 @@ RED.utils = (function() {
return r;
}
function createSVGElement(tag, attrs = {}, parent) {
const element = document.createElementNS('http://www.w3.org/2000/svg', tag)
for (const k in attrs) {
element.setAttribute(k, attrs[k])
}
if (parent) {
parent.appendChild(element)
}
return element
}
return {
createObjectElement: createObjectElement,
getMessageProperty: getMessageProperty,
@@ -1431,7 +1420,6 @@ RED.utils = (function() {
getDarkerColor: getDarkerColor,
parseModuleList: parseModuleList,
checkModuleAllowed: checkModuleAllowed,
getBrowserInfo: getBrowserInfo,
createSVGElement: createSVGElement
getBrowserInfo: getBrowserInfo
}
})();

View File

@@ -91,7 +91,8 @@ RED.view.annotations = (function() {
function addAnnotation(id,evt) {
var opts = annotations[id];
evt.el.__annotations__ = evt.el.__annotations__ || [];
var annotationGroup = RED.utils.createSVGElement("g", { class: opts.class || '' })
var annotationGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
annotationGroup.setAttribute("class",opts.class || "");
evt.el.__annotations__.push({
id:id,
element: annotationGroup

View File

@@ -15,128 +15,133 @@
**/
RED.view.navigator = (function() {
var nav_scale = 25;
var nav_width = 5000/nav_scale;
var nav_height = 5000/nav_scale;
RED.view.navigator = (function() {
var navContainer;
var navBox;
var navBorder;
var scrollPos;
var scaleFactor;
var chartSize;
var dimensions;
var isDragging;
var isShowing = false;
var nav_scale = 25;
var nav_width = 5000/nav_scale;
var nav_height = 5000/nav_scale;
var domSelection
var navContainer;
var navBox;
var navBorder;
var navVis;
var scrollPos;
var scaleFactor;
var chartSize;
var dimensions;
var isDragging;
var isShowing = false;
function refreshNodes() {
if (!isShowing) {
return;
}
domSelection.refresh(RED.view.getActiveNodes())
}
function refreshNodes() {
if (!isShowing) {
return;
}
var navNode = navVis.selectAll(".red-ui-navigator-node").data(RED.view.getActiveNodes(),function(d){return d.id});
navNode.exit().remove();
navNode.enter().insert("rect")
.attr('class','red-ui-navigator-node')
.attr("pointer-events", "none");
navNode.each(function(d) {
d3.select(this).attr("x",function(d) { return (d.x-d.w/2)/nav_scale })
.attr("y",function(d) { return (d.y-d.h/2)/nav_scale })
.attr("width",function(d) { return Math.max(9,d.w/nav_scale) })
.attr("height",function(d) { return Math.max(3,d.h/nav_scale) })
.attr("fill",function(d) { return RED.utils.getNodeColor(d.type,d._def);})
});
}
function onScroll() {
if (!isDragging) {
resizeNavBorder();
}
}
function resizeNavBorder() {
if (navBorder) {
scaleFactor = RED.view.scale();
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()];
navBorder.attr('x',scrollPos[0]/nav_scale)
.attr('y',scrollPos[1]/nav_scale)
.attr('width',chartSize[0]/nav_scale/scaleFactor)
.attr('height',chartSize[1]/nav_scale/scaleFactor)
}
}
function toggle() {
if (!isShowing) {
isShowing = true;
$("#red-ui-view-navigate").addClass("selected");
resizeNavBorder();
refreshNodes();
$("#red-ui-workspace-chart").on("scroll",onScroll);
navContainer.fadeIn(200);
} else {
isShowing = false;
navContainer.fadeOut(100);
$("#red-ui-workspace-chart").off("scroll",onScroll);
$("#red-ui-view-navigate").removeClass("selected");
}
}
function onScroll() {
if (!isDragging) {
resizeNavBorder();
}
}
function resizeNavBorder() {
if (navBorder) {
scaleFactor = RED.view.scale();
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()];
return {
init: function() {
navBorder.attr('x', scrollPos[0]/nav_scale)
navBorder.attr('y', scrollPos[1]/nav_scale)
navBorder.attr('width',chartSize[0]/nav_scale/scaleFactor)
navBorder.attr('height',chartSize[1]/nav_scale/scaleFactor)
}
}
function toggle() {
if (!isShowing) {
isShowing = true;
$("#red-ui-view-navigate").addClass("selected");
resizeNavBorder();
refreshNodes();
$("#red-ui-workspace-chart").on("scroll",onScroll);
navContainer.fadeIn(200);
} else {
isShowing = false;
navContainer.fadeOut(100);
$("#red-ui-workspace-chart").off("scroll",onScroll);
$("#red-ui-view-navigate").removeClass("selected");
}
}
$(window).on("resize", resizeNavBorder);
RED.events.on("sidebar:resize",resizeNavBorder);
RED.actions.add("core:toggle-navigator",toggle);
var hideTimeout;
return {
init: function() {
navContainer = $('<div>').css({
"position":"absolute",
"bottom":$("#red-ui-workspace-footer").height(),
"right":0,
zIndex: 1
}).appendTo("#red-ui-workspace").hide();
$(window).on("resize", resizeNavBorder);
RED.events.on("sidebar:resize",resizeNavBorder);
RED.actions.add("core:toggle-navigator",toggle);
navBox = d3.select(navContainer[0])
.append("svg:svg")
.attr("width", nav_width)
.attr("height", nav_height)
.attr("pointer-events", "all")
.attr("id","red-ui-navigator-canvas")
navContainer = $('<div>').css({
"position":"absolute",
"bottom":$("#red-ui-workspace-footer").height(),
"right":0,
zIndex: 1
}).appendTo("#red-ui-workspace").hide();
navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({
fill:"none",
stroke:"none",
pointerEvents:"all"
}).on("mousedown", function() {
// Update these in case they have changed
scaleFactor = RED.view.scale();
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
navBorder.attr('x',newX).attr('y',newY);
isDragging = true;
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
}).on("mousemove", function() {
if (!isDragging) { return }
if (d3.event.buttons === 0) {
isDragging = false;
return;
}
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
navBorder.attr('x',newX).attr('y',newY);
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
}).on("mouseup", function() {
isDragging = false;
})
navBox = $(RED.utils.createSVGElement('svg', {id: "red-ui-navigator-canvas", width: nav_width, height: nav_height, 'pointer-events': 'all'})).appendTo(navContainer)
navBorder = navBox.append("rect").attr("class","red-ui-navigator-border")
const navBoxBody = $(RED.utils.createSVGElement("rect", { x: 0, y: 0, width: nav_width, height: nav_height, fill: 'none', stroke: 'none', 'pointer-events': 'all'}))
.css({'cursor': 'pointer'})
navBoxBody.on('mousedown',function(event) {
// Update these in case they have changed
scaleFactor = RED.view.scale();
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
var newX = Math.max(0,Math.min(event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
var newY = Math.max(0,Math.min(event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
navBorder.attr('x',newX)
navBorder.attr('y',newY);
isDragging = true;
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
}).on('mousemove', function(event) {
if (!isDragging) { return }
if (event.buttons === 0) {
isDragging = false;
return;
}
var newX = Math.max(0,Math.min(event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
var newY = Math.max(0,Math.min(event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
navBorder.attr('x',newX)
navBorder.attr('y',newY);
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
}).on('mouseup', function() {
isDragging = false;
}).appendTo(navBox)
navVis = navBox.append("svg:g")
navBorder = $(RED.utils.createSVGElement("rect", { "class": "red-ui-navigator-border" })).appendTo(navBox)
const navVis = $(RED.utils.createSVGElement('g')).appendTo(navBox)
domSelection = RED.utils.domSelection(navVis[0], '.red-ui-navigator-node', function() {
return RED.utils.createSVGElement('rect', { class: 'red-ui-navigator-node', 'pointer-events': 'none' })
}, function(node) {
node.setAttribute('x', (this.x-this.w/2)/nav_scale)
node.setAttribute('y', (this.y-this.h/2)/nav_scale)
node.setAttribute('width', Math.max(9,this.w/nav_scale))
node.setAttribute('height', Math.max(3,this.h/nav_scale))
node.setAttribute('fill', RED.utils.getNodeColor(this.type,this._def))
})
RED.statusBar.add({
id: "view-navigator",
align: "right",
element: $('<button class="red-ui-footer-button-toggle single" id="red-ui-view-navigate"><i class="fa fa-map-o"></i></button>')
})
RED.statusBar.add({
id: "view-navigator",
align: "right",
element: $('<button class="red-ui-footer-button-toggle single" id="red-ui-view-navigate"><i class="fa fa-map-o"></i></button>')
})
$("#red-ui-view-navigate").on("click", function(evt) {
evt.preventDefault();

View File

@@ -1015,7 +1015,7 @@ RED.view.tools = (function() {
const nodeDef = n._def || RED.nodes.getType(n.type)
if (nodeDef && nodeDef.defaults && nodeDef.defaults.name) {
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
const defaultNodeNameRE = new RegExp('^'+paletteLabel+' (\\d+)$')
const defaultNodeNameRE = new RegExp('^'+paletteLabel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')+' (\\d+)$')
if (!typeIndex.hasOwnProperty(n.type)) {
const existingNodes = RED.nodes.filterNodes({type: n.type})
let maxNameNumber = 0;

View File

@@ -294,13 +294,25 @@ RED.view = (function() {
]
startTouchDistance = Math.sqrt((a*a)+(b*b));
} else {
var obj = d3.select(document.body);
touch0 = d3.event.touches.item(0);
var pos = [touch0.pageX,touch0.pageY];
startTouchCenter = [touch0.pageX,touch0.pageY];
startTouchDistance = 0;
var point = d3.touches(this)[0];
touchStartTime = setTimeout(function() {
touchStartTime = null;
showTouchMenu(document.body,pos);
showTouchMenu(obj,pos);
//lasso = eventLayer.append("rect")
// .attr("ox",point[0])
// .attr("oy",point[1])
// .attr("rx",2)
// .attr("ry",2)
// .attr("x",point[0])
// .attr("y",point[1])
// .attr("width",0)
// .attr("height",0)
// .attr("class","nr-ui-view-lasso");
},touchLongPressTimeout);
}
d3.event.preventDefault();
@@ -700,11 +712,11 @@ RED.view = (function() {
type: "badge",
class: "red-ui-flow-node-changed",
element: function() {
return RED.utils.createSVGElement("circle", {
cx: 5,
cy: 5,
r: 5
})
var changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle");
changeBadge.setAttribute("cx",5);
changeBadge.setAttribute("cy",5);
changeBadge.setAttribute("r",5);
return changeBadge;
},
show: function(n) { return n.changed||n.moved }
})
@@ -713,9 +725,9 @@ RED.view = (function() {
type: "badge",
class: "red-ui-flow-node-error",
element: function(d) {
return RED.utils.createSVGElement("path", {
d: "M 0,9 l 10,0 -5,-8 z"
})
var errorBadge = document.createElementNS("http://www.w3.org/2000/svg","path");
errorBadge.setAttribute("d","M 0,9 l 10,0 -5,-8 z");
return errorBadge
},
tooltip: function(d) {
if (d.validationErrors && d.validationErrors.length > 0) {
@@ -1059,12 +1071,15 @@ RED.view = (function() {
RED.view.redraw();
}
// `point` is the place in the workspace the mouse has clicked.
// This takes into account scrolling and scaling of the workspace.
var ox = point[0];
var oy = point[1];
// Need to map that to browser location to position the pop-up
const offset = $("#red-ui-workspace-chart").offset()
var clientX = ox + offset.left - $("#red-ui-workspace-chart").scrollLeft()
var clientY = oy + offset.top - $("#red-ui-workspace-chart").scrollTop()
var clientX = (ox * scaleFactor) + offset.left - $("#red-ui-workspace-chart").scrollLeft()
var clientY = (oy * scaleFactor) + offset.top - $("#red-ui-workspace-chart").scrollTop()
if (RED.settings.get("editor").view['view-snap-grid']) {
// eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
@@ -3691,12 +3706,13 @@ RED.view = (function() {
}
function nodeTouchStart(d) {
if (RED.view.DEBUG) { console.warn("nodeTouchStart", mouse_mode,d); }
var obj = d3.select(this);
var touch0 = d3.event.touches.item(0);
var pos = [touch0.pageX,touch0.pageY];
startTouchCenter = [touch0.pageX,touch0.pageY];
startTouchDistance = 0;
touchStartTime = setTimeout(function() {
showTouchMenu(this,pos);
showTouchMenu(obj,pos);
},touchLongPressTimeout);
nodeMouseDown.call(this,d)
d3.event.preventDefault();
@@ -3855,11 +3871,12 @@ RED.view = (function() {
focusView();
d3.event.stopPropagation();
var obj = d3.select(document.body);
var touch0 = d3.event.touches.item(0);
var pos = [touch0.pageX,touch0.pageY];
touchStartTime = setTimeout(function() {
touchStartTime = null;
showTouchMenu(document.body,pos);
showTouchMenu(obj,pos);
},touchLongPressTimeout);
d3.event.preventDefault();
}
@@ -4233,14 +4250,13 @@ RED.view = (function() {
d.resize = true;
d.dirty = true;
var mainRect = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-subflow-port",
rx: 8,
ry: 8,
width: 40,
height: 40,
})
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
mainRect.__data__ = d;
mainRect.setAttribute("class", "red-ui-flow-subflow-port");
mainRect.setAttribute("rx", 8);
mainRect.setAttribute("ry", 8);
mainRect.setAttribute("width", 40);
mainRect.setAttribute("height", 40);
node[0][0].__mainRect__ = mainRect;
d3.select(mainRect)
.on("mouseup",nodeMouseUp)
@@ -4249,50 +4265,50 @@ RED.view = (function() {
.on("touchend",nodeTouchEnd)
nodeContents.appendChild(mainRect);
var output_groupEl = RED.utils.createSVGElement("g", { x: 0, y: 0 })
var output_groupEl = document.createElementNS("http://www.w3.org/2000/svg","g");
output_groupEl.setAttribute("x",0);
output_groupEl.setAttribute("y",0);
node[0][0].__outputLabelGroup__ = output_groupEl;
var output_output = RED.utils.createSVGElement("text", { class: "red-ui-flow-port-label" })
var output_output = document.createElementNS("http://www.w3.org/2000/svg","text");
output_output.setAttribute("class","red-ui-flow-port-label");
output_output.style["font-size"] = "10px";
output_output.textContent = "output";
output_groupEl.appendChild(output_output);
node[0][0].__outputOutput__ = output_output;
var output_number = RED.utils.createSVGElement("text", {
class: "red-ui-flow-port-label red-ui-flow-port-index",
x: 0,
y: 0
})
var output_number = document.createElementNS("http://www.w3.org/2000/svg","text");
output_number.setAttribute("class","red-ui-flow-port-label red-ui-flow-port-index");
output_number.setAttribute("x",0);
output_number.setAttribute("y",0);
output_number.textContent = d.i+1;
output_groupEl.appendChild(output_number);
node[0][0].__outputNumber__ = output_number;
var output_border = RED.utils.createSVGElement("path", {
d: "M 40 1 l 0 38",
class: "red-ui-flow-node-icon-shade-border"
})
var output_border = document.createElementNS("http://www.w3.org/2000/svg","path");
output_border.setAttribute("d","M 40 1 l 0 38")
output_border.setAttribute("class", "red-ui-flow-node-icon-shade-border")
output_groupEl.appendChild(output_border);
node[0][0].__outputBorder__ = output_border;
nodeContents.appendChild(output_groupEl);
var text = RED.utils.createSVGElement("g", {
class: "red-ui-flow-port-label",
transform: "translate(38,0)",
style: 'fill : #888' // hard coded here!
})
var text = document.createElementNS("http://www.w3.org/2000/svg","g");
text.setAttribute("class","red-ui-flow-port-label");
text.setAttribute("transform","translate(38,0)");
text.setAttribute('style', 'fill : #888'); // hard coded here!
node[0][0].__textGroup__ = text;
nodeContents.append(text);
var portEl = RED.utils.createSVGElement("g", { transform: 'translate(-5,15)'})
var portEl = document.createElementNS("http://www.w3.org/2000/svg","g");
portEl.setAttribute('transform','translate(-5,15)')
var port = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-port",
rx: 3,
ry: 3,
width: 10,
height: 10
})
var port = document.createElementNS("http://www.w3.org/2000/svg","rect");
port.setAttribute("class","red-ui-flow-port");
port.setAttribute("rx",3);
port.setAttribute("ry",3);
port.setAttribute("width",10);
port.setAttribute("height",10);
portEl.appendChild(port);
port.__data__ = d;
@@ -4421,11 +4437,10 @@ RED.view = (function() {
}
for (var i=0; i<sn; i++) {
if (i===textLines.length) {
var line = RED.utils.createSVGElement("text", {
class: "red-ui-flow-node-label-text",
x: 0,
y: i*24
});
var line = document.createElementNS("http://www.w3.org/2000/svg","text");
line.setAttribute("class","red-ui-flow-node-label-text");
line.setAttribute("x",0);
line.setAttribute("y",i*24);
this.__textGroup__.appendChild(line);
}
textLines[i].textContent = sa[i];
@@ -4495,35 +4510,32 @@ RED.view = (function() {
d.resize = true;
if (d._def.button) {
var buttonGroup = RED.utils.createSVGElement("g", {
class: "red-ui-flow-node-button",
transform: "translate("+((d._def.align == "right") ? 94 : -25)+",2)"
})
var buttonGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
buttonGroup.__data__ = d;
buttonGroup.setAttribute("transform", "translate("+((d._def.align == "right") ? 94 : -25)+",2)");
buttonGroup.setAttribute("class","red-ui-flow-node-button");
node[0][0].__buttonGroup__ = buttonGroup;
var bgBackground = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-node-button-background",
rx: 5,
ry: 5,
width: 32,
height: node_height-4
})
var bgBackground = document.createElementNS("http://www.w3.org/2000/svg","rect");
bgBackground.__data__ = d;
bgBackground.setAttribute("class","red-ui-flow-node-button-background");
bgBackground.setAttribute("rx",5);
bgBackground.setAttribute("ry",5);
bgBackground.setAttribute("width",32);
bgBackground.setAttribute("height",node_height-4);
buttonGroup.appendChild(bgBackground);
node[0][0].__buttonGroupBackground__ = bgBackground;
var bgButton = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-node-button-button",
x: d._def.align == "right"? 11:5,
y: 4,
rx: 4,
ry: 4,
width: 16,
height: node_height-12,
fill: RED.utils.getNodeColor(d.type,d._def)
})
var bgButton = document.createElementNS("http://www.w3.org/2000/svg","rect");
bgButton.__data__ = d;
bgButton.setAttribute("class","red-ui-flow-node-button-button");
bgButton.setAttribute("x", d._def.align == "right"? 11:5);
bgButton.setAttribute("y",4);
bgButton.setAttribute("rx",4);
bgButton.setAttribute("ry",4);
bgButton.setAttribute("width",16);
bgButton.setAttribute("height",node_height-12);
bgButton.setAttribute("fill", RED.utils.getNodeColor(d.type,d._def));
d3.select(bgButton)
.on("mousedown",function(d) {if (!lasso && isButtonEnabled(d)) {focusView();d3.select(this).attr("fill-opacity",0.2);d3.event.preventDefault(); d3.event.stopPropagation();}})
.on("mouseup",function(d) {if (!lasso && isButtonEnabled(d)) { d3.select(this).attr("fill-opacity",0.4);d3.event.preventDefault();d3.event.stopPropagation();}})
@@ -4544,13 +4556,12 @@ RED.view = (function() {
}
var mainRect = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-node "+(d.type == "unknown"?"red-ui-flow-node-unknown":""),
rx: 5,
ry: 5,
fill: RED.utils.getNodeColor(d.type,d._def)
})
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
mainRect.__data__ = d;
mainRect.setAttribute("class", "red-ui-flow-node "+(d.type == "unknown"?"red-ui-flow-node-unknown":""));
mainRect.setAttribute("rx", 5);
mainRect.setAttribute("ry", 5);
mainRect.setAttribute("fill", RED.utils.getNodeColor(d.type,d._def));
node[0][0].__mainRect__ = mainRect;
d3.select(mainRect)
.on("mouseup",nodeMouseUp)
@@ -4565,65 +4576,61 @@ RED.view = (function() {
if (d._def.icon) {
var icon_url = RED.utils.getNodeIcon(d._def,d);
var icon_groupEl = RED.utils.createSVGElement("g", {
class: "red-ui-flow-node-icon-group"+("right" == d._def.align?" red-ui-flow-node-icon-group-right":""),
x: 0,
y: 0
})
icon_groupEl.style["pointer-events"] = "none";
var icon_groupEl = document.createElementNS("http://www.w3.org/2000/svg","g");
icon_groupEl.__data__ = d;
icon_groupEl.setAttribute("class","red-ui-flow-node-icon-group"+("right" == d._def.align?" red-ui-flow-node-icon-group-right":""));
icon_groupEl.setAttribute("x",0);
icon_groupEl.setAttribute("y",0);
icon_groupEl.style["pointer-events"] = "none";
node[0][0].__iconGroup__ = icon_groupEl;
var icon_shade = RED.utils.createSVGElement("path", {
x: 0,
y: 0,
class: "red-ui-flow-node-icon-shade"
})
var icon_shade = document.createElementNS("http://www.w3.org/2000/svg","path");
icon_shade.setAttribute("x",0);
icon_shade.setAttribute("y",0);
icon_shade.setAttribute("class","red-ui-flow-node-icon-shade")
icon_groupEl.appendChild(icon_shade);
node[0][0].__iconShade__ = icon_shade;
var icon_group = d3.select(icon_groupEl)
createIconAttributes(icon_url, icon_group, d);
var icon_shade_border = RED.utils.createSVGElement("path", {
d: "right" != d._def.align ? "M 30 1 l 0 "+(d.h-2) : "M 0 1 l 0 "+(d.h-2),
class: "red-ui-flow-node-icon-shade-border"
})
var icon_shade_border = document.createElementNS("http://www.w3.org/2000/svg","path");
icon_shade_border.setAttribute("d","right" != d._def.align ? "M 30 1 l 0 "+(d.h-2) : "M 0 1 l 0 "+(d.h-2) )
icon_shade_border.setAttribute("class", "red-ui-flow-node-icon-shade-border")
icon_groupEl.appendChild(icon_shade_border);
node[0][0].__iconShadeBorder__ = icon_shade_border;
nodeContents.appendChild(icon_groupEl);
}
var text = RED.utils.createSVGElement("g", {
class: "red-ui-flow-node-label"+(hideLabel?" hide":"")+(d._def.align?" red-ui-flow-node-label-"+d._def.align:""),
transform: "translate(38,0)"
// dy: ".3px",
// "text-anchor": d._def.align !== "right" ? "start":"end"
})
var text = document.createElementNS("http://www.w3.org/2000/svg","g");
text.setAttribute("class","red-ui-flow-node-label"+(hideLabel?" hide":"")+(d._def.align?" red-ui-flow-node-label-"+d._def.align:""));
text.setAttribute("transform","translate(38,0)");
// text.setAttribute("dy", ".3px");
// text.setAttribute("text-anchor",d._def.align !== "right" ? "start":"end");
nodeContents.appendChild(text);
node[0][0].__textGroup__ = text;
var statusEl = RED.utils.createSVGElement("g", { class: "red-ui-flow-node-status-group" })
var statusEl = document.createElementNS("http://www.w3.org/2000/svg","g");
// statusEl.__data__ = d;
statusEl.setAttribute("class","red-ui-flow-node-status-group");
statusEl.style.display = "none";
node[0][0].__statusGroup__ = statusEl;
var statusRect = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-node-status",
x: 6,
y: 1,
width: 9,
height: 9,
rx: 2,
ry: 2,
"stroke-width": 3
})
var statusRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
statusRect.setAttribute("class","red-ui-flow-node-status");
statusRect.setAttribute("x",6);
statusRect.setAttribute("y",1);
statusRect.setAttribute("width",9);
statusRect.setAttribute("height",9);
statusRect.setAttribute("rx",2);
statusRect.setAttribute("ry",2);
statusRect.setAttribute("stroke-width","3");
statusEl.appendChild(statusRect);
node[0][0].__statusShape__ = statusRect;
var statusLabel = RED.utils.createSVGElement("text", {
class: "red-ui-flow-node-status-label",
x: 20,
y: 10
})
var statusLabel = document.createElementNS("http://www.w3.org/2000/svg","text");
statusLabel.setAttribute("class","red-ui-flow-node-status-label");
statusLabel.setAttribute("x",20);
statusLabel.setAttribute("y",10);
statusEl.appendChild(statusLabel);
node[0][0].__statusLabel__ = statusLabel;
@@ -4708,11 +4715,10 @@ RED.view = (function() {
}
for (var i=0; i<sn; i++) {
if (i===textLines.length) {
var line = RED.utils.createSVGElement("text", {
class: "red-ui-flow-node-label-text",
x: 0,
y: i*24
})
var line = document.createElementNS("http://www.w3.org/2000/svg","text");
line.setAttribute("class","red-ui-flow-node-label-text");
line.setAttribute("x",0);
line.setAttribute("y",i*24);
this.__textGroup__.appendChild(line);
}
textLines[i].textContent = sa[i];
@@ -4811,23 +4817,22 @@ RED.view = (function() {
for(var portIndex = 0; portIndex < numOutputs; portIndex++ ) {
var portGroup;
if (portIndex === this.__outputs__.length) {
portGroup = RED.utils.createSVGElement("g", { class: "red-ui-flow-port-output" })
portGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
portGroup.setAttribute("class","red-ui-flow-port-output");
var portPort;
if (d.type === "link out") {
portPort = RED.utils.createSVGElement("circle", {
cx: 11,
cy: 5,
r: 5,
class: "red-ui-flow-port red-ui-flow-link-port"
})
portPort = document.createElementNS("http://www.w3.org/2000/svg","circle");
portPort.setAttribute("cx",11);
portPort.setAttribute("cy",5);
portPort.setAttribute("r",5);
portPort.setAttribute("class","red-ui-flow-port red-ui-flow-link-port");
} else {
portPort = RED.utils.createSVGElement("rect", {
rx: 3,
ry: 3,
width: 10,
height: 10,
class: "red-ui-flow-port"
})
portPort = document.createElementNS("http://www.w3.org/2000/svg","rect");
portPort.setAttribute("rx",3);
portPort.setAttribute("ry",3);
portPort.setAttribute("width",10);
portPort.setAttribute("height",10);
portPort.setAttribute("class","red-ui-flow-port");
}
portGroup.appendChild(portPort);
portGroup.__port__ = portPort;
@@ -4904,7 +4909,7 @@ RED.view = (function() {
if (d._def.button) {
var buttonEnabled = isButtonEnabled(d);
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-disabled", !buttonEnabled);
if (RED.runtime && Object.hasOwn(RED.runtime,'started')) {
if (RED.runtime && RED.runtime.started !== undefined) {
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-stopped", !RED.runtime.started);
}
@@ -4979,28 +4984,26 @@ RED.view = (function() {
var junction = d3.select(this);
var contents = document.createDocumentFragment();
// d.added = true;
var junctionBack = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-junction-background",
x: -5,
y: -5,
width: 10,
height: 10,
rx: 3,
ry: 3
})
var junctionBack = document.createElementNS("http://www.w3.org/2000/svg","rect");
junctionBack.setAttribute("class","red-ui-flow-junction-background");
junctionBack.setAttribute("x",-5);
junctionBack.setAttribute("y",-5);
junctionBack.setAttribute("width",10);
junctionBack.setAttribute("height",10);
junctionBack.setAttribute("rx",3);
junctionBack.setAttribute("ry",3);
junctionBack.__data__ = d;
this.__junctionBack__ = junctionBack;
contents.appendChild(junctionBack);
var junctionInput = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-junction-port red-ui-flow-junction-port-input",
x: -5,
y: -5,
width: 10,
height: 10,
rx: 3,
ry: 3
})
var junctionInput = document.createElementNS("http://www.w3.org/2000/svg","rect");
junctionInput.setAttribute("class","red-ui-flow-junction-port red-ui-flow-junction-port-input");
junctionInput.setAttribute("x",-5);
junctionInput.setAttribute("y",-5);
junctionInput.setAttribute("width",10);
junctionInput.setAttribute("height",10);
junctionInput.setAttribute("rx",3);
junctionInput.setAttribute("ry",3);
junctionInput.__data__ = d;
junctionInput.__portType__ = PORT_TYPE_INPUT;
junctionInput.__portIndex__ = 0;
@@ -5012,15 +5015,14 @@ RED.view = (function() {
this.__junctionInput__ = junctionInput;
contents.appendChild(junctionInput);
var junctionOutput = RED.utils.createSVGElement("rect", {
class: "red-ui-flow-junction-port red-ui-flow-junction-port-output",
x: -5,
y: -5,
width: 10,
height: 10,
rx: 3,
ry: 3,
})
var junctionOutput = document.createElementNS("http://www.w3.org/2000/svg","rect");
junctionOutput.setAttribute("class","red-ui-flow-junction-port red-ui-flow-junction-port-output");
junctionOutput.setAttribute("x",-5);
junctionOutput.setAttribute("y",-5);
junctionOutput.setAttribute("width",10);
junctionOutput.setAttribute("height",10);
junctionOutput.setAttribute("rx",3);
junctionOutput.setAttribute("ry",3);
junctionOutput.__data__ = d;
junctionOutput.__portType__ = PORT_TYPE_OUTPUT;
junctionOutput.__portIndex__ = 0;
@@ -5077,8 +5079,9 @@ RED.view = (function() {
var pathContents = document.createDocumentFragment();
d.added = true;
var pathBack = RED.utils.createSVGElement("path", { class: "red-ui-flow-link-background red-ui-flow-link-path"+(d.link?" red-ui-flow-link-link":"")})
var pathBack = document.createElementNS("http://www.w3.org/2000/svg","path");
pathBack.__data__ = d;
pathBack.setAttribute("class","red-ui-flow-link-background red-ui-flow-link-path"+(d.link?" red-ui-flow-link-link":""));
this.__pathBack__ = pathBack;
pathContents.appendChild(pathBack);
d3.select(pathBack)
@@ -5114,17 +5117,16 @@ RED.view = (function() {
}
})
var pathOutline = RED.utils.createSVGElement("path", {
class: "red-ui-flow-link-outline red-ui-flow-link-path"
})
var pathOutline = document.createElementNS("http://www.w3.org/2000/svg","path");
pathOutline.__data__ = d;
pathOutline.setAttribute("class","red-ui-flow-link-outline red-ui-flow-link-path");
this.__pathOutline__ = pathOutline;
pathContents.appendChild(pathOutline);
var pathLine = RED.utils.createSVGElement("path", {
class: "red-ui-flow-link-line red-ui-flow-link-path"+(d.link?" red-ui-flow-link-link":(activeSubflow?" red-ui-flow-subflow-link":""))
})
var pathLine = document.createElementNS("http://www.w3.org/2000/svg","path");
pathLine.__data__ = d;
pathLine.setAttribute("class","red-ui-flow-link-line red-ui-flow-link-path"+
(d.link?" red-ui-flow-link-link":(activeSubflow?" red-ui-flow-subflow-link":"")));
this.__pathLine__ = pathLine;
pathContents.appendChild(pathLine);

View File

@@ -30,7 +30,7 @@
bottom: 0px;
left:0px;
right: 0px;
overflow-y: scroll;
overflow-y: auto;
}
.red-ui-debug-filter-box {
position:absolute;

View File

@@ -368,7 +368,7 @@ button.red-ui-button-small
border:1px solid var(--red-ui-secondary-border-color);
border-radius:5px;
height: calc(100% - 21px);
overflow-y: scroll;
overflow-y: auto;
background: var(--red-ui-secondary-background);
}
@@ -562,7 +562,7 @@ div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
.red-ui-icon-list {
width: 308px;
height: 200px;
overflow-y: scroll;
overflow-y: auto;
line-height: 0px;
position: relative;
&.red-ui-icon-list-dark {

View File

@@ -26,7 +26,7 @@
}
}
#red-ui-project-settings-tab-settings {
overflow-y: scroll;
overflow-y: auto;
}
.red-ui-sidebar-vc-shade {
background: var(--red-ui-primary-background);
@@ -183,7 +183,7 @@
}
.red-ui-projects-dialog-project-list-inner-container {
flex-grow: 1 ;
overflow-y: scroll;
overflow-y: auto;
position:relative;
.red-ui-editableList-border {
border: none;

View File

@@ -20,7 +20,7 @@
bottom: 0;
left: 0;
right: 0;
overflow-y: scroll;
overflow-y: auto;
.red-ui-palette-category {
&:not(.expanded) button {

View File

@@ -67,7 +67,7 @@
left: 0;
bottom: 0;
padding: 8px 20px 20px;
overflow-y: scroll;
overflow-y: auto;
}
.red-ui-settings-row {
padding: 5px 10px 2px;

View File

@@ -29,7 +29,7 @@
#red-ui-workspace-chart {
overflow: auto;
position: absolute;
bottom:25px;
bottom:26px;
top: 35px;
left:0px;
right:0px;

View File

@@ -14,6 +14,9 @@ declare var msg: NodeMessage;
/** @type {string} the id of the incoming `msg` (alias of msg._msgid) */
declare const __msgid__:string;
declare const util:typeof import('util')
declare const promisify:typeof import('util').promisify
/**
* @typedef NodeStatus
* @type {object}

View File

@@ -160,6 +160,7 @@
'$base64encode':{ args:[ ]},
'$boolean':{ args:[ 'arg' ]},
'$ceil':{ args:[ 'number' ]},
'$clone': { args:[ 'arg' ]},
'$contains':{ args:[ 'str', 'pattern' ]},
'$count':{ args:[ 'array' ]},
'$decodeUrl':{ args:[ 'str' ]},

View File

@@ -1,6 +1,6 @@
<script type="text/html" data-template-name="complete">
<div class="form-row node-input-target-row">
<button id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
<button type="button" id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-complete-target-filter"></div>

View File

@@ -12,7 +12,7 @@
<label for="node-input-uncaught" style="width: auto" data-i18n="catch.label.uncaught"></label>
</div>
<div class="form-row node-input-target-row">
<button id="node-input-catch-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
<button type="button" id="node-input-catch-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-catch-target-filter"></div>

View File

@@ -8,7 +8,7 @@
</select>
</div>
<div class="form-row node-input-target-row">
<button id="node-input-status-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
<button type="button" id="node-input-status-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-status-target-filter"></div>

View File

@@ -91,21 +91,21 @@
<div id="func-tab-init" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button type="button" id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-body" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 220px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button type="button" id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button type="button" id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
@@ -294,7 +294,7 @@
if (val === "_custom_") {
val = $(this).val();
}
var varName = val.trim().replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/].?/g, function(v) { return v[1]?v[1].toUpperCase():"" });
var varName = val.trim().replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/\.].?/g, function(v) { return v[1]?v[1].toUpperCase():"" });
fvar.val(varName);
fvar.trigger("change");
@@ -451,11 +451,13 @@
tabs.activateTab("func-tab-body");
$( "#node-input-outputs" ).spinner({
min:0,
min: 0,
max: 500,
change: function(event, ui) {
var value = this.value;
if (!value.match(/^\d+$/)) { value = 1; }
else if (value < this.min) { value = this.min; }
var value = parseInt(this.value);
value = isNaN(value) ? 1 : value;
value = Math.max(value, parseInt($(this).attr("aria-valuemin")));
value = Math.min(value, parseInt($(this).attr("aria-valuemax")));
if (value !== this.value) { $(this).spinner("value", value); }
}
});

View File

@@ -26,7 +26,7 @@
<option value="yaml">YAML</option>
<option value="text" data-i18n="template.label.none"></option>
</select>
<button id="node-template-expand-editor" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button>
<button type="button" id="node-template-expand-editor" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button>
</div>
</div>
<div class="form-row node-text-editor-row">

View File

@@ -25,7 +25,7 @@
<label class="red-ui-button" for="node-config-input-certfile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" id="node-config-input-certfile">
<span id="tls-config-certname" style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
<button class="red-ui-button red-ui-button-small" id="tls-config-button-cert-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
<button type="button" class="red-ui-button red-ui-button-small" id="tls-config-button-cert-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
</span>
<input type="hidden" id="node-config-input-certname">
<input type="hidden" id="node-config-input-certdata">
@@ -37,7 +37,7 @@
<label class="red-ui-button" for="node-config-input-keyfile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" id="node-config-input-keyfile">
<span id="tls-config-keyname" style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
<button class="red-ui-button red-ui-button-small" id="tls-config-button-key-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
<button type="button" class="red-ui-button red-ui-button-small" id="tls-config-button-key-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
</span>
<input type="hidden" id="node-config-input-keyname">
<input type="hidden" id="node-config-input-keydata">
@@ -53,7 +53,7 @@
<label class="red-ui-button" for="node-config-input-cafile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" title=" " id="node-config-input-cafile">
<span id="tls-config-caname" style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
<button class="red-ui-button red-ui-button-small" id="tls-config-button-ca-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
<button type="button" class="red-ui-button red-ui-button-small" id="tls-config-button-ca-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
</span>
<input type="hidden" id="node-config-input-caname">
<input type="hidden" id="node-config-input-cadata">

View File

@@ -101,6 +101,7 @@
hostField.val(data.host);
}
},
sortable: true,
removable: true
});
if (this.noproxy) {

View File

@@ -474,7 +474,6 @@ module.exports = function(RED) {
setIfHasProperty(opts, node, "protocolVersion", init);
setIfHasProperty(opts, node, "keepalive", init);
setIfHasProperty(opts, node, "cleansession", init);
setIfHasProperty(opts, node, "sessionExpiry", init);
setIfHasProperty(opts, node, "topicAliasMaximum", init);
setIfHasProperty(opts, node, "maximumPacketSize", init);
setIfHasProperty(opts, node, "receiveMaximum", init);
@@ -484,6 +483,11 @@ module.exports = function(RED) {
} else if (hasProperty(opts, "userProps")) {
node.userProperties = opts.userProps;
}
if (hasProperty(opts, "sessionExpiry")) {
node.sessionExpiryInterval = opts.sessionExpiry;
} else if (hasProperty(opts, "sessionExpiryInterval")) {
node.sessionExpiryInterval = opts.sessionExpiryInterval
}
function createLWT(topic, payload, qos, retain, v5opts, v5SubPropName) {
let message = undefined;
@@ -782,7 +786,9 @@ module.exports = function(RED) {
// Send any birth message
if (node.birthMessage) {
node.publish(node.birthMessage);
setTimeout(() => {
node.publish(node.birthMessage);
}, 1);
}
});
node._clientOn("reconnect", function() {
@@ -991,14 +997,21 @@ module.exports = function(RED) {
}
if (topicOK) {
node.client.publish(msg.topic, msg.payload, options, function(err) {
done && done(err);
return
});
node.client.publish(msg.topic, msg.payload, options, function (err) {
if (done) {
done(err)
} else {
node.error(err, msg)
}
})
} else {
const error = new Error(RED._("mqtt.errors.invalid-topic"));
error.warn = true;
done(error);
const error = new Error(RED._("mqtt.errors.invalid-topic"))
error.warn = true
if (done) {
done(error)
} else {
node.warn(error, msg)
}
}
}
};

View File

@@ -227,6 +227,7 @@
}
});
},
sortable: true,
removable: true
});

View File

@@ -282,7 +282,7 @@ module.exports = function(RED) {
RED.nodes.createNode(this,n);
var node = this;
this.headers = n.headers||{};
this.statusCode = n.statusCode;
this.statusCode = parseInt(n.statusCode);
this.on("input",function(msg,_send,done) {
if (msg.res) {
var headers = RED.util.cloneMessage(node.headers);
@@ -323,7 +323,7 @@ module.exports = function(RED) {
}
}
}
var statusCode = node.statusCode || msg.statusCode || 200;
var statusCode = node.statusCode || parseInt(msg.statusCode) || 200;
if (typeof msg.payload == "object" && !Buffer.isBuffer(msg.payload)) {
msg.res._res.status(statusCode).jsonp(msg.payload);
} else {

View File

@@ -91,6 +91,11 @@
<label for="node-input-senderr" style="width: auto" data-i18n="httpin.senderr"></label>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-insecureHTTPParser" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-insecureHTTPParser", style="width: auto;" data-i18n="httpin.insecureHTTPParser"></label>
</div>
<div class="form-row">
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
@@ -227,6 +232,7 @@
persist: {value:false},
proxy: {type:"http proxy",required: false,
label:RED._("node-red:httpin.proxy-config") },
insecureHTTPParser: {value: false},
authType: {value: ""},
senderr: {value: false},
headers: { value: [] }
@@ -338,6 +344,12 @@
} else {
$("#node-input-useProxy").prop("checked", false);
}
if (node.insecureHTTPParser) {
$("node-intput-insecureHTTPParser").prop("checked", true)
} else {
$("node-intput-insecureHTTPParser").prop("checked", false)
}
updateProxyOptions();
$("#node-input-useProxy").on("click", function() {
updateProxyOptions();
@@ -405,6 +417,7 @@
});
},
sortable: true,
removable: true
});
if (node.headers) {

View File

@@ -86,6 +86,7 @@ in your Node-RED user directory (${RED.settings.userDir}).
if (n.paytoqs === true || n.paytoqs === "query") { paytoqs = true; }
else if (n.paytoqs === "body") { paytobody = true; }
node.insecureHTTPParser = n.insecureHTTPParser
var prox, noprox;
if (process.env.http_proxy) { prox = process.env.http_proxy; }
@@ -244,6 +245,10 @@ in your Node-RED user directory (${RED.settings.userDir}).
delete options.headers[h];
}
})
if (node.insecureHTTPParser) {
options.insecureHTTPParser = true
}
}
],
beforeRedirect: [

View File

@@ -52,4 +52,7 @@
used to mark the templated sections. For example, to use <code>[[ ]]</code>
instead, add the following line to the top of the template:</p>
<pre>{{=[[ ]]=}}</pre>
<h4>Using environment variables</h4>
<p>The template node can access environment variables using the syntax:</p>
<pre>My favourite colour is {{env.COLOUR}}.</pre>
</script>

View File

@@ -554,7 +554,8 @@
},
"status": {
"requesting": "requesting"
}
},
"insecureHTTPParser": "Disable strict HTTP parsing"
},
"websocket": {
"label": {

View File

@@ -48,4 +48,7 @@
<p><b>: </b>デフォルトでは、<i>mustache</i>形式は置換対象のHTML要素をエスケープしますこれを抑止するには<code>{{{三重}}}</code>使</p>
<p>もしコンテンツの中で<code>{{ }}</code>使<code>[[ ]]</code></p>
<pre>{{=[[ ]]=}}</pre>
<h4>環境変数の利用</h4>
<p>templateードでは次の構文を用いると環境変数にアクセスできます:</p>
<pre>私の好きな色は{{env.COLOUR}}です</pre>
</script>

View File

@@ -554,7 +554,8 @@
},
"status": {
"requesting": "要求中"
}
},
"insecureHTTPParser": "厳密なHTTPパース処理を無効化"
},
"websocket": {
"label": {

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -25,7 +25,7 @@
"cookie": "0.5.0",
"cors": "2.8.5",
"cronosjs": "1.7.1",
"denque": "2.0.1",
"denque": "2.1.0",
"form-data": "4.0.0",
"fs-extra": "10.1.0",
"got": "11.8.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,11 +16,11 @@
}
],
"dependencies": {
"@node-red/util": "3.1.0-beta.0",
"@node-red/util": "3.0.2",
"clone": "2.1.2",
"fs-extra": "10.1.0",
"semver": "7.3.7",
"tar": "6.1.11",
"uglify-js": "3.16.2"
"uglify-js": "3.16.3"
}
}

View File

@@ -100,9 +100,13 @@ function buildDiagnosticReport(scope, callback) {
version: os.version(),
},
runtime: {
isStarted: runtime.isStarted(),
modules: modules,
version: runtime.settings.version,
isStarted: runtime.isStarted(),
flows: {
state: runtime.flows && runtime.flows.state(),
started: runtime.flows && runtime.flows.started,
},
modules: modules,
settings: {
available: runtime.settings.available(),
apiMaxLength: runtime.settings.apiMaxLength || "UNSET",
@@ -114,6 +118,11 @@ function buildDiagnosticReport(scope, callback) {
flowFile: runtime.settings.flowFile || "UNSET",
mqttReconnectTime: runtime.settings.mqttReconnectTime || "UNSET",
serialReconnectTime: runtime.settings.serialReconnectTime || "UNSET",
socketReconnectTime: runtime.settings.socketReconnectTime || "UNSET",
socketTimeout: runtime.settings.socketTimeout || "UNSET",
tcpMsgQueueSize: runtime.settings.tcpMsgQueueSize || "UNSET",
inboundWebSocketTimeout: runtime.settings.inboundWebSocketTimeout || "UNSET",
runtimeState: runtime.settings.runtimeState || "UNSET",
adminAuth: runtime.settings.adminAuth ? "SET" : "UNSET",
@@ -131,6 +140,7 @@ function buildDiagnosticReport(scope, callback) {
uiHost: runtime.settings.uiHost ? "SET" : "UNSET",
uiPort: runtime.settings.uiPort ? "SET" : "UNSET",
userDir: runtime.settings.userDir ? "SET" : "UNSET",
nodesDir: runtime.settings.nodesDir && runtime.settings.nodesDir.length ? "SET" : "UNSET",
}
}
}

View File

@@ -134,10 +134,12 @@ function createNode(flow,config) {
subflowInstanceConfig,
instanceConfig
);
// Register this subflow as an instance node of the parent flow.
// This allows nodes inside the subflow to get ahold of each other
// such as a node accessing its config node
flow.subflowInstanceNodes[config.id] = subflow
subflow.start();
return subflow.node;
Log.error(Log._("nodes.flow.unknown-type", {type:type}));
}
} catch(err) {
Log.error(err);

View File

@@ -373,6 +373,11 @@ Node.prototype.send = function(msg) {
if (msg === null || typeof msg === "undefined") {
return;
} else if (!util.isArray(msg)) {
// A single message has been passed in
if (typeof msg !== 'object') {
this.error(Log._("nodes.flow.non-message-returned", { type: typeof msg }));
return
}
if (this._wire) {
// A single message and a single wire on output 0
// TODO: pre-load flows.get calls - cannot do in constructor
@@ -425,27 +430,31 @@ Node.prototype.send = function(msg) {
for (k = 0; k < msgs.length; k++) {
var m = msgs[k];
if (m !== null && m !== undefined) {
if (!m._msgid) {
hasMissingIds = true;
if (typeof m !== 'object') {
this.error(Log._("nodes.flow.non-message-returned", { type: typeof m }));
} else {
if (!m._msgid) {
hasMissingIds = true;
}
/* istanbul ignore else */
if (!sentMessageId) {
sentMessageId = m._msgid;
}
sendEvents.push({
msg: m,
source: {
id: this.id,
node: this,
port: i
},
destination: {
id: wires[j],
node: undefined
},
cloneMessage: msgSent
});
msgSent = true;
}
/* istanbul ignore else */
if (!sentMessageId) {
sentMessageId = m._msgid;
}
sendEvents.push({
msg: m,
source: {
id: this.id,
node: this,
port: i
},
destination: {
id: wires[j],
node: undefined
},
cloneMessage: msgSent
});
msgSent = true;
}
}
}

View File

@@ -1,6 +1,6 @@
{
"runtime": {
"welcome": "Willkommen bei Node-RED!",
"welcome": "Willkommen bei Node-RED",
"version": "__component__ Version: __version__",
"unsupported_version": "Nicht unterstützte Version von __component__. Erforderlich: __requires__, jedoch gefunden: __version__",
"paths": {
@@ -8,7 +8,6 @@
"httpStatic": "HTTP-Statisch: __path__"
}
},
"server": {
"loading": "Paletten-Nodes werden geladen",
"palette-editor": {
@@ -34,17 +33,19 @@
"install-failed-not-found": "Das Modul $t(server.install.install-failed-long) wurde nicht gefunden",
"install-failed-name": "$t(server.install.install-failed-long). Ungültiger Modulname: __name__",
"install-failed-url": "$t(server.install.install-failed-long). Ungültige URL: __url__",
"post-install-error": "Fehler bei der Ausführung des 'postInstall'-Hooks:",
"upgrading": "Upgrade von Modul __name__ auf Version __version__ gestartet",
"upgraded": "Upgrade von Modul __name__ war erfolgreich. Neustart von Node-RED für die Verwendung der neuen Version erforderlich.",
"upgrade-failed-not-found": "Upgrade fehlgeschlagen. $t(server.install.install-failed-long). Version nicht gefunden.",
"uninstalling": "Das Modul __name__ wird deinstalliert",
"uninstall-failed": "Deinstallation fehlgeschlagen",
"uninstall-failed-long": "Die Deinstallation des Moduls __name__ ist fehlgeschlagen:",
"uninstalled": "Das Modul __name__ ist deinstalliert"
"uninstalled": "Das Modul __name__ ist deinstalliert",
"old-ext-mod-dir-warning": "\n\n---------------------------------------------------------------------\nNode-RED 1.3 Verzeichnis externer Module erkannt:\n __oldDir__\nDieses Verzeichnis wird nicht mehr verwendet. Die externen Module werden\nin Ihrem Node-RED-Benutzerverzeichnis neu installiert:\n __newDir__\nLöschen Sie das alte externalModules-Verzeichnis, um diese Meldung abzustellen.\n---------------------------------------------------------------------\n"
},
"deprecatedOption": "Die Verwendung von __old__ ist abgekündigt. Stattdessen __new__ verwenden.",
"unable-to-listen": "Überwachen (listen) von __listenpath__ nicht möglich",
"port-in-use": "FEHLER: Port wird verwendet",
"port-in-use": "Fehler: Port wird verwendet",
"uncaught-exception": "Nicht abgefangene Ausnahmebedingung:",
"admin-ui-disabled": "Administrator-Benutzeroberfläche deaktiv",
"now-running": "Server wird jetzt auf __listenpath__ ausgeführt",
@@ -55,11 +56,10 @@
"refresh-interval": "Erneuerung der https-Einstellungen erfolgt alle __interval__ Stunden",
"settings-refreshed": "https-Einstellungen wurden erneuert",
"refresh-failed": "Erneuerung der https-Einstellungen fehlgeschlagen: __message__",
"nodejs-version": "httpsRefreshInterval erfordert Node.js 11 or later",
"nodejs-version": "httpsRefreshInterval erfordert Node.js 11 oder höher",
"function-required": "httpsRefreshInterval erfordert die https-Eigenschaft in Form einer Funktion"
}
},
"api": {
"flows": {
"error-save": "Fehler beim Speichern der Flows: __message__",
@@ -77,17 +77,16 @@
"error-enable": "Der Node konnte nicht aktiviert werden:"
}
},
"comms": {
"error": "Kommunikationskanal-Fehler: __message__",
"error-server": "Kommunikationsserver-Fehler: __message__",
"error-send": "Kommunikationsende-Fehler: __message__"
},
"settings": {
"user-not-available": "Einstellungen konnten nicht gespeichert werden: __message__",
"not-available": "Einstellungen nicht verfügbar",
"property-read-only": "Die Eigenschaft '__prop__ 'ist schreibgeschützt"
"property-read-only": "Die Eigenschaft '__prop__' ist schreibgeschützt",
"readonly-mode": "Laufzeitumgebung im Nur-Lese-Modus. Änderungen werden nicht gespeichert."
},
"library": {
"unknownLibrary": "Unbekannte Bibliothek (Library): __library__",
@@ -98,10 +97,12 @@
},
"nodes": {
"credentials": {
"error": "Fehler beim Laden der Berechtigungen: __message__",
"error-saving": "Fehler beim Speichern der Berechtigungen: __message__",
"not-registered": "Der Berechtigung-Typ '__type__' ist nicht registriert",
"system-key-warning": "\n---------------------------------------------------------------------\nDie Datei mit den Flow-Berechtigungen wird mit einem vom System\ngenerierten Schlüssel verschlüsselt.\nWenn der vom System generierte Schlüssel aus irgendeinem Grund\nverloren geht, kann die Datei mit den Berechtigungen nicht\nwiederhergestellt werden. Sie muss dann gelöscht und die\nBerechtigungen müssen erneut eingestellt werden.\nEs sollte ein eigener Schlüssel mit Hilfe der Option\n'credentialSecret' in der Einstellungsdatei vorgegeben werden.\nNode-RED wird dann die Datei mit den Flow-Berechtigungen\nbei der nächsten Übernahme (deploy) einer Änderung erneut\nverschlüsseln.\n---------------------------------------------------------------------"
"error": "Fehler beim Laden der Credentials: __message__",
"error-saving": "Fehler beim Speichern der Credentials: __message__",
"not-registered": "Der Credentials-Typ '__type__' ist nicht registriert",
"system-key-warning": "\n---------------------------------------------------------------------\nDie Datei mit den Flow-Credentials wird mit einem vom System\ngenerierten Schlüssel verschlüsselt.\nWenn der vom System generierte Schlüssel aus irgendeinem Grund\nverloren geht, kann die Datei mit den Credentials nicht\nwiederhergestellt werden. Sie muss dann gelöscht und die\nCredentials müssen erneut eingestellt werden.\nEs sollte ein eigener Schlüssel mit Hilfe der Option\n'credentialSecret' in der Einstellungsdatei vorgegeben werden.\nNode-RED wird dann die Datei mit den Flow-Credentials\nbei der nächsten Übernahme (deploy) einer Änderung erneut\nverschlüsseln.\n---------------------------------------------------------------------",
"unencrypted": "Verwende unverschlüsselte Credentials",
"encryptedNotFound": "Verschlüsselte Credentials nicht gefunden"
},
"flows": {
"safe-mode": "Die Flows sind gestoppt im abgesicherten Modus. Übernahme (deploy) zum Starten.",
@@ -121,6 +122,7 @@
"stopped-flows": "Flows sind gestoppt",
"stopped": "gestoppt",
"stopping-error": "Fehler beim Stoppen des Nodes: __message__",
"updated-flows": "Flows aktualisiert",
"added-flow": "Flow wird hinzugefügt: __label__",
"updated-flow": "Aktualisierter Flow: __label__",
"removed-flow": "Entfernter Flow: __label__",
@@ -145,7 +147,6 @@
}
}
},
"storage": {
"index": {
"forbidden-flow-name": "Unzulässiger Flow-Name"
@@ -159,6 +160,7 @@
"restore": "Die '__type__'-Dateisicherung wird wiederhergestellt: __path__",
"restore-fail": "Die Wiederherstellung der '__type__'-Dateisicherung ist fehlgeschlagen: __message__",
"fsync-fail": "Die Übertragung der Datei __path__ auf das Laufwerk ist fehlgeschlagen: __message__",
"warn_name": "Name der Flows-Datei nicht festgelegt. Name wird unter Verwendung des Hostnamens generiert.",
"projects": {
"changing-project": "Aktives Projekt wird festgelegt: __project__",
"active-project": "Aktives Projekt: __project__",
@@ -174,7 +176,6 @@
}
}
},
"context": {
"log-store-init": "Kontextspeicher: __name__ [__info__]",
"error-loading-module": "Fehler beim Laden des Kontextspeichers: __message__",
@@ -189,5 +190,4 @@
"error-write": "Fehler beim Schreiben des Kontextes: __message__"
}
}
}

View File

@@ -134,7 +134,8 @@
"flow": {
"unknown-type": "Unknown type: __type__",
"missing-types": "missing types",
"error-loop": "Message exceeded maximum number of catches"
"error-loop": "Message exceeded maximum number of catches",
"non-message-returned": "Node tried to send a message of type __type__"
},
"index": {
"unrecognised-id": "Unrecognised id: __id__",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/registry": "3.1.0-beta.0",
"@node-red/util": "3.1.0-beta.0",
"@node-red/registry": "3.0.2",
"@node-red/util": "3.0.2",
"async-mutex": "0.3.2",
"clone": "2.1.2",
"express": "4.18.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/util",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
],
"dependencies": {
"fs-extra": "10.1.0",
"i18next": "21.8.14",
"i18next": "21.8.16",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.6",
"lodash.clonedeep": "^4.5.0",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "3.1.0-beta.0",
"version": "3.0.2",
"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": "3.1.0-beta.0",
"@node-red/runtime": "3.1.0-beta.0",
"@node-red/util": "3.1.0-beta.0",
"@node-red/nodes": "3.1.0-beta.0",
"@node-red/editor-api": "3.0.2",
"@node-red/runtime": "3.0.2",
"@node-red/util": "3.0.2",
"@node-red/nodes": "3.0.2",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"express": "4.18.1",

View File

@@ -31,6 +31,8 @@ var multer = require("multer");
var RED = require("nr-test-utils").require("node-red/lib/red");
var fs = require('fs-extra');
var auth = require('basic-auth');
const { version } = require("os");
const net = require('net')
describe('HTTP Request Node', function() {
var testApp;
@@ -2265,4 +2267,71 @@ describe('HTTP Request Node', function() {
});
});
});
describe('should parse broken headers', function() {
const versions = process.versions.node.split('.')
if (( versions[0] == 14 && versions[1] >= 20 ) ||
( versions[0] == 16 && versions[1] >= 16 ) ||
( versions[0] == 18 && versions[1] >= 5 ) ||
( versions[0] > 18)) {
// only test if on new enough NodeJS version
let port = testPort++
let server;
before(function() {
server = net.createServer(function (socket) {
socket.write("HTTP/1.0 200\nContent-Type: text/plain\n\nHelloWorld")
socket.end()
})
server.listen(port,'127.0.0.1', function(err) {
})
});
after(function() {
server.close()
});
it('should accept broken headers', function (done) {
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:`http://localhost:${port}/`, insecureHTTPParser: true},
{id:"n2", type:"helper"}];
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on('input', function(msg) {
try {
msg.payload.should.equal('HelloWorld')
done()
} catch (err) {
done(err)
}
})
n1.receive({payload: 'foo'})
});
});
it('should reject broken headers', function (done) {
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:`http://localhost:${port}/`},
{id:"n2", type:"helper"}];
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on('input', function(msg) {
try{
msg.payload.should.equal(`RequestError: Parse Error: Missing expected CR after header value : http://localhost:${port}/`)
done()
} catch (err) {
done(err)
}
})
n1.receive({payload: 'foo'})
});
});
}
});
});

View File

@@ -27,7 +27,7 @@ describe('MQTT Nodes', function () {
} catch (error) { }
});
it('should be loaded and have default values', function (done) {
it('should be loaded and have default values (MQTT V4)', function (done) {
this.timeout = 2000;
const { flow, nodes } = buildBasicMQTTSendRecvFlow({ id: "mqtt.broker", name: "mqtt_broker", autoConnect: false }, { id: "mqtt.in", topic: "in_topic" }, { id: "mqtt.out", topic: "out_topic" });
helper.load(mqttNodes, flow, function () {
@@ -61,6 +61,52 @@ describe('MQTT Nodes', function () {
mqttBroker.options.clientId.should.containEql('nodered_');
mqttBroker.options.should.have.property('keepalive').type("number");
mqttBroker.options.should.have.property('reconnectPeriod').type("number");
//as this is not a v5 connection, ensure v5 properties are not present
mqttBroker.options.should.not.have.property('protocolVersion', 5);
mqttBroker.options.should.not.have.property('properties');
done();
} catch (error) {
done(error)
}
});
});
it('should be loaded and have default values (MQTT V5)', function (done) {
this.timeout = 2000;
const { flow, nodes } = buildBasicMQTTSendRecvFlow({ id: "mqtt.broker", name: "mqtt_broker", autoConnect: false, cleansession: false, clientid: 'clientid', keepalive: 35, sessionExpiry: '6000', protocolVersion: '5', userProps: {"prop": "val"}}, { id: "mqtt.in", topic: "in_topic" }, { id: "mqtt.out", topic: "out_topic" });
helper.load(mqttNodes, flow, function () {
try {
const mqttIn = helper.getNode("mqtt.in");
const mqttOut = helper.getNode("mqtt.out");
const mqttBroker = helper.getNode("mqtt.broker");
should(mqttIn).be.type("object", "mqtt in node should be an object")
mqttIn.should.have.property('broker', nodes.mqtt_broker.id); //should be the id of the broker node
mqttIn.should.have.property('datatype', 'utf8'); //default: 'utf8'
mqttIn.should.have.property('isDynamic', false); //default: false
mqttIn.should.have.property('inputs', 0); //default: 0
mqttIn.should.have.property('qos', 2); //default: 2
mqttIn.should.have.property('topic', "in_topic");
mqttIn.should.have.property('wires', [["helper.node"]]);
should(mqttOut).be.type("object", "mqtt out node should be an object")
mqttOut.should.have.property('broker', nodes.mqtt_broker.id); //should be the id of the broker node
mqttOut.should.have.property('topic', "out_topic");
should(mqttBroker).be.type("object", "mqtt broker node should be an object")
mqttBroker.should.have.property('broker', BROKER_HOST);
mqttBroker.should.have.property('port', BROKER_PORT);
mqttBroker.should.have.property('brokerurl');
// mqttBroker.should.have.property('autoUnsubscribe', true);//default: true
mqttBroker.should.have.property('autoConnect', false);//Set "autoConnect:false" in brokerOptions
mqttBroker.should.have.property('options');
mqttBroker.options.should.have.property('clean', false);
mqttBroker.options.should.have.property('clientId', 'clientid');
mqttBroker.options.should.have.property('keepalive').type("number", 35);
mqttBroker.options.should.have.property('reconnectPeriod').type("number");
//as this IS a v5 connection, ensure v5 properties are not present
mqttBroker.options.should.have.property('protocolVersion', 5);
mqttBroker.options.should.have.property('properties');
mqttBroker.options.properties.should.have.property('sessionExpiryInterval');
done();
} catch (error) {
done(error)
@@ -173,7 +219,7 @@ describe('MQTT Nodes', function () {
topic: nextTopic(),
payload: '{prop:"value3", "num":3}', // send invalid JSON ...
}
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
const hooks = { done: null, beforeLoad: null, afterLoad: null, afterConnect: null }
hooks.afterLoad = (helperNode, mqttBroker, mqttIn, mqttOut) => {
helperNode.on("input", function (msg) {
try {
@@ -299,7 +345,7 @@ describe('MQTT Nodes', function () {
topic: nextTopic(),
payload: '{prop:"value3", "num":3}', contentType: "application/json", // send invalid JSON ...
}
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
const hooks = { done: null, beforeLoad: null, afterLoad: null, afterConnect: null }
hooks.afterLoad = (helperNode, mqttBroker, mqttIn, mqttOut) => {
helperNode.on("input", function (msg) {
try {
@@ -385,7 +431,7 @@ describe('MQTT Nodes', function () {
if (skipTests) { return this.skip() }
this.timeout = 2000;
const options = {}
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
const hooks = { beforeLoad: null, afterLoad: null, afterConnect: null }
hooks.beforeLoad = (flow) => { //add a status node pointed at MQTT Out node (to watch for connection status change)
flow.push({ "id": "status.node", "type": "status", "name": "status_node", "scope": ["mqtt.out"], "wires": [["helper.node"]] });//add status node to watch mqtt_out
}
@@ -416,18 +462,31 @@ describe('MQTT Nodes', function () {
this.timeout = 2000;
const baseTopic = nextTopic();
const brokerOptions = {
autoConnect: false,
protocolVersion: 4,
birthTopic: baseTopic + "/birth",
birthPayload: "broker connected",
birthPayload: "broker birth",
birthQos: 2,
}
const options = {};
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null };
options.expectMsg = {
const expectMsg = {
topic: brokerOptions.birthTopic,
payload: brokerOptions.birthPayload,
qos: brokerOptions.birthQos
};
const options = { };
const hooks = { };
hooks.afterLoad = (helperNode, mqttBroker, mqttIn, mqttOut) => {
helperNode.on("input", function (msg) {
try {
compareMsgToExpected(msg, expectMsg);
done();
} catch (error) {
done(error)
}
})
mqttIn.receive({ "action": "connect" }); //now request connect action
return true; //handled
}
testSendRecv(brokerOptions, { topic: brokerOptions.birthTopic }, {}, options, hooks);
});
itConditional('should publish close message', function (done) {
@@ -666,6 +725,7 @@ function buildMQTTBrokerNode(id, name, brokerHost, brokerPort, options) {
node.cleansession = String(options.cleansession) == "false" ? false : true;
node.autoUnsubscribe = String(options.autoUnsubscribe) == "false" ? false : true;
node.autoConnect = String(options.autoConnect) == "false" ? false : true;
node.sessionExpiry = options.sessionExpiry ? options.sessionExpiry : undefined;
if (options.birthTopic) {
node.birthTopic = options.birthTopic;
@@ -760,8 +820,8 @@ function waitBrokerConnect(broker, timeLimit) {
let waitConnected = (broker, timeLimit) => {
const brokers = Array.isArray(broker) ? broker : [broker];
timeLimit = timeLimit || 1000;
let timer, resolved = false;
return new Promise( (resolve, reject) => {
let timer, resolved = false;
timer = wait();
function wait() {
if (brokers.every(e => e.connected == true)) {

View File

@@ -61,7 +61,7 @@ describe("api/index", function() {
should.not.exist(api.httpAdmin);
done();
});
describe('initalises admin api without adminAuth', function(done) {
describe('initalises admin api without adminAuth', function() {
before(function() {
beforeEach();
api.init({},{},{},{});
@@ -78,7 +78,7 @@ describe("api/index", function() {
})
});
describe('initalises admin api without editor', function(done) {
describe('initalises admin api without editor', function() {
before(function() {
beforeEach();
api.init({ disableEditor: true },{},{},{});
@@ -95,7 +95,7 @@ describe("api/index", function() {
})
});
describe('initialises api with admin middleware', function(done) {
describe('initialises api with admin middleware', function() {
it('ignores non-function values',function(done) {
api.init({ httpAdminRoot: true, httpAdminMiddleware: undefined },{},{},{});
const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'testMiddleware')
@@ -112,7 +112,7 @@ describe("api/index", function() {
});
});
describe('initialises api with authentication enabled', function(done) {
describe('initialises api with authentication enabled', function() {
it('enables an oauth/openID based authentication mechanism',function(done) {
const stub = sinon.stub(apiAuth, 'genericStrategy').callsFake(function(){});
@@ -135,7 +135,7 @@ describe("api/index", function() {
});
describe('initialises api with custom cors config', function (done) {
describe('initialises api with custom cors config', function () {
const httpAdminCors = {
origin: "*",
methods: "GET,PUT,POST,DELETE"
@@ -156,7 +156,7 @@ describe("api/index", function() {
})
});
describe('editor start', function (done) {
describe('editor start', function () {
it('cannot be started when editor is disabled', function (done) {
const stub = sinon.stub(apiEditor, 'start').callsFake(function () {

View File

@@ -33,6 +33,11 @@ describe("runtime-api/diagnostics", function() {
flowFile: "flows.json",
mqttReconnectTime: 321,
serialReconnectTime: 432,
socketReconnectTime: 2222,
socketTimeout: 3333,
tcpMsgQueueSize: 4444,
inboundWebSocketTimeout: 5555,
runtimeState: {enabled: true, ui: false},
adminAuth: {},//should be sanitised to "SET"
httpAdminRoot: "/admin/root/",
httpAdminCors: {},//should be sanitised to "SET"
@@ -45,6 +50,7 @@ describe("runtime-api/diagnostics", function() {
uiHost: "something.secret.com",//should be sanitised to "SET"
uiPort: 1337,//should be sanitised to "SET"
userDir: "/var/super/secret/",//should be sanitised to "SET",
nodesDir: "/var/super/secret/",//should be sanitised to "SET",
contextStorage: {
default : { module: "memory" },
file: { module: "localfilesystem" },
@@ -73,8 +79,9 @@ describe("runtime-api/diagnostics", function() {
//result.runtime.xxxxx
const runtimeCount = Object.keys(result.runtime).length;
runtimeCount.should.eql(4);//ensure no more than 4 keys are present in runtime
runtimeCount.should.eql(5);//ensure 5 keys are present in runtime
result.runtime.should.have.property('isStarted',true)
result.runtime.should.have.property('flows')
result.runtime.should.have.property('modules').type("object");
result.runtime.should.have.property('settings').type("object");
result.runtime.should.have.property('version','7.7.7');
@@ -87,7 +94,7 @@ describe("runtime-api/diagnostics", function() {
//result.runtime.settings.xxxxx
const settingsCount = Object.keys(result.runtime.settings).length;
settingsCount.should.eql(21);//ensure no more than the 21 settings listed below are present in the settings object
settingsCount.should.eql(27);//ensure no more than the 21 settings listed below are present in the settings object
result.runtime.settings.should.have.property('available',true);
result.runtime.settings.should.have.property('apiMaxLength', "UNSET");//deliberately disabled to ensure UNSET is returned
result.runtime.settings.should.have.property('debugMaxLength', 1111);
@@ -96,6 +103,11 @@ describe("runtime-api/diagnostics", function() {
result.runtime.settings.should.have.property('flowFile', "flows.json");
result.runtime.settings.should.have.property('mqttReconnectTime', 321);
result.runtime.settings.should.have.property('serialReconnectTime', 432);
result.runtime.settings.should.have.property('socketReconnectTime', 2222);
result.runtime.settings.should.have.property('socketTimeout', 3333);
result.runtime.settings.should.have.property('tcpMsgQueueSize', 4444);
result.runtime.settings.should.have.property('inboundWebSocketTimeout', 5555);
result.runtime.settings.should.have.property('runtimeState', {enabled: true, ui: false});
result.runtime.settings.should.have.property("adminAuth", "SET"); //should be sanitised to "SET"
result.runtime.settings.should.have.property("httpAdminCors", "SET"); //should be sanitised to "SET"
result.runtime.settings.should.have.property('httpAdminRoot', "/admin/root/");
@@ -109,6 +121,7 @@ describe("runtime-api/diagnostics", function() {
result.runtime.settings.should.have.property("uiPort", "SET"); //should be sanitised to "SET"
result.runtime.settings.should.have.property("userDir", "SET"); //should be sanitised to "SET"
result.runtime.settings.should.have.property('contextStorage').type("object");
result.runtime.settings.should.have.property('nodesDir', "SET")
//result.runtime.settings.contextStorage.xxxxx
const contextCount = Object.keys(result.runtime.settings.contextStorage).length;