Compare commits

...

198 Commits

Author SHA1 Message Date
Nick O'Leary
df19e54555 Fix lint issue 2023-02-02 14:36:04 +00:00
Nick O'Leary
6d717a21cf Add 310 tour 2023-02-02 13:34:01 +00:00
Nick O'Leary
fc251d005e Merge pull request #4039 from node-red/tab-context-menu
Locking Flows
2023-02-02 11:35:54 +00:00
Nick O'Leary
4624e28675 Merge branch 'dev' into tab-context-menu 2023-02-02 11:33:06 +00:00
Nick O'Leary
3a1cc38aaf Update for 3.1.0-beta.1 2023-02-02 11:09:55 +00:00
Nick O'Leary
68bb38b8d7 Merge branch 'master' into dev 2023-02-02 10:40:33 +00:00
Nick O'Leary
2ca3b3e99d Merge pull request #4007 from node-red-hitachi/add-markdown-mermaid-diagram
Add support for mermaid diagram to markdown editor
2023-02-02 10:35:32 +00:00
Nick O'Leary
67c8354f76 Merge branch 'pr_4006' into dev 2023-02-02 10:29:39 +00:00
Nick O'Leary
384377782a Remove package-lock from git history 2023-02-02 10:25:57 +00:00
Nick O'Leary
8382665bbb Merge pull request #3999 from node-red/fix-plugin-async
Fix async loading of modules containing both nodes and plugins
2023-02-02 10:23:42 +00:00
Nick O'Leary
e799cfc16a Merge pull request #4004 from dirkjanfaber/patch-1
Comment node: Clarify where the text will appear
2023-02-02 10:23:22 +00:00
Nick O'Leary
055d0081e1 Merge pull request #4021 from node-red/inject-async-context
Allow Inject node to work with async context stores
2023-02-02 10:22:59 +00:00
Nick O'Leary
9035de32c8 Merge pull request #4023 from node-red/trigger-hide-nul-option
Hide trigger node repeat send  option if sending nothing
2023-02-02 10:22:40 +00:00
Nick O'Leary
af62a520d3 Merge pull request #4028 from node-red/Add-count-to-join-and-batch-node-labels
Add count to join and batch node labels
2023-02-02 10:21:57 +00:00
Nick O'Leary
1824108d09 Merge pull request #4035 from xiaobinqt/dev
fix .red-ui-notification class
2023-02-02 10:20:54 +00:00
Nick O'Leary
149e8ce9b0 Merge pull request #4036 from kazuhitoyokoi/master-usemain
Use main branch as default in project feature
2023-02-02 10:20:24 +00:00
Nick O'Leary
f4661eec75 Merge pull request #4038 from bonanitech/function-node-setup-tab
Fix border radius on Modules list header
2023-02-02 10:19:54 +00:00
Mauricio Bonani
0f7a1a42e4 Fix border radius on Modules list header 2023-02-01 17:50:05 -05:00
Kazuhito Yokoi
5bda221f9d Use main branch as default in project feature 2023-01-31 00:36:18 +09:00
weibin
fd42becbdc fix .red-ui-notification
if flows stopped due to missing too much node types manage-project-dep button display none.
2023-01-30 23:02:42 +08:00
Nick O'Leary
2759c1616c Merge branch 'dev' into pr_4031 2023-01-30 09:52:31 +00:00
Nick O'Leary
55ac98c989 Merge pull request #4033 from node-red-hitachi/fix-hide-subflow-tooltip
fix hide subflow tooltip
2023-01-30 09:48:20 +00:00
Nick O'Leary
c42c6a7b08 Merge pull request #4030 from node-red-hitachi/disable-delete-tab-menu-when-single-tab-exists
Disable delete tab menu when single tab exists
2023-01-30 09:38:16 +00:00
Nick O'Leary
b99bd38649 Merge pull request #4029 from node-red-hitachi/fix-tab-menu-error
fix workspace reference error in case of empty tabs
2023-01-30 09:34:05 +00:00
Hiroyasu Nishiyama
013ee2f1f4 fix hide subflow tooltip 2023-01-30 16:24:52 +09:00
Hiroyasu Nishiyama
7b79d79f84 remove useless console output 2023-01-30 14:09:01 +09:00
Hiroyasu Nishiyama
66f9686e48 disable hide all menu if all tabs hidden 2023-01-30 11:42:53 +09:00
Hiroyasu Nishiyama
9b1b7437b3 disable delete tab menu when single tab exists 2023-01-30 10:59:34 +09:00
Hiroyasu Nishiyama
720d44d53e fix workspace reference error in case of empty tabs 2023-01-30 10:30:06 +09:00
Nick O'Leary
7dca148349 Merge pull request #4027 from kazuhitoyokoi/master-fixmenu4project
Fix disabled menu items in project feature
2023-01-27 10:29:10 +00:00
Dave Conway-Jones
47bacaf58a Add count to join and batch node labels 2023-01-26 22:13:17 +00:00
Kazuhito Yokoi
ffff8aeb91 Fix disabled menu in project feature 2023-01-26 02:11:34 +09:00
Dave Conway-Jones
9a856f50d7 Hide repeat send option if sending nothing
to address https://discourse.nodered.org/t/trigger-node-how-to-delay-and-repeat-message/74117/5
2023-01-25 10:59:04 +00:00
Hiroyasu Nishiyama
e7540de85d remove useless variable 2023-01-25 16:40:12 +09:00
Hiroyasu Nishiyama
ba9ddefbee removed endpoint 2023-01-25 16:06:37 +09:00
Hiroyasu Nishiyama
f1801f9662 fix to prevent uploging unexpected file type 2023-01-25 13:38:12 +09:00
Nick O'Leary
ae92ea9476 Merge pull request #4020 from node-red/rename-package-var
Rename package var to avoid strict mode error
2023-01-23 20:44:29 +00:00
Nick O'Leary
c7017ee84b Allow Inject node to work with async context stores
Fixes #4014
2023-01-23 20:42:25 +00:00
Nick O'Leary
0346294c59 Rename package var 2023-01-23 17:50:50 +00:00
Nick O'Leary
8d240ca797 Rename package var to avoid strict more error
Fixes #4017
2023-01-23 17:44:03 +00:00
Nick O'Leary
a607ee90e0 Merge pull request #4009 from node-red/TCP-node-replaceall-fix
TCP Node: ensure newline substitution applies to whole message
2023-01-23 17:23:28 +00:00
Nick O'Leary
7dbbafec1b Merge pull request #4000 from node-red/fix-split-stream
Split node: avoid duplicate done call for buffer split
2023-01-23 17:04:31 +00:00
Nick O'Leary
428132ea3b Merge pull request #3997 from kazuhitoyokoi/dev-jpn
Add Japanese translation for v3.1.0-beta.0
2023-01-23 17:04:16 +00:00
Nick O'Leary
c49330f9d1 Merge pull request #4012 from kazuhitoyokoi/master-addjpn
Add Japanese translations for v3.0.3
2023-01-23 16:58:34 +00:00
Nick O'Leary
937c5fe893 Merge pull request #4019 from node-red/force-ipv4-lookup-over-ipv6
if possible - force ipv4 name resolution to have priority
2023-01-23 16:58:21 +00:00
Dave Conway-Jones
d2c9f12c3a if possible - force ipv4 name resolution to have priority
to fix Issue #4010
and others (eg) email node server connect fails, and some reported on SO
2023-01-23 13:02:58 +00:00
Robin Schneider
10324d8260 Fix typos in settings.js (#4013)
* chore: Remove trailing whitespace in settings.js

* chore: Fix typos in settings.js

* chore: Use consistent terminology in settings.js
2023-01-19 09:28:46 +00:00
Kazuhito Yokoi
8f27dae7ea Add Japanese translations for v3.0.3 2023-01-16 00:56:39 +09:00
Dave Conway-Jones
94ae511a6d fix tcp to replace all in newline substitution
to close #3989
2023-01-09 09:26:24 +00:00
Hiroyasu Nishiyama
038f75e48f add support for mermaid diagram to markdown editor 2023-01-05 17:25:16 +09:00
Hiroyasu Nishiyama
b9fe4c5cd3 merge upstream/dev 2023-01-05 10:29:45 +09:00
Hiroyasu Nishiyama
7e8b7602b4 add support for inline image drag and drop to markdown editor 2023-01-05 10:28:48 +09:00
Dirk-Jan Faber
7c306a8430 Comment node: Clarify where the text will appear
The text will appear in the information tab of the side panel and not in the help tab of the side panel.
2023-01-03 13:41:31 +01:00
Nick O'Leary
dd2bc44c2d Merge branch 'dev' into dev-jpn 2023-01-01 22:38:20 +00:00
Nick O'Leary
74794fea09 Split node: avoid duplicate done call for buffer split
Fixes #3982
2023-01-01 22:21:49 +00:00
Nick O'Leary
1efd1a52a7 Ensure modules containing plugins and nodes are loaded properly
Fixes #3523
2023-01-01 19:36:49 +00:00
Nick O'Leary
928131cf08 Merge pull request #3941 from node-red-hitachi/global-env-var
add global environment variable feature
2023-01-01 14:10:15 +00:00
Nick O'Leary
4d202a7a37 Merge pull request #3971 from node-red/fix-cred-on-global
Ensure credentials object is removed before returning node in getFlow request
2023-01-01 14:09:54 +00:00
Nick O'Leary
e0d71abdc6 Merge pull request #3992 from node-red/fix-mqtt-reconnect
Fix mqtt nodes not reconnecting on modified-flows deploy
2023-01-01 14:09:33 +00:00
Nick O'Leary
550eb6ee2f Merge pull request #3995 from bonanitech/radialMenu
Let themes change radialMenu text colors
2023-01-01 14:06:00 +00:00
Kazuhito Yokoi
a661bc1d23 Add Japanese translation for v3.1.0-beta.0 2022-12-31 00:41:35 +09:00
Mauricio Bonani
f737162697 Let themes change radialMenu text colors 2022-12-29 09:47:05 -05:00
Nick O'Leary
ce57ba80eb Fix mqtt nodes not reconnected on modified-flows deploy 2022-12-27 14:56:32 +00:00
Hiroyasu Nishiyama
99bd957ea0 Resolve merge conflict 2022-12-27 23:45:25 +09:00
Nick O'Leary
270eb56718 Merge pull request #3916 from kazuhitoyokoi/dev
Add Japanese translation for v3.1.0-beta.0
2022-12-27 14:16:02 +00:00
Nick O'Leary
b3ce0c0079 Merge pull request #3987 from kazuhitoyokoi/master-fixproject
Ignore commit error in project feature
2022-12-27 14:15:47 +00:00
Nick O'Leary
e6cee58e0d Merge pull request #3974 from Steve-Mcl/remember-export-format
Remember compact/pretty flow export user choice
2022-12-27 14:09:47 +00:00
Nick O'Leary
4adc6b269c Merge pull request #3980 from kazuhitoyokoi/master-fixpalette
Hide subflow category after deleting subflow
2022-12-27 13:47:58 +00:00
Nick O'Leary
920b0178ec Merge pull request #3981 from kazuhitoyokoi/master-fixtypo
Fix typo in 25-status.html
2022-12-27 13:43:35 +00:00
Nick O'Leary
3583b40e02 Merge pull request #3990 from node-red/csv-change-to-replaceAll
Csv change replace to replaceAll
2022-12-27 13:43:12 +00:00
Nick O'Leary
7870830367 Merge pull request #3991 from hardillb/http-request-form-array
Support form-data arrays
2022-12-27 13:42:33 +00:00
Ben Hardill
4c1d7ad2d2 Merge branch 'master' into http-request-form-array 2022-12-24 20:37:33 +00:00
Ben Hardill
661b07c856 Add tests 2022-12-24 20:35:51 +00:00
Ben Hardill
5670bd8265 Support form-data arrays 2022-12-24 19:32:33 +00:00
Dave Conway-Jones
93a1911232 CSV - Add note about msg.reset to info page
to close #3976
2022-12-19 21:26:20 +00:00
Dave Conway-Jones
2429191838 CSV - swap to regex replace for node14 support 2022-12-19 13:48:21 +00:00
Dave Conway-Jones
f6901cd19f CSV node replace replace with replaceAll just in case
mentioned in Issue #3989
2022-12-19 09:50:29 +00:00
Kazuhito Yokoi
156c3984a7 Ignore commit error in project feature 2022-12-12 01:23:00 +09:00
Kazuhito Yokoi
f91af2153a Fix typo in 25-status.html 2022-12-10 00:33:40 +09:00
Kazuhito Yokoi
805f8a5ee7 Hide subflow category after deleting subflow 2022-12-08 23:43:47 +09:00
Hiroyasu Nishiyama
2ab8121a4a add description to global-config settings 2022-12-06 21:12:52 +09:00
Hiroyasu Nishiyama
601a4ec70d Add hasUsers to global-config 2022-12-06 10:33:10 +09:00
Hiroyasu Nishiyama
707b831c30 Update packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 10:25:38 +09:00
Hiroyasu Nishiyama
72ae375e44 Update packages/node_modules/@node-red/nodes/core/common/91-global-config.html
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 10:25:25 +09:00
Hiroyasu Nishiyama
3c1ddb5c9d Update packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 09:32:04 +09:00
Hiroyasu Nishiyama
817db23146 Update packages/node_modules/@node-red/nodes/locales/en-US/messages.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 09:29:51 +09:00
Hiroyasu Nishiyama
a8c820f558 Update packages/node_modules/@node-red/nodes/locales/ja/messages.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 09:29:45 +09:00
Hiroyasu Nishiyama
6d09c81f11 Update packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 09:27:17 +09:00
Hiroyasu Nishiyama
192e537e5d Update packages/node_modules/@node-red/editor-client/locales/ja/editor.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-06 09:27:02 +09:00
Steve-Mcl
7b52ef34be Remember compact/pretty flow export user choice
closes #3849
2022-12-05 22:17:05 +00:00
Kazuhito Yokoi
7117472e73 Add Japanese translation for range node 2022-12-05 23:13:50 +09:00
Kazuhito Yokoi
c24b123917 Add Japanese translation for editor actions 2022-12-05 23:11:56 +09:00
Hiroyasu Nishiyama
9eb8cf121c Update Japanese message reflecting English message update 2022-12-05 11:29:37 +09:00
Hiroyasu Nishiyama
41ef9ae010 Update test/nodes/core/common/91-global-config_spec.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:17:29 +09:00
Hiroyasu Nishiyama
1674bbbde9 Update packages/node_modules/@node-red/nodes/locales/ja/messages.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:17:20 +09:00
Hiroyasu Nishiyama
0fb739f7cd Update packages/node_modules/@node-red/nodes/locales/ja/common/91-global-config.html
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:17:04 +09:00
Hiroyasu Nishiyama
169fa940e4 Update packages/node_modules/@node-red/nodes/locales/en-US/messages.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:16:53 +09:00
Hiroyasu Nishiyama
c9664cc425 Update packages/node_modules/@node-red/nodes/locales/en-US/common/91-global-config.html
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:16:35 +09:00
Hiroyasu Nishiyama
e61cdff655 Update packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:15:43 +09:00
Hiroyasu Nishiyama
a479b8a5d7 Update packages/node_modules/@node-red/nodes/core/common/91-global-config.html
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-12-05 11:15:32 +09:00
Kazuhito Yokoi
26462e684b Merge branch 'node-red:dev' into dev 2022-12-05 01:08:45 +09:00
Nick O'Leary
113d42ef35 Merge pull request #3970 from node-red/prevent-text-selection
Prevent dbl-click opening node edit dialog with text selected
2022-12-03 23:34:57 +00:00
Nick O'Leary
c18018f017 Ensure credentials object is removed before returning node in getFlow request
Fixes #3953
2022-12-03 23:33:33 +00:00
Nick O'Leary
e804addf0a Prevent dbl-click opening node edit dialog with text selected
Fixes #3958
2022-12-03 23:13:44 +00:00
Nick O'Leary
04cea003b9 Merge pull request #3938 from node-red/locking-flows
Locking flows
2022-12-03 23:01:58 +00:00
Nick O'Leary
65fcc56a56 Merge pull request #3968 from node-red/context-menu-updates
Context menu updates
2022-12-03 23:01:37 +00:00
Nick O'Leary
c065d253e9 Merge pull request #3969 from node-red/bump-deps
Update dependencies
2022-12-03 23:01:10 +00:00
Nick O'Leary
4bb2b91ee6 Merge pull request #3966 from Steve-Mcl/fix-mqtt-single-subscription
fix single subscription mqtt node status
2022-12-03 22:47:42 +00:00
Nick O'Leary
b3f761776d Update dependencies 2022-12-03 22:43:03 +00:00
Nick O'Leary
dce1cccbde Allow subflow to be edited if instance exists on locked flow 2022-12-03 22:30:35 +00:00
Nick O'Leary
3630056ed8 Fix RED.nodes.clear() when handling locked flows 2022-12-03 21:44:33 +00:00
Nick O'Leary
2d6e1d7089 NLS updates for context menu 2022-12-03 21:29:27 +00:00
Nick O'Leary
71db79ba53 More context menu options 2022-12-03 21:16:57 +00:00
Steve-Mcl
5bb66ed7d4 fix single subscription mqtt node status 2022-12-01 13:08:48 +00:00
Nick O'Leary
14e74afb07 Merge pull request #3909 from node-red/warn-invalid-msg
Add check that node sends object rather than primitive type
2022-11-30 22:28:09 +00:00
Nick O'Leary
c4e216f839 Merge pull request #3912 from node-red/handle_username_spaces
Ensure key_path is quoted in GIT_SSH_COMMAND in case of spaces in pathname
2022-11-30 22:18:24 +00:00
Nick O'Leary
752fdfedf2 Merge pull request #3935 from node-red/Add-drop-mode-to-range-node
Add drop mode to range node
2022-11-30 22:17:02 +00:00
Nick O'Leary
2a49e7c8ef Merge pull request #3908 from node-red/add-httpheaders
Ensure msg.req.headers is enumerable
2022-11-30 22:15:23 +00:00
Nick O'Leary
02af01d2ca Merge pull request #3867 from Steve-Mcl/improve-nodesdir-scan
Fix nodesDir scan when node package has js/html in sub dir to package.json
2022-11-30 22:15:00 +00:00
Nick O'Leary
07c05c1f2a Merge pull request #3930 from node-red/tab-context-menu
Improve UX around hiding flows via context menu
2022-11-30 22:13:54 +00:00
Nick O'Leary
ee4af4c7bf Merge pull request #3920 from node-red/CSV-header-props-with-quotes
CSV node check header properties for ' and "
2022-11-30 22:10:40 +00:00
Nick O'Leary
3d565e74a5 Merge pull request #3917 from kazuhitoyokoi/master-fixpermission
Fix file permissions
2022-11-30 22:10:03 +00:00
Nick O'Leary
3cb84222f8 Merge pull request #3921 from node-red/fix-group-unknown
Handle replacing unknown node inside group or subflow
2022-11-30 22:09:35 +00:00
Nick O'Leary
1b013bb73b Merge pull request #3949 from Steveorevo/master
Fix #3939, red border red-ui-typedInput-container
2022-11-30 22:07:04 +00:00
Nick O'Leary
fd54e625d5 Merge pull request #3965 from we11adam/master
fix: fix typo in catch.html
2022-11-30 21:40:34 +00:00
Adam Lau
77f6412d3b fix: fix typo in catch.html 2022-11-30 17:51:13 +08:00
Stephen J. Carnam
c81cd5450f Support for PHP syntax highlight 2022-11-09 16:45:32 -08:00
Steveorevo
0b663abe50 Fix #3939, red border red-ui-typedInput-container 2022-11-09 10:33:05 -08:00
Nick O'Leary
3b27fb2aa7 Merge branch 'dev' into dev 2022-11-07 23:16:14 +00:00
Nick O'Leary
6bd67ae68c Merge pull request #3944 from node-red-hitachi/fix-deploy-locked-flow
fix deployment of locked flow
2022-11-07 23:13:03 +00:00
Nick O'Leary
14c362d4ba Merge pull request #3942 from node-red-hitachi/fix-watch-test
fix watch node test on MacOS/ARM
2022-11-07 21:12:55 +00:00
Nick O'Leary
f28bc1bff7 Remove jshint warning 2022-11-07 21:11:58 +00:00
Nick O'Leary
de8a5ea262 Merge pull request #3945 from node-red-hitachi/fix-jshint-es-version
fix to allow es11 for jshint check
2022-11-07 21:10:26 +00:00
Nick O'Leary
339013434b Merge pull request #3946 from node-red-hitachi/i18n-item-url-copy-notification
i18n item URL copy notification & add Japanese message
2022-11-07 21:07:57 +00:00
Nick O'Leary
8a3ad331d2 Merge pull request #3947 from node-red-hitachi/add-item-url-Japanese-action-message
add Japanese message for item url copy actions
2022-11-07 21:07:38 +00:00
Hiroyasu Nishiyama
e3892dc26d add Japanese message for item url copy actions 2022-11-07 16:07:46 +09:00
Hiroyasu Nishiyama
b95df6d883 i18n item URL copy notification & add Japanese message 2022-11-07 15:47:19 +09:00
Hiroyasu Nishiyama
11ad03b21e fix to allow es11 for jshint check 2022-11-07 10:42:07 +09:00
Hiroyasu Nishiyama
9cb474ea9c fix deployment of locked flow 2022-11-07 09:40:36 +09:00
Hiroyasu Nishiyama
fce43b4e1d fix condition for platform check 2022-11-05 14:50:14 +09:00
Hiroyasu Nishiyama
1d547500e8 fix watch node test on MacOS/ARM 2022-11-05 14:30:32 +09:00
Hiroyasu Nishiyama
f23d0480e4 add global environment variable feature 2022-11-04 18:42:51 +09:00
Nick O'Leary
fe9c630572 Prevent deleting subflow if instance on locked tab 2022-11-01 11:42:40 +00:00
Nick O'Leary
ce94226c3c Disable subflow/flow menu options if active is locked 2022-11-01 11:29:23 +00:00
Nick O'Leary
f12d36b5ed Locking flows fixes and context menu options 2022-11-01 10:48:48 +00:00
Nick O'Leary
3cb5259494 Initial locking flows UX 2022-11-01 10:37:18 +00:00
Nick O'Leary
a351cd9d9f Add move-to-start/end and better subflow menu options 2022-11-01 10:35:57 +00:00
Nick O'Leary
d8e01584f3 Remove add-flow-to-right option if clicked in tab bar 2022-10-31 20:20:05 +00:00
Kazuhito Yokoi
dd76840568 Fix uncleared translations in change node 2022-11-01 01:09:06 +09:00
Dave Conway-Jones
94690fad7a Merge branch 'CSV-header-props-with-quotes' of https://github.com/node-red/node-red into CSV-header-props-with-quotes 2022-10-29 17:36:17 +01:00
Dave Conway-Jones
d693af9615 CSV node check header properties for ' and "
and add test
to close #3919
2022-10-29 17:35:45 +01:00
Dave Conway-Jones
4cc18c25fe Add drop mode to range node
and include tests
2022-10-29 17:34:29 +01:00
Kazuhito Yokoi
8b398f49c0 Merge branch 'node-red:master' into master-fixpermission 2022-10-29 23:51:05 +09:00
Nick O'Leary
902ce68164 Merge branch 'master' into fix-group-unknown 2022-10-26 00:52:34 +01:00
Nick O'Leary
cd0474ce7b Update packages/node_modules/@node-red/editor-client/src/js/nodes.js
Co-authored-by: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com>
2022-10-26 00:51:41 +01:00
Nick O'Leary
946def022f Merge pull request #3922 from node-red/fix-httpreq-tests
Fix httprequest tests to be more lenient on error message
2022-10-26 00:40:47 +01:00
Nick O'Leary
fb499be979 Add context menu to tab bar 2022-10-25 23:44:59 +01:00
Nick O'Leary
c62a101635 Fix httprequest tests to be more lenient on error message 2022-10-16 23:10:57 +01:00
Nick O'Leary
69a575097d Remove debug 2022-10-16 22:47:34 +01:00
Nick O'Leary
b40551a8fa Handle replacing unknown node inside group or subflow 2022-10-16 22:38:11 +01:00
Dave Conway-Jones
5b27bcd781 CSV node check header properties for ' and "
and add test
to close #3919
2022-10-16 18:05:21 +01:00
Kazuhito Yokoi
75725a38df Fix file permission 2022-10-12 23:50:33 +09:00
Kazuhito Yokoi
c4e277853c Add Japanese translation for button of node URL 2022-10-12 23:24:21 +09:00
Nick O'Leary
24b055b1b8 Ensure key_path is quoted in GIT_SSH_COMMAND in case of spaces in pathname 2022-10-04 15:44:29 +01:00
Nick O'Leary
7da3773f7f Merge pull request #3898 from node-red/delay-flush-reset
let delay node handle both flush then reset
2022-10-04 15:39:05 +01:00
Nick O'Leary
32999ffa84 Merge pull request #3906 from node-red/Fix-for-csv-undefined-property
Fix for CSV undefined property
2022-10-04 15:38:37 +01:00
Nick O'Leary
f06c53f1f1 Merge pull request #3905 from node-red/mqtt-followups
Fix birth topic handling in MQTT node
2022-10-04 15:36:49 +01:00
Nick O'Leary
a9eec28360 Merge pull request #3884 from node-red/fix-auto-complete
Fix autocomplete entry for responseUrl
2022-10-04 15:35:10 +01:00
Nick O'Leary
5cda972872 Merge pull request #3890 from kazuhitoyokoi/master-fixmqttproperty
Fix pull-down menus of MQTT configuration node
2022-10-04 15:34:50 +01:00
Nick O'Leary
087946876b Merge pull request #3907 from boahc077/github_actions_token_permission
ci: add minimum GitHub token permissions for workflows
2022-10-04 15:32:47 +01:00
Nick O'Leary
318f0f1b7e Merge pull request #3899 from node-red/fix-change-self-overwrite
Fix change node overwriting msg with itself
2022-10-04 15:29:23 +01:00
Stephen McLaughlin
6d1a12af4b remove debug/test code 2022-10-04 13:36:23 +01:00
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
7c79ca7878 Ensure msg.req.headers is enumerable
Fixes #3878
2022-10-04 11:28:26 +01:00
Ashish Kurmi
87e7f3a61c ci: add minimum GitHub token permissions for workflows
Signed-off-by: Ashish Kurmi <akurmi@stepsecurity.io>
2022-10-02 11:16:13 -07:00
Dave Conway-Jones
e724f216bf Fix for CSV undefined property
to close #3900 main issue
and add tests
(other fix is commented out but no tests)
2022-09-30 13:48:48 +01:00
Steve-Mcl
e6b379358a better logging of set with no types 2022-09-29 21:28:13 +01:00
Steve-Mcl
b0abba15a6 remove dud code instead of commenting 2022-09-29 19:08:46 +01:00
Steve-Mcl
81b4874a7c fix new test and fix bug found in previous PR 2022-09-29 19:05:53 +01:00
Steve-Mcl
f11b9c1e18 add test bad birth topic
part of #3865
2022-09-29 13:12:15 +01:00
Steve-Mcl
e15ecc00ce remove old unused code (5y+ not used) 2022-09-29 13:11:25 +01:00
Dave Conway-Jones
3e4c45ac6a Fix change node overwriting msg with itself
and add test
to close #3891
2022-09-22 20:22:11 +01:00
Dave Conway-Jones
fc657ecc71 let delay node handle both flush then reset
and add tests
2022-09-22 10:51:48 +01:00
Kazuhito Yokoi
f872e2ab80 Add icon to typedInput in MQTT node 2022-09-18 19:11:33 +09:00
Kazuhito Yokoi
a81b1aa0cb Support i18n in MQTT node property 2022-09-18 17:10:19 +09:00
Kazuhito Yokoi
efc0f1ab91 Fix default values for MQTT retain settings 2022-09-18 16:24:25 +09:00
Nick O'Leary
313bab37e2 Merge pull request #3870 from node-red/uri-fragments
Support uri fragments for nodes and groups including edit support
2022-09-15 21:25:50 +01:00
Nick O'Leary
9fd4989142 Fix autocomplete entry for responseUrl
Fixes #3883
2022-09-15 21:22:55 +01:00
Nick O'Leary
0caa308757 Add core:copy-item-link action and expose in info sidebar 2022-09-12 20:53:46 +01:00
Nick O'Leary
1fa8f30550 Support uri fragments for nodes and groups including edit support 2022-09-05 21:08:36 +01:00
Steve-Mcl
6a19d8246c add test for specific arrangement of node package 2022-09-03 21:37:27 +01:00
Steve-Mcl
d6bb3a558f fix loading node package in nodesDir on linux
fixes #3861
2022-09-03 21:23:38 +01:00
Nick O'Leary
44300dbb34 Merge pull request #3807 from node-red-hitachi/env-var-jsonata
Env var jsonata
2022-09-02 20:47:30 +01:00
Hiroyasu Nishiyama
1ddbeaa50f add test cases 2022-07-27 20:25:43 +09:00
Hiroyasu Nishiyama
93a88a83a8 add JSONata support for env var definition 2022-07-20 10:13:13 +09:00
Nick O'Leary
30ea300f65 Merge pull request #3769 from node-red/310
Bump dev to 3.1.0-beta.0
2022-07-14 21:16:38 +01:00
Nick O'Leary
04f4d5274d Bump dev to 3.1.0-beta.0 2022-07-14 20:58:25 +01:00
Nick O'Leary
1f9695abd7 Merge pull request #3768 from node-red/master
Get `dev` branch up to date with `master`
2022-07-14 20:56:42 +01:00
177 changed files with 3027 additions and 904 deletions

View File

@@ -5,6 +5,9 @@ on:
release:
types: [published]
permissions:
contents: read
jobs:
generate:
name: 'Update node-red-docker image'

View File

@@ -6,8 +6,14 @@ on:
pull_request:
branches: [ master, dev ]
permissions:
contents: read
jobs:
build:
permissions:
checks: write # for coverallsapp/github-action to create new checks
contents: read # for actions/checkout to fetch code
runs-on: ubuntu-latest
strategy:
matrix:

View File

@@ -15,5 +15,5 @@
"shadow": true, // allow variable shadowing (re-use of names...)
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
"proto": true, // allow setting of __proto__ in node < v0.12,
"esversion": 6 // allow es6
"esversion": 11 // allow es11(ES2020)
}

View File

@@ -1,3 +1,94 @@
#### 3.1.0-beta.1: Beta Release
Editor
- NEW: Locking Flows (#3938) @knolleary
- NEW: Improve UX around hiding flows via context menu (#3930) @knolleary
- NEW: Add support for inline image in markdown editor by drag and drop of an image file (#4006) @HiroyasuNishiyama
- NEW: Add support for mermaid diagram to markdown editor (#4007) @HiroyasuNishiyama
- NEW: Support uri fragments for nodes and groups including edit support (#3870) @knolleary
- NEW: Add global environment variable feature (#3941) @HiroyasuNishiyama
- Remember compact/pretty flow export user choice (#3974) @Steve-Mcl
- fix .red-ui-notification class (#4035) @xiaobinqt
- Fix border radius on Modules list header (#4038) @bonanitech
- fix workspace reference error in case of empty tabs (#4029) @HiroyasuNishiyama
- Disable delete tab menu when single tab exists (#4030) @HiroyasuNishiyama
- Disable hide all menu if all tabs hidden (#4031) @HiroyasuNishiyama
- fix hide subflow tooltip (#4033) @HiroyasuNishiyama
- Fix disabled menu items in project feature (#4027) @kazuhitoyokoi
- Let themes change radialMenu text colors (#3995) @bonanitech
- Add Japanese translations for v3.0.3 (#4012) @kazuhitoyokoi
- Add Japanese translation for v3.1.0-beta.0 (#3997) @kazuhitoyokoi
- Add Japanese translation for v3.1.0-beta.0 (#3916) @kazuhitoyokoi
- Hide subflow category after deleting subflow (#3980) @kazuhitoyokoi
- Prevent dbl-click opening node edit dialog with text selected (#3970) @knolleary
- Handle replacing unknown node inside group or subflow (#3921) @knolleary
- Fix #3939, red border red-ui-typedInput-container (#3949) @Steveorevo
- i18n item URL copy notification & add Japanese message (#3946) @HiroyasuNishiyama
- add Japanese message for item url copy actions (#3947) @HiroyasuNishiyama
- Fix autocomplete entry for responseUrl (#3884) @knolleary
- Fix Japanese translation for JSONata editor (#3872) @HiroyasuNishiyama
- Fix search type with spaces (#3841) @Steve-Mcl
- Fix error hanndling of JSONata expression editor for extended functions (#3871) @HiroyasuNishiyama
- Add button type to the adding SSH key button (#3866) @kazuhitoyokoi
- Check radio button as default in project dialog (#3879) @kazuhitoyokoi
- Add $clone as supported function (#3874) @HiroyasuNishiyama
- Env var jsonata (#3807) @HiroyasuNishiyama
- Add Japanese translation for v3.0.2 (#3852) @kazuhitoyokoi
Runtime
- Force IPv4 name resolution to have priority (#4019) @dceejay
- Fix async loading of modules containing both nodes and plugins (#3999) @knolleary
- Use main branch as default in project feature (#4036) @kazuhitoyokoi
- Rename package var to avoid strict mode error (#4020) @knolleary
- Fix typos in settings.js (#4013) @ypid
- Ensure credentials object is removed before returning node in getFlow request (#3971) @knolleary
- Ignore commit error in project feature (#3987) @kazuhitoyokoi
- Update dependencies (#3969) @knolleary
- Add check that node sends object rather than primitive type (#3909) @knolleary
- Ensure key_path is quoted in GIT_SSH_COMMAND in case of spaces in pathname (#3912) @knolleary
- Fix nodesDir scan when node package has js/html in sub dir to package.json (#3867) @Steve-Mcl
- Fix file permissions (#3917) @kazuhitoyokoi
- ci: add minimum GitHub token permissions for workflows (#3907) @boahc077
Nodes
- Catch: fix typo in catch.html (#3965) @we11adam
- Change: Fix change node overwriting msg with itself (#3899) @dceejay
- Comment node: Clarify where the text will appear (#4004) @dirkjanfaber
- CSV: change replace to replaceAll (#3990) @dceejay
- CSV node: check header properties for ' and " (#3920) @dceejay
- CSV: Fix for CSV undefined property (#3906) @dceejay
- Delay: let delay node handle both flush then reset (#3898) @dceejay
- Function: Limit number of ports in function node (#3886) @kazuhitoyokoi
- Function: Remove dot from variable name for external module in function node (#3880) @kazuhitoyokoi
- Function: add function node monaco types util and promisify (#3868) @Steve-Mcl
- HTTP In: Ensure msg.req.headers is enumerable (#3908) @knolleary
- HTTP Request: Support form-data arrays (#3991) @hardillb
- HTTP Request: Fix httprequest tests to be more lenient on error message (#3922) @knolleary
- HTTP Request: Add missing property to node object HTTPRequest (#3842) @hardillb
- HTTP Request/Response: Support sortable list on property UI of http request and http response nodes (#3857) @kazuhitoyokoi
- HTTP Response: Ensure statusCode is a number (#3894) @hardillb
- Inject: Allow Inject node to work with async context stores (#4021) @knolleary
- Join/Batch: Add count to join and batch node labels (#4028) @dceejay
- MQTT: Fix birth topic handling in MQTT node (#3905) @Steve-Mcl
- MQTT: Fix pull-down menus of MQTT configuration node (#3890) @kazuhitoyokoi
- MQTT: Prevent invalid mqtt birth topic crashing node-red (#3869) @Steve-Mcl
- MQTT: ensure sessionExpiry(Interval) is applied (#3840) @Steve-Mcl
- MQTT: Fix mqtt nodes not reconnecting on modified-flows deploy (#3992) @knolleary
- MQTT: fix single subscription mqtt node status (#3966) @Steve-Mcl
- Range: Add drop mode to range node (#3935) @dceejay
- Remove done from describe (#3873) @HiroyasuNishiyama
- Split node: avoid duplicate done call for buffer split (#4000) @knolleary
- Status: Fix typo in 25-status.html (#3981) @kazuhitoyokoi
- TCP Node: ensure newline substitution applies to whole message (#4009) @dceejay
- Template: Add information about environment variable to template node (#3882) @kazuhitoyokoi
- Trigger: Hide trigger node repeat send option if sending nothing (#4023) @dceejay
- Watch: fix watch node test on MacOS/ARM (#3942) @HiroyasuNishiyama
#### 3.0.2: Maintenance Release
Editor

View File

@@ -151,6 +151,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
"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/mermaid.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.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",
@@ -169,6 +170,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
@@ -224,7 +226,7 @@ module.exports = function(grunt) {
"node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js"
],
// "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
// // TODO: resolve relative resource paths in
@@ -233,6 +235,9 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
"node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
],
"packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js": [
"node_modules/mermaid/dist/mermaid.min.js"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "3.0.2",
"version": "3.1.0-beta.1",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -26,13 +26,13 @@
}
],
"dependencies": {
"acorn": "8.7.1",
"acorn": "8.8.1",
"acorn-walk": "8.2.0",
"ajv": "8.11.0",
"async-mutex": "0.3.2",
"ajv": "8.11.2",
"async-mutex": "0.4.0",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.20.0",
"body-parser": "1.20.1",
"cheerio": "1.0.0-rc.10",
"clone": "2.1.2",
"content-type": "1.0.4",
@@ -41,15 +41,15 @@
"cors": "2.8.5",
"cronosjs": "1.7.1",
"denque": "2.1.0",
"express": "4.18.1",
"express": "4.18.2",
"express-session": "1.17.3",
"form-data": "4.0.0",
"fs-extra": "10.1.0",
"got": "11.8.5",
"hash-sum": "2.0.0",
"hpagent": "1.0.0",
"hpagent": "1.2.0",
"https-proxy-agent": "5.0.1",
"i18next": "21.8.16",
"i18next": "21.10.0",
"iconv-lite": "0.6.3",
"is-utf8": "0.2.1",
"js-yaml": "4.1.0",
@@ -60,7 +60,7 @@
"memorystore": "1.6.7",
"mime": "3.0.0",
"moment": "2.29.4",
"moment-timezone": "0.5.34",
"moment-timezone": "0.5.39",
"mqtt": "4.3.7",
"multer": "1.4.5-lts.1",
"mustache": "4.2.0",
@@ -73,19 +73,19 @@
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.5.1",
"semver": "7.3.7",
"tar": "6.1.11",
"tough-cookie": "4.0.0",
"uglify-js": "3.16.3",
"semver": "7.3.8",
"tar": "6.1.12",
"tough-cookie": "4.1.2",
"uglify-js": "3.17.4",
"uuid": "8.3.2",
"ws": "7.5.6",
"xml2js": "0.4.23"
},
"optionalDependencies": {
"bcrypt": "5.0.1"
"bcrypt": "5.1.0"
},
"devDependencies": {
"dompurify": "2.3.10",
"dompurify": "2.4.1",
"grunt": "1.5.3",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.4.3",
@@ -108,13 +108,14 @@
"i18next-http-backend": "1.4.1",
"jquery-i18next": "1.2.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "4.0.18",
"marked": "4.2.3",
"mermaid": "^9.3.0",
"minami": "1.2.3",
"mocha": "9.2.2",
"node-red-node-test-helper": "^0.3.0",
"nodemon": "2.0.19",
"nodemon": "2.0.20",
"proxy": "^1.0.2",
"sass": "1.54.2",
"sass": "1.56.1",
"should": "13.2.3",
"sinon": "11.1.2",
"stoppable": "^1.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "3.0.2",
"version": "3.1.0-beta.1",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,14 +16,14 @@
}
],
"dependencies": {
"@node-red/util": "3.0.2",
"@node-red/editor-client": "3.0.2",
"@node-red/util": "3.1.0-beta.1",
"@node-red/editor-client": "3.1.0-beta.1",
"bcryptjs": "2.4.3",
"body-parser": "1.20.0",
"body-parser": "1.20.1",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.3",
"express": "4.18.1",
"express": "4.18.2",
"memorystore": "1.6.7",
"mime": "3.0.0",
"multer": "1.4.5-lts.1",
@@ -35,6 +35,6 @@
"ws": "7.5.6"
},
"optionalDependencies": {
"bcrypt": "5.0.1"
"bcrypt": "5.1.0"
}
}

View File

View File

View File

View File

@@ -53,22 +53,30 @@
"confirmDelete": "Confirm delete",
"delete": "Are you sure you want to delete '__label__'?",
"dropFlowHere": "Drop the flow here",
"dropImageHere": "Drop the image here",
"addFlow": "Add flow",
"addFlowToRight": "Add flow to the right",
"closeFlow": "Close flow",
"hideFlow": "Hide flow",
"hideOtherFlows": "Hide other flows",
"showAllFlows": "Show all flows",
"showAllFlows": "Show all flows (__count__ hidden)",
"hideAllFlows": "Hide all flows",
"hiddenFlows": "List __count__ hidden flow",
"hiddenFlows_plural": "List __count__ hidden flows",
"showLastHiddenFlow": "Show last hidden flow",
"showLastHiddenFlow": "Reopen hidden flow",
"listFlows": "List flows",
"listSubflows": "List subflows",
"status": "Status",
"enabled": "Enabled",
"disabled": "Disabled",
"info": "Description",
"selectNodes": "Click nodes to select"
"selectNodes": "Click nodes to select",
"enableFlow": "Enable flow",
"disableFlow": "Disable flow",
"lockFlow": "Lock flow",
"unlockFlow": "Unlock flow",
"moveToStart": "Move flow to start",
"moveToEnd": "Move flow to end"
},
"menu": {
"label": {
@@ -101,6 +109,7 @@
"displayStatus": "Show node status",
"displayConfig": "Configuration nodes",
"import": "Import",
"importExample": "Import Example Flow",
"export": "Export",
"search": "Search flows",
"searchInput": "search your flows",
@@ -497,6 +506,7 @@
"addRemoveNode": "Add/remove node from selection",
"editSelected": "Edit selected node",
"deleteSelected": "Delete selected nodes or link",
"deleteReconnect": "Delete and Reconnect",
"importNode": "Import nodes",
"exportNode": "Export nodes",
"nudgeNode": "Move selected nodes (1px)",
@@ -683,7 +693,9 @@
"empty": "empty",
"globalConfig": "Global Configuration Nodes",
"triggerAction": "Trigger action",
"find": "Find in workspace"
"find": "Find in workspace",
"copyItemUrl": "Copy item url",
"copyURL2Clipboard": "Copied url to clipboard"
},
"help": {
"name": "Help",
@@ -984,7 +996,10 @@
"quote": "Quote",
"link": "Link",
"horizontal-rule": "Horizontal rule",
"toggle-preview": "Toggle preview"
"toggle-preview": "Toggle preview",
"mermaid": {
"summary": "Mermaid Diagram"
}
},
"bufferEditor": {
"title": "Buffer editor",
@@ -1206,5 +1221,10 @@
"node": "Node",
"junction": "Junction",
"linkNodes": "Link Nodes"
},
"env-var": {
"environment": "Environment",
"header": "Global Environment Variables",
"revert": "Revert"
}
}

View File

View File

View File

@@ -53,8 +53,10 @@
"confirmDelete": "削除の確認",
"delete": "本当に '__label__' を削除しますか?",
"dropFlowHere": "ここにフローをドロップしてください",
"dropImageHere": "ここに画像ファイルをドロップしてください",
"addFlow": "フローの追加",
"addFlowToRight": "右側にフローを追加",
"closeFlow": "フローを閉じる",
"hideFlow": "フローを非表示",
"hideOtherFlows": "他のフローを非表示",
"showAllFlows": "全てのフローを表示",
@@ -68,7 +70,11 @@
"enabled": "有効",
"disabled": "無効",
"info": "詳細",
"selectNodes": "ノードをクリックして選択"
"selectNodes": "ノードをクリックして選択",
"enableFlow": "フローを有効化",
"disableFlow": "フローを無効化",
"moveToStart": "フローを先頭へ移動",
"moveToEnd": "フローを最後へ移動"
},
"menu": {
"label": {
@@ -683,7 +689,9 @@
"empty": "空",
"globalConfig": "グローバル設定ノード",
"triggerAction": "アクションを実行",
"find": "ワークスペース内を検索"
"find": "ワークスペース内を検索",
"copyItemUrl": "要素のURLをコピー",
"copyURL2Clipboard": "URLをクリップボードにコピーしました"
},
"help": {
"name": "ヘルプ",
@@ -984,7 +992,10 @@
"quote": "引用",
"link": "リンク",
"horizontal-rule": "区切り線",
"toggle-preview": "プレビュー表示切替え"
"toggle-preview": "プレビュー表示切替え",
"mermaid": {
"summary": "Mermaid図"
}
},
"bufferEditor": {
"title": "バッファエディタ",
@@ -1350,6 +1361,15 @@
"show-project-settings": "プロジェクト設定を表示",
"show-version-control-tab": "バージョンコントロールタブを表示",
"start-flows": "フローを開始",
"stop-flows": "フローを停止"
"stop-flows": "フローを停止",
"copy-item-url": "要素のURLをコピー",
"copy-item-edit-url": "要素の編集URLをコピー",
"move-flow-to-start": "フローを先頭に移動",
"move-flow-to-end": "フローを末尾に移動"
},
"env-var": {
"environment": "環境変数",
"header": "大域環境変数",
"revert": "破棄"
}
}

View File

View File

View File

View File

View File

View File

View File

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

View File

@@ -14,7 +14,7 @@
* limitations under the License.
**/
/**
/**
* An API for undo / redo history buffer
* @namespace RED.history
*/
@@ -434,7 +434,9 @@ RED.history = (function() {
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
}
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('locked')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!ev.node.locked);
}
if (ev.subflow) {
inverseEv.subflow = {};

View File

@@ -19,7 +19,6 @@
* @namespace RED.nodes
*/
RED.nodes = (function() {
var PORT_TYPE_INPUT = 1;
var PORT_TYPE_OUTPUT = 0;
@@ -63,6 +62,7 @@ RED.nodes = (function() {
defaults: {
label: {value:""},
disabled: {value: false},
locked: {value: false},
info: {value: ""},
env: {value: []}
}
@@ -575,15 +575,48 @@ RED.nodes = (function() {
}
}
const nodeProxyHandler = {
get(node, prop) {
if (prop === '__isProxy__') {
return true
} else if (prop == '__node__') {
return node
}
return node[prop]
},
set(node, prop, value) {
if (node.z && (RED.nodes.workspace(node.z)?.locked || RED.nodes.subflow(node.z)?.locked)) {
if (
node._def.defaults[prop] ||
prop === 'z' ||
prop === 'l' ||
prop === 'd' ||
(prop === 'changed' && (!!node.changed) !== (!!value)) || // jshint ignore:line
((prop === 'x' || prop === 'y') && !node.resize && node.type !== 'group')
) {
throw new Error(`Cannot modified property '${prop}' of locked object '${node.type}:${node.id}'`)
}
}
node[prop] = value;
return true
}
}
function addNode(n) {
let newNode
if (!n.__isProxy__) {
newNode = new Proxy(n, nodeProxyHandler)
} else {
newNode = n
}
if (n.type.indexOf("subflow") !== 0) {
n["_"] = n._def._;
} else {
var subflowId = n.type.substring(8);
var sf = RED.nodes.subflow(subflowId);
if (sf) {
sf.instances.push(sf);
sf.instances.push(newNode);
}
n["_"] = RED._;
}
@@ -600,12 +633,13 @@ RED.nodes = (function() {
});
n.i = nextId+1;
}
allNodes.addNode(n);
allNodes.addNode(newNode);
if (!nodeLinks[n.id]) {
nodeLinks[n.id] = {in:[],out:[]};
}
}
RED.events.emit('nodes:add',n);
RED.events.emit('nodes:add',newNode);
return newNode
}
function addLink(l) {
if (nodeLinks[l.source.id]) {
@@ -1046,6 +1080,9 @@ RED.nodes = (function() {
node.type = n.type;
for (var d in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d)) {
if (d === 'locked' && !n.locked) {
continue
}
node[d] = n[d];
}
}
@@ -1965,7 +2002,7 @@ RED.nodes = (function() {
}
}
} else {
const keepNodesCurrentZ = reimport && n.z && RED.workspaces.contains(n.z)
const keepNodesCurrentZ = reimport && n.z && (RED.workspaces.contains(n.z) || RED.nodes.subflow(n.z))
if (!keepNodesCurrentZ && n.z && !workspace_map[n.z] && !subflow_map[n.z]) {
n.z = activeWorkspace;
}
@@ -2067,7 +2104,7 @@ RED.nodes = (function() {
node.id = getID();
} else {
node.id = n.id;
const keepNodesCurrentZ = reimport && node.z && RED.workspaces.contains(node.z)
const keepNodesCurrentZ = reimport && node.z && (RED.workspaces.contains(node.z) || RED.nodes.subflow(node.z))
if (!keepNodesCurrentZ && (node.z == null || (!workspace_map[node.z] && !subflow_map[node.z]))) {
if (createMissingWorkspace) {
if (missingWorkspace === null) {
@@ -2315,19 +2352,6 @@ RED.nodes = (function() {
if (n.g && !new_group_set.has(n.g)) {
delete n.g;
}
n.nodes = n.nodes.map(function(id) {
return node_map[id];
})
// Just in case the group references a node that doesn't exist for some reason
n.nodes = n.nodes.filter(function(v) {
if (v) {
// Repair any nodes that have forgotten they are in this group
if (v.g !== n.id) {
v.g = n.id;
}
}
return !!v
});
if (!n.g) {
groupDepthMap[n.id] = 0;
}
@@ -2350,21 +2374,22 @@ RED.nodes = (function() {
return groupDepthMap[A.id] - groupDepthMap[B.id];
});
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
addGroup(n);
new_groups[i] = addGroup(new_groups[i]);
node_map[new_groups[i].id] = new_groups[i]
}
for (i=0;i<new_junctions.length;i++) {
var junction = new_junctions[i];
addJunction(junction);
new_junctions[i] = addJunction(new_junctions[i]);
node_map[new_junctions[i].id] = new_junctions[i]
}
// Now the nodes have been fully updated, add them.
for (i=0;i<new_nodes.length;i++) {
var node = new_nodes[i];
addNode(node);
new_nodes[i] = addNode(new_nodes[i])
node_map[new_nodes[i].id] = new_nodes[i]
}
// Finally validate them all.
// This has to be done after everything is added so that any checks for
// dependent config nodes will pass
@@ -2372,6 +2397,39 @@ RED.nodes = (function() {
var node = new_nodes[i];
RED.editor.validateNode(node);
}
const lookupNode = (id) => {
const mappedNode = node_map[id]
if (!mappedNode) {
return null
}
if (mappedNode.__isProxy__) {
return mappedNode
} else {
return node_map[mappedNode.id]
}
}
// Update groups to reference proxy node objects
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
// bypass the proxy in case the flow is locked
n.__node__.nodes = n.nodes.map(lookupNode)
// Just in case the group references a node that doesn't exist for some reason
n.__node__.nodes = n.nodes.filter(function(v) {
if (v) {
// Repair any nodes that have forgotten they are in this group
if (v.g !== n.id) {
v.g = n.id;
}
}
return !!v
});
}
// Update links to use proxy node objects
for (i=0;i<new_links.length;i++) {
new_links[i].source = lookupNode(new_links[i].source.id) || new_links[i].source
new_links[i].target = lookupNode(new_links[i].target.id) || new_links[i].target
}
RED.workspaces.refresh();
@@ -2500,11 +2558,17 @@ RED.nodes = (function() {
junctions = {};
junctionsByZ = {};
var workspaceIds = Object.keys(workspaces);
// Ensure all workspaces are unlocked so we don't get any edit-protection
// preventing removal
workspaceIds.forEach(function(id) {
workspaces[id].locked = false
});
var subflowIds = Object.keys(subflows);
subflowIds.forEach(function(id) {
RED.subflow.removeSubflow(id)
});
var workspaceIds = Object.keys(workspaces);
workspaceIds.forEach(function(id) {
RED.workspaces.remove(workspaces[id]);
});
@@ -2525,10 +2589,14 @@ RED.nodes = (function() {
}
function addGroup(group) {
if (!group.__isProxy__) {
group = new Proxy(group, nodeProxyHandler)
}
groupsByZ[group.z] = groupsByZ[group.z] || [];
groupsByZ[group.z].push(group);
groups[group.id] = group;
RED.events.emit("groups:add",group);
return group
}
function removeGroup(group) {
var i = groupsByZ[group.z].indexOf(group);
@@ -2549,6 +2617,9 @@ RED.nodes = (function() {
}
function addJunction(junction) {
if (!junction.__isProxy__) {
junction = new Proxy(junction, nodeProxyHandler)
}
junctionsByZ[junction.z] = junctionsByZ[junction.z] || []
junctionsByZ[junction.z].push(junction)
junctions[junction.id] = junction;
@@ -2556,6 +2627,7 @@ RED.nodes = (function() {
nodeLinks[junction.id] = {in:[],out:[]};
}
RED.events.emit("junctions:add", junction)
return junction
}
function removeJunction(junction) {
var i = junctionsByZ[junction.z].indexOf(junction)
@@ -2740,6 +2812,7 @@ RED.nodes = (function() {
}
});
const nodeGroupMap = {}
var replaceNodeIds = Object.keys(replaceNodes);
if (replaceNodeIds.length > 0) {
var reimportList = [];
@@ -2750,6 +2823,12 @@ RED.nodes = (function() {
} else {
allNodes.removeNode(n);
}
if (n.g) {
// reimporting a node *without* including its group object
// will cause the g property to be cleared. Cache it
// here so we can restore it
nodeGroupMap[n.id] = n.g
}
reimportList.push(convertNode(n));
RED.events.emit('nodes:remove',n);
});
@@ -2771,6 +2850,18 @@ RED.nodes = (function() {
var newNodeMap = {};
result.nodes.forEach(function(n) {
newNodeMap[n.id] = n;
if (nodeGroupMap[n.id]) {
// This node is in a group - need to substitute the
// node reference inside the group
n.g = nodeGroupMap[n.id]
const group = RED.nodes.group(n.g)
if (group) {
var index = group.nodes.findIndex(gn => gn.id === n.id)
if (index > -1) {
group.nodes[index] = n
}
}
}
});
RED.nodes.eachLink(function(l) {
if (newNodeMap.hasOwnProperty(l.source.id)) {
@@ -2831,7 +2922,7 @@ RED.nodes = (function() {
},
addWorkspace: addWorkspace,
removeWorkspace: removeWorkspace,
getWorkspaceOrder: function() { return workspacesOrder },
getWorkspaceOrder: function() { return [...workspacesOrder] },
setWorkspaceOrder: function(order) { workspacesOrder = order; },
workspace: getWorkspace,

View File

@@ -249,8 +249,35 @@ var RED = (function() {
RED.nodes.import(nodes.flows);
RED.nodes.dirty(false);
RED.view.redraw(true);
if (/^#flow\/.+$/.test(currentHash)) {
RED.workspaces.show(currentHash.substring(6),true);
if (/^#(flow|node|group)\/.+$/.test(currentHash)) {
const hashParts = currentHash.split('/')
const showEditDialog = hashParts.length > 2 && hashParts[2] === 'edit'
if (hashParts[0] === '#flow') {
RED.workspaces.show(hashParts[1], true);
if (showEditDialog) {
RED.workspaces.edit()
}
} else if (hashParts[0] === '#node') {
const nodeToShow = RED.nodes.node(hashParts[1])
if (nodeToShow) {
setTimeout(() => {
RED.view.reveal(nodeToShow.id)
window.location.hash = currentHash
if (showEditDialog) {
RED.editor.edit(nodeToShow)
}
}, 50)
}
} else if (hashParts[0] === '#group') {
const nodeToShow = RED.nodes.group(hashParts[1])
if (nodeToShow) {
RED.view.reveal(nodeToShow.id)
window.location.hash = currentHash
if (showEditDialog) {
RED.editor.editGroup(nodeToShow)
}
}
}
}
if (RED.workspaces.count() > 0) {
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
@@ -321,6 +348,8 @@ var RED = (function() {
loader.end()
RED.notify($("<p>").text(message));
RED.sidebar.info.refresh()
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
});
});
return;
@@ -641,11 +670,6 @@ var RED = (function() {
]});
menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"},
null,
{id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"},
{id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"},
{id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"},
@@ -655,7 +679,12 @@ var RED = (function() {
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
null,
{id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"},
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"}
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"},
null,
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"}
]});
menuOptions.push(null);
@@ -748,6 +777,7 @@ var RED = (function() {
RED.deploy.init(RED.settings.theme("deployButton",null));
RED.keyboard.init(buildMainMenu);
RED.envVar.init();
RED.nodes.init();
RED.runtime.init()

View File

@@ -423,11 +423,10 @@ RED.clipboard = (function() {
}
}
function showImportNodes(mode) {
function showImportNodes(library = 'clipboard') {
if (disabled) {
return;
}
mode = mode || "clipboard";
dialogContainer.empty();
dialogContainer.append($(importNodesDialog));
@@ -504,7 +503,7 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport);
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
if (RED.workspaces.active() === 0) {
if (RED.workspaces.active() === 0 || RED.workspaces.isActiveLocked()) {
$("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected");
$("#red-ui-clipboard-dialog-import-opt-new").addClass("selected");
} else {
@@ -533,8 +532,8 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
})
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode);
if (mode === 'clipboard') {
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+library);
if (library === 'clipboard') {
setTimeout(function() {
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
},100)
@@ -558,13 +557,16 @@ RED.clipboard = (function() {
});
}
function showExportNodes(mode) {
/**
* Show the export dialog
* @params library which export destination to show
* @params mode whether to default to 'auto' (default) or 'flow'
**/
function showExportNodes(library = 'clipboard', mode = 'auto' ) {
if (disabled) {
return;
}
mode = mode || "clipboard";
dialogContainer.empty();
dialogContainer.append($(exportNodesDialog));
@@ -654,7 +656,12 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select();
dialogContainer.i18n();
var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini";
const userFormat = RED.settings.get("editor.dialog.export.pretty")
if (userFormat === false || userFormat === true) {
format = userFormat ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini";
}
$("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) {
evt.preventDefault();
@@ -670,7 +677,8 @@ RED.clipboard = (function() {
var nodes = JSON.parse(flow);
format = $(this).attr('id');
if (format === 'red-ui-clipboard-dialog-export-fmt-full') {
const pretty = format === "red-ui-clipboard-dialog-export-fmt-full";
if (pretty) {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
@@ -679,6 +687,7 @@ RED.clipboard = (function() {
setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50);
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
RED.settings.set("editor.dialog.export.pretty", pretty)
}
});
@@ -766,12 +775,15 @@ RED.clipboard = (function() {
}
}
}
if (mode === 'flow' && !$("#red-ui-clipboard-dialog-export-rng-flow").hasClass('disabled')) {
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
}
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
$("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
} else {
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
}
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+library);
var dialogHeight = 400;
var winHeight = $(window).height();
@@ -1266,15 +1278,17 @@ RED.clipboard = (function() {
RED.keyboard.add("#red-ui-drop-target", "escape" ,hideDropTarget);
$('#red-ui-workspace-chart').on("dragenter",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
if (!RED.workspaces.isActiveLocked() && (
$.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1)) {
$("#red-ui-drop-target").css({display:'table'}).focus();
}
});
$('#red-ui-drop-target').on("dragover",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1 ||
RED.workspaces.isActiveLocked()) {
event.preventDefault();
}
})
@@ -1282,27 +1296,29 @@ RED.clipboard = (function() {
hideDropTarget();
})
.on("drop",function(event) {
try {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
importNodes(data);
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
var files = event.originalEvent.dataTransfer.files;
if (files.length === 1) {
var file = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
importNodes(e.target.result);
};
})(file);
reader.readAsText(file);
if (!RED.workspaces.isActiveLocked()) {
try {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
importNodes(data);
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
var files = event.originalEvent.dataTransfer.files;
if (files.length === 1) {
var file = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
importNodes(e.target.result);
};
})(file);
reader.readAsText(file);
}
}
} catch(err) {
// Ensure any errors throw above doesn't stop the drop target from
// being hidden.
}
} catch(err) {
// Ensure any errors throw above doesn't stop the drop target from
// being hidden.
}
hideDropTarget();
event.preventDefault();

View File

@@ -94,8 +94,8 @@ RED.menu = (function() {
var link = $(linkContent).appendTo(item);
opt.link = link;
if (typeof opt.onselect === 'string') {
var shortcut = RED.keyboard.getShortcut(opt.onselect);
if (typeof opt.onselect === 'string' || opt.shortcut) {
var shortcut = opt.shortcut || RED.keyboard.getShortcut(opt.onselect);
if (shortcut && shortcut.key) {
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(link.find(".red-ui-menu-label"));
}

View File

@@ -141,7 +141,29 @@ RED.tabs = (function() {
})
}
if (options.contextmenu) {
wrapper.on('contextmenu', function(evt) {
let clickedTab
let target = evt.target
while(target.nodeName !== 'A' && target.nodeName !== 'UL' && target.nodeName !== 'BODY') {
target = target.parentNode
}
if (target.nodeName === 'A') {
const href = target.getAttribute('href')
if (href) {
clickedTab = tabs[href.slice(1)]
}
}
evt.preventDefault()
evt.stopPropagation()
RED.contextMenu.show({
x:evt.clientX-5,
y:evt.clientY-5,
options: options.contextmenu(clickedTab)
})
return false
})
}
var scrollLeft;
var scrollRight;
@@ -807,19 +829,19 @@ RED.tabs = (function() {
event.preventDefault();
removeTab(tab.id);
});
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
}
if (tab.hideable) {
li.addClass("red-ui-tabs-closeable")
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
closeLink.append('<i class="fa fa-eye" />');
closeLink.append('<i class="fa fa-eye-slash" />');
closeLink.on("click",function(event) {
event.preventDefault();
hideTab(tab.id);
});
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
RED.popover.tooltip(closeLink,RED._("workspace.closeFlow"));
}
// if (tab.hideable) {
// li.addClass("red-ui-tabs-closeable")
// var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
// closeLink.append('<i class="fa fa-eye" />');
// closeLink.append('<i class="fa fa-eye-slash" />');
// closeLink.on("click",function(event) {
// event.preventDefault();
// hideTab(tab.id);
// });
// RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
// }
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
if (options.onselect) {
@@ -938,6 +960,9 @@ RED.tabs = (function() {
activeIndex: function() {
return ul.find("li.active").index()
},
getTabIndex: function (id) {
return ul.find("a[href='#"+id+"']").parent().index()
},
contains: function(id) {
return ul.find("a[href='#"+id+"']").length > 0;
},

View File

@@ -146,7 +146,7 @@
{ value: "reset", source: ["delay","trigger","join","rbe"] },
{ value: "responseCookies", source: ["http request"] },
{ value: "responseTopic", source: ["mqtt"] },
{ value: "responseURL", source: ["http request"] },
{ value: "responseUrl", source: ["http request"] },
{ value: "restartTimeout", source: ["join"] },
{ value: "retain", source: ["mqtt"] },
{ value: "schema", source: ["json"] },

View File

@@ -1,21 +1,6 @@
RED.contextMenu = (function () {
let menu;
function createMenu() {
// menu = RED.popover.menu({
// options: [
// {
// label: 'delete selection',
// onselect: function() {
// RED.actions.invoke('core:delete-selection')
// RED.view.focus()
// }
// },
// { label: 'world' }
// ],
// width: 200,
// })
}
function disposeMenu() {
$(document).off("mousedown.red-ui-workspace-context-menu");
@@ -28,114 +13,164 @@ RED.contextMenu = (function () {
if (menu) {
menu.remove()
}
let menuItems = []
if (options.options) {
menuItems = options.options
} else if (options.type === 'workspace') {
const selection = RED.view.selection()
const noSelection = !selection || Object.keys(selection).length === 0
const hasSelection = (selection.nodes && selection.nodes.length > 0);
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || [];
const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || [];
const hasLinks = wireLinks.length > 0;
const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
const canDelete = hasSelection || hasLinks
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
const canEdit = !RED.workspaces.isActiveLocked()
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
const isAllGroups = hasSelection && selection.nodes.filter(n => n.type !== 'group').length === 0
const hasGroup = hasSelection && selection.nodes.filter(n => n.type === 'group' ).length > 0
const offset = $("#red-ui-workspace-chart").offset()
const selection = RED.view.selection()
const noSelection = !selection || Object.keys(selection).length === 0
const hasSelection = (selection.nodes && selection.nodes.length > 0);
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || [];
const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || [];
const hasLinks = wireLinks.length > 0;
const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
const canDelete = hasSelection || hasLinks
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
const offset = $("#red-ui-workspace-chart").offset()
// 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 () { } },
{
label: RED._("contextMenu.insert"),
options: [
{
label: RED._("contextMenu.node"),
onselect: function () {
RED.view.showQuickAddDialog({
position: [addX, addY],
touchTrigger: true,
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
label: RED._("contextMenu.junction"),
onselect: 'core:split-wires-with-junctions',
disabled: !hasLinks
} : {
label: RED._("contextMenu.junction"),
onselect: function () {
const nn = {
_def: { defaults: {} },
type: 'junction',
z: RED.workspaces.active(),
id: RED.nodes.id(),
x: addX,
y: addY,
w: 0, h: 0,
outputs: 1,
inputs: 1,
dirty: true
}
const historyEvent = {
dirty: RED.nodes.dirty(),
t: 'add',
junctions: [nn]
}
RED.nodes.addJunction(nn);
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.view.select({nodes: [nn] });
RED.view.redraw(true)
}
},
{
label: RED._("contextMenu.linkNodes"),
onselect: 'core:split-wire-with-link-nodes',
disabled: !hasLinks
}
]
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)
}
menuItems.push(
{ onselect: 'core:show-action-list', onpostselect: function () { } }
)
const insertOptions = []
menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions })
insertOptions.push(
{
label: RED._("contextMenu.node"),
onselect: function () {
RED.view.showQuickAddDialog({
position: [addX, addY],
touchTrigger: true,
splice: isSingleLink ? selection.links[0] : undefined,
// spliceMultiple: isMultipleLinks
})
},
disabled: !canEdit
},
(hasLinks) ? { // has least 1 wire selected
label: RED._("contextMenu.junction"),
onselect: 'core:split-wires-with-junctions',
disabled: !canEdit || !hasLinks
} : {
label: RED._("contextMenu.junction"),
onselect: function () {
const nn = {
_def: { defaults: {} },
type: 'junction',
z: RED.workspaces.active(),
id: RED.nodes.id(),
x: addX,
y: addY,
w: 0, h: 0,
outputs: 1,
inputs: 1,
dirty: true
}
const historyEvent = {
dirty: RED.nodes.dirty(),
t: 'add',
junctions: [nn]
}
RED.nodes.addJunction(nn);
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.view.select({nodes: [nn] });
RED.view.redraw(true)
},
disabled: !canEdit
},
{
label: RED._("contextMenu.linkNodes"),
onselect: 'core:split-wire-with-link-nodes',
disabled: !canEdit || !hasLinks
},
null,
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
)
if (hasSelection && canEdit) {
const nodeOptions = []
if (!hasMultipleSelection && !isGroup) {
nodeOptions.push(
{ onselect: 'core:show-node-help' },
null
)
}
nodeOptions.push(
{ onselect: 'core:enable-selected-nodes' },
{ onselect: 'core:disable-selected-nodes' },
null,
{ onselect: 'core:show-selected-node-labels' },
{ onselect: 'core:hide-selected-node-labels' }
)
menuItems.push({
label: RED._('sidebar.info.node'),
options: nodeOptions
})
menuItems.push({
label: RED._('sidebar.info.group'),
options: [
{ onselect: 'core:group-selection' },
{ onselect: 'core:ungroup-selection', disabled: !hasGroup },
null,
{ onselect: 'core:copy-group-style', disabled: !hasGroup },
{ onselect: 'core:paste-group-style', disabled: !hasGroup}
]
})
if (canRemoveFromGroup) {
menuItems[menuItems.length - 1].options.push(
null,
{ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") }
)
}
}
if (canEdit && hasMultipleSelection) {
menuItems.push({
label: RED._('menu.label.arrange'),
options: [
{ label:RED._("menu.label.alignLeft"), onselect: "core:align-selection-to-left"},
{ label:RED._("menu.label.alignCenter"), onselect: "core:align-selection-to-center"},
{ label:RED._("menu.label.alignRight"), onselect: "core:align-selection-to-right"},
null,
{ label:RED._("menu.label.alignTop"), onselect: "core:align-selection-to-top"},
{ label:RED._("menu.label.alignMiddle"), onselect: "core:align-selection-to-middle"},
{ label:RED._("menu.label.alignBottom"), onselect: "core:align-selection-to-bottom"},
null,
{ label:RED._("menu.label.distributeHorizontally"), onselect: "core:distribute-selection-horizontally"},
{ label:RED._("menu.label.distributeVertically"), onselect: "core:distribute-selection-vertically"}
]
})
}
]
menuItems.push(
null,
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
null,
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection },
{ onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() },
{ onselect: 'core:delete-selection', disabled: !canDelete },
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
{ onselect: 'core:select-all-nodes' }
)
if (hasSelection) {
menuItems.push(
null,
isGroup ?
{ onselect: 'core:ungroup-selection', disabled: !isGroup }
: { onselect: 'core:group-selection', disabled: !hasSelection }
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
null,
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !canEdit || !hasSelection },
{ onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() },
{ onselect: 'core:delete-selection', disabled: !canEdit || !canDelete },
{ onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete },
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
{ onselect: 'core:select-all-nodes' },
)
if (canRemoveFromGroup) {
menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") })
}
}
var direction = "right";

View File

@@ -558,6 +558,11 @@ RED.deploy = (function() {
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
}
RED.nodes.eachNode(function (node) {
const flow = node.z && (RED.nodes.workspace(node.z) || RED.nodes.subflow(node.z) || null);
const isLocked = flow ? flow.locked : false;
if (flow && isLocked) {
flow.locked = false;
}
if (node.changed) {
node.dirty = true;
node.changed = false;
@@ -569,6 +574,9 @@ RED.deploy = (function() {
if (node.credentials) {
delete node.credentials;
}
if (flow && isLocked) {
flow.locked = isLocked;
}
});
RED.nodes.eachConfig(function (confNode) {
confNode.changed = false;

View File

@@ -238,6 +238,7 @@ RED.editor = (function() {
var valid = validateNodeProperty(node, defaults, property,value);
if (((typeof valid) === "string") || !valid) {
input.addClass("input-error");
input.next(".red-ui-typedInput-container").addClass("input-error");
if ((typeof valid) === "string") {
var tooltip = input.data("tooltip");
if (tooltip) {
@@ -250,6 +251,7 @@ RED.editor = (function() {
}
} else {
input.removeClass("input-error");
input.next(".red-ui-typedInput-container").removeClass("input-error");
var tooltip = input.data("tooltip");
if (tooltip) {
input.data("tooltip", null);
@@ -1851,11 +1853,15 @@ RED.editor = (function() {
workspace.disabled = disabled;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
if (workspace.id === RED.workspaces.active()) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
}
}
var locked = $("#node-input-locked").prop("checked");
if (workspace.locked !== locked) {
editState.changes.locked = workspace.locked;
editState.changed = true;
workspace.locked = locked;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked);
}
if (editState.changed) {
var historyEvent = {
t: "edit",
@@ -1896,6 +1902,7 @@ RED.editor = (function() {
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
var trayFooterRight = $('<div class="red-ui-tray-footer-right"></div>').appendTo(trayFooter)
var nodeEditPanes = [
'editor-tab-flow-properties',
@@ -1910,6 +1917,18 @@ RED.editor = (function() {
disabledIcon: "fa-ban",
invertState: true
})
if (!workspace.hasOwnProperty("locked")) {
workspace.locked = false;
}
$('<input id="node-input-locked" type="checkbox">').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({
enabledLabel: 'Unlocked',
enabledIcon: "fa-unlock-alt",
disabledLabel: 'Locked',
disabledIcon: "fa-lock",
invertState: true
})
prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) {
activeEditPanes = _activeEditPanes;
trayBody.i18n();

View File

@@ -45,6 +45,9 @@
selectedCodeEditor = RED.editor.codeEditor[defaultEditor];
initialised = selectedCodeEditor.init();
}
$('<div id="red-ui-image-drop-target"><div data-i18n="[append]workspace.dropImageHere"><i class="fa fa-download"></i><br></div></div>').appendTo('#red-ui-editor');
$("#red-ui-image-drop-target").hide();
}
function create(options) {
@@ -64,6 +67,7 @@
options = {};
}
var editor = null;
if (this.editor.type === MONACO) {
// compatibility (see above note)
if (!options.element && !options.id) {
@@ -74,10 +78,14 @@
console.warn("createEditor() options.element or options.id is not valid", options);
$("#dialog-form").append('<div id="' + options.id + '" style="display: none;" />');
}
return this.editor.create(options);
editor = this.editor.create(options);
} else {
return this.editor.create(options);//fallback to ACE
editor = this.editor.create(options);//fallback to ACE
}
if (options.mode === "ace/mode/markdown") {
RED.editor.customEditTypes['_markdown'].postInit(editor, options);
}
return editor;
}
return {

View File

@@ -2,7 +2,7 @@ RED.editor.envVarList = (function() {
var currentLocale = 'en-US';
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred','jsonata'];
/**
* Create env var edit interface

View File

@@ -14,6 +14,61 @@
* limitations under the License.
**/
(function() {
/**
* Converts dropped image file to date URL
*/
function file2base64Image(file, cb) {
var reader = new FileReader();
reader.onload = (function (fd) {
return function (e) {
cb(e.target.result);
};
})(file);
reader.readAsDataURL(file);
}
var initialized = false;
var currentEditor = null;
/**
* Initialize handler for image file drag events
*/
function initImageDrag(elem, editor) {
$(elem).on("dragenter", function (ev) {
ev.preventDefault();
$("#red-ui-image-drop-target").css({display:'table'}).focus();
currentEditor = editor;
});
if (!initialized) {
initialized = true;
$("#red-ui-image-drop-target").on("dragover", function (ev) {
ev.preventDefault();
}).on("dragleave", function (ev) {
$("#red-ui-image-drop-target").hide();
}).on("drop", function (ev) {
ev.preventDefault();
if ($.inArray("Files",ev.originalEvent.dataTransfer.types) != -1) {
var files = ev.originalEvent.dataTransfer.files;
if (files.length === 1) {
var file = files[0];
var name = file.name.toLowerCase();
if (name.match(/\.(apng|avif|gif|jpeg|png|svg|webp)$/)) {
file2base64Image(file, function (image) {
var session = currentEditor.getSession();
var img = `<img src="${image}"/>\n`;
var pos = session.getCursorPosition();
session.insert(pos, img);
$("#red-ui-image-drop-target").hide();
});
return;
}
}
}
$("#red-ui-image-drop-target").hide();
});
}
}
var toolbarTemplate = '<div style="margin-bottom: 5px">'+
'<span class="button-group">'+
@@ -114,6 +169,7 @@
var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop();
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
mermaid.init();
},200);
})
if (options.header) {
@@ -122,6 +178,7 @@
if (value) {
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
mermaid.init();
}
panels = RED.panels.create({
id:"red-ui-editor-type-markdown-panels",
@@ -148,10 +205,14 @@
});
RED.popover.tooltip($("#node-btn-markdown-preview"), RED._("markdownEditor.toggle-preview"));
if (options.cursor && !expressionEditor._initState) {
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
}
if(!expressionEditor._initState) {
if (options.cursor) {
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
}
else {
expressionEditor.gotoLine(0, 0, false);
}
}
dialogForm.i18n();
},
close: function() {
@@ -215,7 +276,11 @@
}
})
return toolbar;
}
},
postInit: function (editor, options) {
var elem = $("#"+options.id);
initImageDrag(elem, editor);
}
}
RED.editor.registerTypeEditor("_markdown", definition);
})();

View File

@@ -52,8 +52,6 @@
node.info = info;
}
$("#red-ui-tab-"+(node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!node.disabled);
}
}
});

View File

@@ -0,0 +1,175 @@
RED.envVar = (function() {
function saveEnvList(list) {
const items = list.editableList("items")
const new_env = [];
items.each(function (i,el) {
var data = el.data('data');
var item;
if (data.nameField && data.valueField) {
item = {
name: data.nameField.val(),
value: data.valueField.typedInput("value"),
type: data.valueField.typedInput("type")
};
new_env.push(item);
}
});
return new_env;
}
function getGlobalConf(create) {
var gconf = null;
RED.nodes.eachConfig(function (conf) {
if (conf.type === "global-config") {
gconf = conf;
}
});
if ((gconf === null) && create) {
var cred = {
_ : {},
map: {}
};
gconf = {
id: RED.nodes.id(),
type: "global-config",
env: [],
name: "global-config",
label: "",
hasUsers: false,
users: [],
credentials: cred,
_def: RED.nodes.getType("global-config"),
};
RED.nodes.add(gconf);
}
return gconf;
}
function applyChanges(list) {
var gconf = getGlobalConf(false);
var new_env = [];
var items = list.editableList('items');
var credentials = gconf ? gconf.credentials : null;
if (!credentials) {
credentials = {
_ : {},
map: {}
};
}
items.each(function (i,el) {
var data = el.data('data');
if (data.nameField && data.valueField) {
var item = {
name: data.nameField.val(),
value: data.valueField.typedInput("value"),
type: data.valueField.typedInput("type")
};
if (item.name.trim() !== "") {
new_env.push(item);
if ((item.type === "cred") && (item.value !== "__PWRD__")) {
credentials.map[item.name] = item.value;
credentials.map["has_"+item.name] = (item.value !== "");
item.value = "__PWRD__";
}
}
}
});
if (gconf === null) {
gconf = getGlobalConf(true);
}
if ((JSON.stringify(new_env) !== JSON.stringify(gconf.env)) ||
(JSON.stringify(credentials) !== JSON.stringify(gconf.credentials))) {
gconf.env = new_env;
gconf.credentials = credentials;
RED.nodes.dirty(true);
}
}
function getSettingsPane() {
var gconf = getGlobalConf(false);
var env = gconf ? gconf.env : [];
var cred = gconf ? gconf.credentials : null;
if (!cred) {
cred = {
_ : {},
map: {}
};
}
var pane = $("<div/>", {
id: "red-ui-settings-tab-envvar",
class: "form-horizontal"
});
var content = $("<div/>", {
class: "form-row node-input-env-container-row"
}).css({
"margin": "10px"
}).appendTo(pane);
var label = $("<label></label>").css({
width: "100%"
}).appendTo(content);
$("<i/>", {
class: "fa fa-list"
}).appendTo(label);
$("<span/>").text(" "+RED._("env-var.header")).appendTo(label);
var list = $("<ol/>", {
id: "node-input-env-container"
}).appendTo(content);
var node = {
type: "",
env: env,
credentials: cred.map,
};
RED.editor.envVarList.create(list, node);
var buttons = $("<div/>").css({
"text-align": "right",
}).appendTo(content);
var revertButton = $("<button/>", {
class: "red-ui-button"
}).css({
}).text(RED._("env-var.revert")).appendTo(buttons);
var items = saveEnvList(list);
revertButton.on("click", function (ev) {
list.editableList("empty");
list.editableList("addItems", items);
});
return pane;
}
function init(done) {
if (!RED.user.hasPermission("settings.write")) {
RED.notify(RED._("user.errors.settings"),"error");
return;
}
RED.userSettings.add({
id:'envvar',
title: RED._("env-var.environment"),
get: getSettingsPane,
focus: function() {
var height = $("#red-ui-settings-tab-envvar").parent().height();
$("#node-input-env-container").editableList("height", (height -100));
},
close: function() {
var list = $("#node-input-env-container");
try {
applyChanges(list);
}
catch (e) {
console.log(e);
console.log(e.stack);
}
}
});
}
return {
init: init,
};
})();

View File

@@ -188,6 +188,8 @@ RED.group = (function() {
var activateMerge = false;
var activateRemove = false;
var singleGroupSelected = false;
var locked = RED.workspaces.isActiveLocked()
if (activateGroup) {
singleGroupSelected = selection.nodes.length === 1 && selection.nodes[0].type === 'group';
selection.nodes.forEach(function (n) {
@@ -202,12 +204,12 @@ RED.group = (function() {
activateMerge = (selection.nodes.length > 1);
}
}
RED.menu.setDisabled("menu-item-group-group", !activateGroup);
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
RED.menu.setDisabled("menu-item-group-group", locked || !activateGroup);
RED.menu.setDisabled("menu-item-group-ungroup", locked || !activateUngroup);
RED.menu.setDisabled("menu-item-group-merge", locked || !activateMerge);
RED.menu.setDisabled("menu-item-group-remove", locked || !activateRemove);
RED.menu.setDisabled("menu-item-edit-copy-group-style", !singleGroupSelected);
RED.menu.setDisabled("menu-item-edit-paste-group-style", !activateUngroup);
RED.menu.setDisabled("menu-item-edit-paste-group-style", locked || !activateUngroup);
});
RED.actions.add("core:group-selection", function() { groupSelection() })
@@ -264,6 +266,7 @@ RED.group = (function() {
}
}
function pasteGroupStyle() {
if (RED.workspaces.isActiveLocked()) { return }
if (RED.view.state() !== RED.state.DEFAULT) { return }
if (groupStyleClipboard) {
var selection = RED.view.selection();
@@ -298,6 +301,7 @@ RED.group = (function() {
}
function groupSelection() {
if (RED.workspaces.isActiveLocked()) { return }
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
@@ -316,6 +320,7 @@ RED.group = (function() {
}
}
function ungroupSelection() {
if (RED.workspaces.isActiveLocked()) { return }
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
@@ -339,6 +344,7 @@ RED.group = (function() {
}
function ungroup(g) {
if (RED.workspaces.isActiveLocked()) { return }
var nodes = [];
var parentGroup = RED.nodes.group(g.g);
g.nodes.forEach(function(n) {
@@ -365,6 +371,7 @@ RED.group = (function() {
}
function mergeSelection() {
if (RED.workspaces.isActiveLocked()) { return }
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
@@ -434,6 +441,7 @@ RED.group = (function() {
}
function removeSelection() {
if (RED.workspaces.isActiveLocked()) { return }
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
@@ -461,6 +469,7 @@ RED.group = (function() {
}
}
function createGroup(nodes) {
if (RED.workspaces.isActiveLocked()) { return }
if (nodes.length === 0) {
return;
}
@@ -483,7 +492,7 @@ RED.group = (function() {
}
group.z = nodes[0].z;
RED.nodes.addGroup(group);
group = RED.nodes.addGroup(group);
try {
addToGroup(group,nodes);
@@ -566,6 +575,7 @@ RED.group = (function() {
markDirty(group);
}
function removeFromGroup(group, nodes, reparent) {
if (RED.workspaces.isActiveLocked()) { return }
if (!Array.isArray(nodes)) {
nodes = [nodes];
}

0
packages/node_modules/@node-red/editor-client/src/js/ui/library.js vendored Executable file → Normal file
View File

View File

@@ -0,0 +1,46 @@
// Mermaid diagram stub library for on-demand dynamic loading
// Will be overwritten after script loading by $.getScript
var mermaid = (function () {
var enabled /* = undefined */;
var initializing = false;
var initCalled = false;
function initialize(opt) {
if (enabled === undefined) {
if (RED.settings.markdownEditor &&
RED.settings.markdownEditor.mermaid) {
enabled = RED.settings.markdownEditor.mermaid.enabled;
}
else {
enabled = true;
}
}
if (enabled) {
initializing = true;
$.getScript("vendor/mermaid/mermaid.min.js",
function (data, stat, jqxhr) {
$(".mermaid").show();
// invoke loaded mermaid API
initializing = false;
mermaid.initialize(opt);
if (initCalled) {
mermaid.init();
initCalled = false;
}
});
}
}
function init() {
if (initializing) {
$(".mermaid").hide();
initCalled = true;
}
}
return {
initialize: initialize,
init: init,
};
})();

166
packages/node_modules/@node-red/editor-client/src/js/ui/palette.js vendored Executable file → Normal file
View File

@@ -292,6 +292,7 @@ RED.palette = (function() {
var hoverGroup;
var paletteWidth;
var paletteTop;
var dropEnabled;
$(d).draggable({
helper: 'clone',
appendTo: '#red-ui-editor',
@@ -299,6 +300,7 @@ RED.palette = (function() {
revertDuration: 200,
containment:'#red-ui-main-container',
start: function() {
dropEnabled = !(RED.nodes.workspace(RED.workspaces.active())?.locked);
paletteWidth = $("#red-ui-palette").width();
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
hoverGroup = null;
@@ -309,96 +311,100 @@ RED.palette = (function() {
RED.view.focus();
},
stop: function() {
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");
if (dropEnabled) {
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");
}
if (activeGroup) {
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
}
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
}
if (activeGroup) {
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
}
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
},
drag: function(e,ui) {
var paletteNode = getPaletteNode(nt);
ui.originalPosition.left = paletteNode.offset().left;
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
if (!groupTimer) {
groupTimer = setTimeout(function() {
var mx = mouseX / RED.view.scale();
var my = mouseY / RED.view.scale();
var group = RED.view.getGroupAtPoint(mx,my);
if (group !== hoverGroup) {
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
if (group) {
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
}
hoverGroup = group;
if (hoverGroup) {
$(ui.helper).data('group',hoverGroup);
} else {
$(ui.helper).removeData('group');
}
}
groupTimer = null;
},200)
}
if (def.inputs > 0 && def.outputs > 0) {
if (!spliceTimer) {
spliceTimer = setTimeout(function() {
var nodes = [];
var bestDistance = Infinity;
var bestLink = null;
if (chartSVG.getIntersectionList) {
var svgRect = chartSVG.createSVGRect();
svgRect.x = mouseX;
svgRect.y = mouseY;
svgRect.width = 1;
svgRect.height = 1;
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
} else {
// Firefox doesn't do getIntersectionList and that
// makes us sad
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
}
if (dropEnabled) {
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
if (!groupTimer) {
groupTimer = setTimeout(function() {
var mx = mouseX / RED.view.scale();
var my = mouseY / RED.view.scale();
for (var i=0;i<nodes.length;i++) {
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 = 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 = nodes[i];
var group = RED.view.getGroupAtPoint(mx,my);
if (group !== hoverGroup) {
if (hoverGroup) {
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
}
if (group) {
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
}
hoverGroup = group;
if (hoverGroup) {
$(ui.helper).data('group',hoverGroup);
} else {
$(ui.helper).removeData('group');
}
}
groupTimer = null;
},200)
}
if (def.inputs > 0 && def.outputs > 0) {
if (!spliceTimer) {
spliceTimer = setTimeout(function() {
var nodes = [];
var bestDistance = Infinity;
var bestLink = null;
if (chartSVG.getIntersectionList) {
var svgRect = chartSVG.createSVGRect();
svgRect.x = mouseX;
svgRect.y = mouseY;
svgRect.width = 1;
svgRect.height = 1;
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
} else {
// Firefox doesn't do getIntersectionList and that
// makes us sad
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
}
var mx = mouseX / RED.view.scale();
var my = mouseY / RED.view.scale();
for (var i=0;i<nodes.length;i++) {
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 = 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 = nodes[i];
}
}
}
}
}
if (activeSpliceLink && activeSpliceLink !== bestLink) {
d3.select(activeSpliceLink.parentNode).classed('red-ui-flow-link-splice',false);
}
if (bestLink) {
d3.select(bestLink.parentNode).classed('red-ui-flow-link-splice',true)
} else {
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
}
if (activeSpliceLink !== bestLink) {
if (bestLink) {
$(ui.helper).data('splice',d3.select(bestLink).data()[0]);
} else {
$(ui.helper).removeData('splice');
if (activeSpliceLink && activeSpliceLink !== bestLink) {
d3.select(activeSpliceLink.parentNode).classed('red-ui-flow-link-splice',false);
}
}
activeSpliceLink = bestLink;
spliceTimer = null;
},200);
if (bestLink) {
d3.select(bestLink.parentNode).classed('red-ui-flow-link-splice',true)
} else {
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
}
if (activeSpliceLink !== bestLink) {
if (bestLink) {
$(ui.helper).data('splice',d3.select(bestLink).data()[0]);
} else {
$(ui.helper).removeData('splice');
}
}
activeSpliceLink = bestLink;
spliceTimer = null;
},200);
}
}
}
}
@@ -432,6 +438,7 @@ RED.palette = (function() {
categoryNode.find(".red-ui-palette-content").slideToggle();
categoryNode.find("i").toggleClass("expanded");
}
categoryNode.hide();
}
}
@@ -510,6 +517,7 @@ RED.palette = (function() {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
currentCategoryNode.hide();
}
}

View File

View File

@@ -273,6 +273,11 @@ RED.subflow = (function() {
var subflowInstances = [];
if (activeSubflow) {
RED.nodes.filterNodes({type:"subflow:"+activeSubflow.id}).forEach(function(n) {
const parentFlow = RED.nodes.workspace(n.z)
const wasLocked = parentFlow && parentFlow.locked
if (wasLocked) {
parentFlow.locked = false
}
subflowInstances.push({
id: n.id,
changed: n.changed
@@ -285,6 +290,9 @@ RED.subflow = (function() {
n.resize = true;
n.dirty = true;
RED.editor.updateNodeProperties(n);
if (wasLocked) {
parentFlow.locked = true
}
});
RED.editor.validateNode(activeSubflow);
return {
@@ -431,44 +439,7 @@ RED.subflow = (function() {
$("#red-ui-subflow-delete").on("click", function(event) {
event.preventDefault();
var subflow = RED.nodes.subflow(RED.workspaces.active());
if (subflow.instances.length > 0) {
var msg = $('<div>')
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
var confirmDeleteNotification = RED.notify(msg, {
modal: true,
fixed: true,
buttons: [
{
text: RED._('common.label.cancel'),
click: function() {
confirmDeleteNotification.close();
}
},
{
text: RED._('workspace.confirmDelete'),
class: "primary",
click: function() {
confirmDeleteNotification.close();
completeDelete();
}
}
]
});
return;
} else {
completeDelete();
}
function completeDelete() {
var startDirty = RED.nodes.dirty();
var historyEvent = removeSubflow(RED.workspaces.active());
historyEvent.t = 'delete';
historyEvent.dirty = startDirty;
RED.history.push(historyEvent);
}
RED.subflow.delete(RED.workspaces.active())
});
refreshToolbar(activeSubflow);
@@ -481,7 +452,51 @@ RED.subflow = (function() {
$("#red-ui-workspace-toolbar").hide().empty();
$("#red-ui-workspace-chart").css({"margin-top": "0"});
}
function deleteSubflow(id) {
const subflow = RED.nodes.subflow(id || RED.workspaces.active());
if (!subflow) {
return
}
if (subflow.instances.length > 0) {
if (subflow.instances.some(sf => { const ws = RED.nodes.workspace(sf.z); return ws?ws.locked:false })) {
return
}
const msg = $('<div>')
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
const confirmDeleteNotification = RED.notify(msg, {
modal: true,
fixed: true,
buttons: [
{
text: RED._('common.label.cancel'),
click: function() {
confirmDeleteNotification.close();
}
},
{
text: RED._('workspace.confirmDelete'),
class: "primary",
click: function() {
confirmDeleteNotification.close();
completeDelete();
}
}
]
});
return;
} else {
completeDelete();
}
function completeDelete() {
const startDirty = RED.nodes.dirty();
const historyEvent = removeSubflow(subflow.id);
historyEvent.t = 'delete';
historyEvent.dirty = startDirty;
RED.history.push(historyEvent);
}
}
function removeSubflow(id, keepInstanceNodes) {
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
var removedNodes = [];
@@ -558,7 +573,7 @@ RED.subflow = (function() {
}
});
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
if (!selection.nodes || RED.workspaces.isActiveLocked()) {
RED.menu.setDisabled("menu-item-subflow-convert",true);
} else {
RED.menu.setDisabled("menu-item-subflow-convert",false);
@@ -621,6 +636,9 @@ RED.subflow = (function() {
}
function convertToSubflow() {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
if (!selection.nodes) {
RED.notify(RED._("subflow.errors.noNodesSelected"),"error");
@@ -776,7 +794,7 @@ RED.subflow = (function() {
}
subflowInstance._def = RED.nodes.getType(subflowInstance.type);
RED.editor.validateNode(subflowInstance);
RED.nodes.add(subflowInstance);
subflowInstance = RED.nodes.add(subflowInstance);
if (containingGroup) {
RED.group.addToGroup(containingGroup, subflowInstance);
@@ -1330,7 +1348,10 @@ RED.subflow = (function() {
init: init,
createSubflow: createSubflow,
convertToSubflow: convertToSubflow,
// removeSubflow: Internal function to remove subflow
removeSubflow: removeSubflow,
// delete: Prompt user for confirmation
delete: deleteSubflow,
refresh: refresh,
removeInput: removeSubflowInput,
removeOutput: removeSubflowOutput,

View File

@@ -43,12 +43,15 @@ RED.sidebar.config = (function() {
var categories = {};
function getOrCreateCategory(name,parent,label) {
function getOrCreateCategory(name,parent,label,isLocked) {
name = name.replace(/\./i,"-");
if (!categories[name]) {
var container = $('<div class="red-ui-palette-category red-ui-sidebar-config-category" id="red-ui-sidebar-config-category-'+name+'"></div>').appendTo(parent);
var header = $('<div class="red-ui-sidebar-config-tray-header red-ui-palette-header"><i class="fa fa-angle-down expanded"></i></div>').appendTo(container);
let lockIcon
if (label) {
lockIcon = $('<span style="margin-right: 5px"><i class="fa fa-lock"/></span>').appendTo(header)
lockIcon.toggle(!!isLocked)
$('<span class="red-ui-palette-node-config-label"/>').text(label).appendTo(header);
} else {
$('<span class="red-ui-palette-node-config-label" data-i18n="sidebar.config.'+name+'">').appendTo(header);
@@ -62,6 +65,7 @@ RED.sidebar.config = (function() {
var icon = header.find("i");
var result = {
label: label,
lockIcon,
list: category,
size: function() {
return result.list.find("li:not(.red-ui-palette-node-config-none)").length
@@ -100,6 +104,9 @@ RED.sidebar.config = (function() {
});
categories[name] = result;
} else {
if (isLocked !== undefined && categories[name].lockIcon) {
categories[name].lockIcon.toggle(!!isLocked)
}
if (categories[name].label !== label) {
categories[name].list.parent().find('.red-ui-palette-node-config-label').text(label);
categories[name].label = label;
@@ -216,7 +223,7 @@ RED.sidebar.config = (function() {
RED.nodes.eachWorkspace(function(ws) {
validList[ws.id.replace(/\./g,"-")] = true;
getOrCreateCategory(ws.id,flowCategories,ws.label);
getOrCreateCategory(ws.id,flowCategories,ws.label, ws.locked);
})
RED.nodes.eachSubflow(function(sf) {
validList[sf.id.replace(/\./g,"-")] = true;
@@ -274,6 +281,15 @@ RED.sidebar.config = (function() {
changes: {},
dirty: RED.nodes.dirty()
}
for (let i = 0; i < selectedNodes.length; i++) {
let node = RED.nodes.node(selectedNodes[i])
if (node.z) {
let ws = RED.nodes.workspace(node.z)
if (ws && ws.locked) {
return
}
}
}
selectedNodes.forEach(function(id) {
var node = RED.nodes.node(id);
try {

View File

@@ -141,7 +141,8 @@ RED.sidebar.help = (function() {
RED.events.on('registry:node-type-removed', queueRefresh);
RED.events.on('subflows:change', refreshSubflow);
RED.actions.add("core:show-help-tab",show);
RED.actions.add("core:show-help-tab", show);
RED.actions.add("core:show-node-help", showNodeHelp)
}
@@ -338,6 +339,19 @@ RED.sidebar.help = (function() {
resizeStack();
}
function showNodeHelp(node) {
if (!node) {
const selection = RED.view.selection()
if (selection.nodes && selection.nodes.length > 0) {
node = selection.nodes.find(n => n.type !== 'group' && n.type !== 'junction')
}
}
if (node) {
show(node.type, true)
}
}
// TODO: DRY - projects.js
function addTargetToExternalLinks(el) {
$(el).find("a").each(function(el) {

View File

@@ -221,6 +221,22 @@ RED.sidebar.info.outliner = (function() {
} else {
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
}
if (n.type === 'tab') {
var lockToggleButton = $('<button type="button" class="red-ui-info-outline-item-control-lock red-ui-button red-ui-button-small"><i class="fa fa-unlock-alt"></i><i class="fa fa-lock"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (n.locked) {
RED.workspaces.unlock(n.id)
} else {
RED.workspaces.lock(n.id)
}
})
RED.popover.tooltip(lockToggleButton,function() {
return RED._("common.label."+(n.locked?"unlock":"lock"));
});
} else {
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
}
controls.find("button").on("dblclick", function(evt) {
evt.preventDefault();
evt.stopPropagation();
@@ -364,6 +380,8 @@ RED.sidebar.info.outliner = (function() {
flowList.treeList.addChild(objects[ws.id])
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
objects[ws.id].element.toggleClass("red-ui-info-outline-item-locked", !!ws.locked)
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-locked", !!ws.locked)
updateSearch();
}
@@ -378,6 +396,8 @@ RED.sidebar.info.outliner = (function() {
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
existingObject.element.toggleClass("red-ui-info-outline-item-locked", !!n.locked)
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-locked", !!n.locked)
updateSearch();
}
function onFlowsReorder(order) {

View File

@@ -25,6 +25,7 @@ RED.sidebar.info = (function() {
var propertiesPanelHeaderLabel;
var propertiesPanelHeaderReveal;
var propertiesPanelHeaderHelp;
var propertiesPanelHeaderCopyLink;
var selectedObject;
@@ -67,10 +68,20 @@ RED.sidebar.info = (function() {
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderLabel = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
propertiesPanelHeaderCopyLink = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-link"></button>').css({
position: 'absolute',
top: '12px',
right: '32px'
}).on("click", function(evt) {
RED.actions.invoke('core:copy-item-url',selectedObject)
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderCopyLink,RED._("sidebar.info.copyItemUrl"));
propertiesPanelHeaderHelp = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
position: 'absolute',
top: '12px',
right: '56px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
@@ -80,8 +91,7 @@ RED.sidebar.info = (function() {
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
propertiesPanelHeaderReveal = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
position: 'absolute',
top: '12px',
right: '8px'
@@ -185,6 +195,7 @@ RED.sidebar.info = (function() {
propertiesPanelHeaderLabel.text("");
propertiesPanelHeaderReveal.hide();
propertiesPanelHeaderHelp.hide();
propertiesPanelHeaderCopyLink.hide();
return;
} else if (Array.isArray(node)) {
// Multiple things selected
@@ -196,6 +207,7 @@ RED.sidebar.info = (function() {
propertiesPanelHeaderLabel.text("Selection");
propertiesPanelHeaderReveal.hide();
propertiesPanelHeaderHelp.hide();
propertiesPanelHeaderCopyLink.hide();
selectedObject = null;
var types = {
@@ -277,9 +289,11 @@ RED.sidebar.info = (function() {
if (node.type === "tab" || node.type === "subflow") {
// If nothing is selected, but we're on a flow or subflow tab.
propertiesPanelHeaderHelp.hide();
propertiesPanelHeaderCopyLink.show();
} else if (node.type === "group") {
propertiesPanelHeaderHelp.hide();
propertiesPanelHeaderCopyLink.show();
propRow = $('<tr class="red-ui-help-info-row"><td>&nbsp;</td><td></td></tr>').appendTo(tableBody);
@@ -304,8 +318,10 @@ RED.sidebar.info = (function() {
}
} else if (node.type === 'junction') {
propertiesPanelHeaderHelp.hide();
propertiesPanelHeaderCopyLink.hide();
} else {
propertiesPanelHeaderHelp.show();
propertiesPanelHeaderCopyLink.show();
if (!subflowRegex) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+'</td><td></td></tr>').appendTo(tableBody);
@@ -447,7 +463,8 @@ RED.sidebar.info = (function() {
el = el.next();
}
$(this).toggleClass('expanded',!isExpanded);
})
});
mermaid.init();
}
var tips = (function() {

View File

@@ -435,10 +435,15 @@ RED.tourGuide = (function() {
function listTour() {
return [
{
id: "3_1",
label: "3.1",
path: "./tours/welcome.js"
},
{
id: "3_0",
label: "3.0",
path: "./tours/welcome.js"
path: "./tours/3.0/welcome.js"
},
{
id: "2_2",

View File

@@ -96,6 +96,37 @@ RED.utils = (function() {
}
}
var mermaidIsInitialized = false;
var mermaidIsEnabled /* = undefined */;
renderer.code = function (code, lang) {
if(lang === "mermaid") {
// mermaid diagram rendering
if (mermaidIsEnabled === undefined) {
if (RED.settings.markdownEditor &&
RED.settings.markdownEditor.mermaid) {
mermaidIsEnabled = RED.settings.markdownEditor.mermaid.enabled;
}
else {
mermaidIsEnabled = true;
}
}
if (mermaidIsEnabled) {
if (!mermaidIsInitialized) {
mermaidIsInitialized = true;
mermaid.initialize({startOnLoad:false});
}
return `<pre class='mermaid'>${code}</pre>`;
}
else {
return `<details><summary>${RED._("markdownEditor.mermaid.summary")}</summary><pre><code>${code}</code></pre></details>`;
}
}
else {
return "<pre><code>" +code +"</code></pre>";
}
};
window._marked.setOptions({
renderer: renderer,
gfm: true,

View File

@@ -15,7 +15,7 @@
**/
RED.view.tools = (function() {
'use strict';
function selectConnected(type) {
var selection = RED.view.selection();
var visited = new Set();
@@ -39,6 +39,9 @@ RED.view.tools = (function() {
}
function alignToGrid() {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
if (selection.nodes) {
var changedNodes = [];
@@ -87,6 +90,9 @@ RED.view.tools = (function() {
}
function moveSelection(dx,dy) {
if (RED.workspaces.isActiveLocked()) {
return
}
if (moving_set === null) {
moving_set = [];
var selection = RED.view.selection();
@@ -153,6 +159,9 @@ RED.view.tools = (function() {
}
function setSelectedNodeLabelState(labelShown) {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
var historyEvents = [];
var nodes = [];
@@ -439,6 +448,9 @@ RED.view.tools = (function() {
}
function alignSelectionToEdge(direction) {
// if (RED.workspaces.isActiveLocked()) {
// return
// }
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length > 1) {
@@ -539,8 +551,10 @@ RED.view.tools = (function() {
}
}
function distributeSelection(direction) {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length > 2) {
@@ -699,6 +713,9 @@ RED.view.tools = (function() {
}
function reorderSelection(dir) {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
if (selection.nodes) {
var nodesToMove = [];
@@ -734,8 +751,10 @@ RED.view.tools = (function() {
}
}
function wireSeriesOfNodes() {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
if (selection.nodes) {
if (selection.nodes.length > 1) {
@@ -776,6 +795,9 @@ RED.view.tools = (function() {
}
function wireNodeToMultiple() {
if (RED.workspaces.isActiveLocked()) {
return
}
var selection = RED.view.selection();
if (selection.nodes) {
if (selection.nodes.length > 1) {
@@ -823,6 +845,9 @@ RED.view.tools = (function() {
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
*/
function splitWiresWithLinkNodes(wires) {
if (RED.workspaces.isActiveLocked()) {
return
}
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
if (!wiresToSplit) {
return
@@ -877,7 +902,6 @@ RED.view.tools = (function() {
if(!nnLinkOut) {
const nLinkOut = RED.view.createNode("link out"); //create link node
nnLinkOut = nLinkOut.node;
nodeSrcMap[linkOutMapId] = nnLinkOut;
let yOffset = 0;
if(nSrc.outputs > 1) {
@@ -892,7 +916,8 @@ RED.view.tools = (function() {
updateNewNodePosXY(nSrc, nnLinkOut, false, RED.view.snapGrid, yOffset);
}
//add created node
RED.nodes.add(nnLinkOut);
nnLinkOut = RED.nodes.add(nnLinkOut);
nodeSrcMap[linkOutMapId] = nnLinkOut;
RED.editor.validateNode(nnLinkOut);
history.events.push(nLinkOut.historyEvent);
//connect node to link node
@@ -913,10 +938,10 @@ RED.view.tools = (function() {
if(!nnLinkIn) {
const nLinkIn = RED.view.createNode("link in"); //create link node
nnLinkIn = nLinkIn.node;
nodeTrgMap[nTrg.id] = nnLinkIn;
updateNewNodePosXY(nTrg, nnLinkIn, true, RED.view.snapGrid, 0);
//add created node
RED.nodes.add(nnLinkIn);
nnLinkIn = RED.nodes.add(nnLinkIn);
nodeTrgMap[nTrg.id] = nnLinkIn;
RED.editor.validateNode(nnLinkIn);
history.events.push(nLinkIn.historyEvent);
//connect node to link node
@@ -991,6 +1016,9 @@ RED.view.tools = (function() {
* @param {{ renameBlank: boolean, renameClash: boolean, generateHistory: boolean }} options Possible options are `renameBlank`, `renameClash` and `generateHistory`
*/
function generateNodeNames(node, options) {
if (RED.workspaces.isActiveLocked()) {
return
}
options = Object.assign({
renameBlank: true,
renameClash: true,
@@ -1061,6 +1089,9 @@ RED.view.tools = (function() {
}
function addJunctionsToWires(wires) {
if (RED.workspaces.isActiveLocked()) {
return
}
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
if (!wiresToSplit) {
return
@@ -1131,7 +1162,7 @@ RED.view.tools = (function() {
var nodeGroups = new Set()
RED.nodes.addJunction(junction)
junction = RED.nodes.addJunction(junction)
addedJunctions.push(junction)
let newLink
if (gid === links[0].source.id+":"+links[0].sourcePort) {
@@ -1192,6 +1223,30 @@ RED.view.tools = (function() {
RED.view.redraw(true);
}
function copyItemUrl(node, isEdit) {
if (!node) {
const selection = RED.view.selection();
if (selection.nodes && selection.nodes.length > 0) {
node = selection.nodes[0]
}
}
if (node) {
let thingType = 'node'
if (node.type === 'group') {
thingType = 'group'
} else if (node.type === 'tab' || node.type === 'subflow') {
thingType = 'flow'
}
let url = `${window.location.origin}${window.location.pathname}#${thingType}/${node.id}`
if (isEdit) {
url += '/edit'
}
if (RED.clipboard.copyText(url)) {
RED.notify(RED._("sidebar.info.copyURL2Clipboard"), { timeout: 2000 })
}
}
}
return {
init: function() {
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
@@ -1258,6 +1313,9 @@ RED.view.tools = (function() {
RED.actions.add("core:generate-node-names", generateNodeNames )
RED.actions.add("core:copy-item-url", function (node) { copyItemUrl(node) })
RED.actions.add("core:copy-item-edit-url", function (node) { copyItemUrl(node, true) })
// RED.actions.add("core:add-node", function() { addNode() })
},
/**

213
packages/node_modules/@node-red/editor-client/src/js/ui/view.js vendored Executable file → Normal file
View File

@@ -54,6 +54,7 @@ RED.view = (function() {
var spliceTimer;
var groupHoverTimer;
var activeFlowLocked = false;
var activeSubflow = null;
var activeNodes = [];
var activeLinks = [];
@@ -211,6 +212,7 @@ RED.view = (function() {
evt.preventDefault()
evt.stopPropagation()
RED.contextMenu.show({
type: 'workspace',
x:evt.clientX-5,
y:evt.clientY-5
})
@@ -410,8 +412,19 @@ RED.view = (function() {
activeSubflow = RED.nodes.subflow(event.workspace);
RED.menu.setDisabled("menu-item-workspace-edit", activeSubflow || event.workspace === 0);
RED.menu.setDisabled("menu-item-workspace-delete",event.workspace === 0 || RED.workspaces.count() == 1 || activeSubflow);
if (activeSubflow) {
activeFlowLocked = activeSubflow.locked
} else {
var activeWorkspace = RED.nodes.workspace(event.workspace)
if (activeWorkspace) {
activeFlowLocked = activeWorkspace.locked
} else {
activeFlowLocked = true
}
}
RED.menu.setDisabled("menu-item-workspace-edit", activeFlowLocked || activeSubflow || event.workspace === 0);
RED.menu.setDisabled("menu-item-workspace-delete",activeFlowLocked || event.workspace === 0 || RED.workspaces.count() == 1 || activeSubflow);
if (workspaceScrollPositions[event.workspace]) {
chart.scrollLeft(workspaceScrollPositions[event.workspace].left);
@@ -438,6 +451,15 @@ RED.view = (function() {
redraw();
});
RED.events.on("flows:change", function(workspace) {
if (workspace.id === RED.workspaces.active()) {
activeFlowLocked = !!workspace.locked
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked);
}
})
RED.statusBar.add({
id: "view-zoom-controls",
align: "right",
@@ -495,6 +517,9 @@ RED.view = (function() {
chart.droppable({
accept:".red-ui-palette-node",
drop: function( event, ui ) {
if (activeFlowLocked) {
return
}
d3.event = event;
var selected_tool = $(ui.draggable[0]).attr("data-palette-type");
var result = createNode(selected_tool);
@@ -502,9 +527,7 @@ RED.view = (function() {
return;
}
var historyEvent = result.historyEvent;
var nn = result.node;
RED.nodes.add(nn);
var nn = RED.nodes.add(result.node);
var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
@@ -631,6 +654,9 @@ RED.view = (function() {
RED.actions.add("core:copy-selection-to-internal-clipboard",copySelection);
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection(true);deleteSelection();});
RED.actions.add("core:paste-from-internal-clipboard",function(){
if (RED.workspaces.isActiveLocked()) {
return
}
importNodes(clipboard,{generateIds: clipboardSource === 'copy', generateDefaultNames: clipboardSource === 'copy'});
});
@@ -639,22 +665,27 @@ RED.view = (function() {
RED.events.on("view:selection-changed", function(selection) {
var hasSelection = (selection.nodes && selection.nodes.length > 0);
var hasMultipleSelection = hasSelection && selection.nodes.length > 1;
RED.menu.setDisabled("menu-item-edit-cut",!hasSelection);
RED.menu.setDisabled("menu-item-edit-copy",!hasSelection);
RED.menu.setDisabled("menu-item-edit-select-connected",!hasSelection);
RED.menu.setDisabled("menu-item-view-tools-move-to-back",!hasSelection);
RED.menu.setDisabled("menu-item-view-tools-move-to-front",!hasSelection);
RED.menu.setDisabled("menu-item-view-tools-move-backwards",!hasSelection);
RED.menu.setDisabled("menu-item-view-tools-move-forwards",!hasSelection);
var hasLinkSelected = selection.links && selection.links.length > 0;
var canEdit = !activeFlowLocked && hasSelection
var canEditMultiple = !activeFlowLocked && hasMultipleSelection
RED.menu.setDisabled("menu-item-edit-cut", !canEdit);
RED.menu.setDisabled("menu-item-edit-copy", !hasSelection);
RED.menu.setDisabled("menu-item-edit-select-connected", !hasSelection);
RED.menu.setDisabled("menu-item-view-tools-move-to-back", !canEdit);
RED.menu.setDisabled("menu-item-view-tools-move-to-front", !canEdit);
RED.menu.setDisabled("menu-item-view-tools-move-backwards", !canEdit);
RED.menu.setDisabled("menu-item-view-tools-move-forwards", !canEdit);
RED.menu.setDisabled("menu-item-view-tools-align-left",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-align-center",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-align-right",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-align-top",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-align-middle",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-align-bottom",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-distribute-horizontally",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-distribute-veritcally",!hasMultipleSelection);
RED.menu.setDisabled("menu-item-view-tools-align-left", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-align-center", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-align-right", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-align-top", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-align-middle", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-align-bottom", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-distribute-horizontally", !canEditMultiple);
RED.menu.setDisabled("menu-item-view-tools-distribute-veritcally", !canEditMultiple);
RED.menu.setDisabled("menu-item-edit-split-wire-with-links", activeFlowLocked || !hasLinkSelected);
})
RED.actions.add("core:delete-selection",deleteSelection);
@@ -1044,7 +1075,7 @@ RED.view = (function() {
.attr("class", "nr-ui-view-lasso");
d3.event.preventDefault();
}
} else if (d3.event.altKey) {
} else if (d3.event.altKey && !activeFlowLocked) {
//Alt [+shift] held - Begin slicing
clearSelection();
mouse_mode = (d3.event.shiftKey) ? RED.state.SLICING_JUNCTION : RED.state.SLICING;
@@ -1058,6 +1089,9 @@ RED.view = (function() {
}
function showQuickAddDialog(options) {
if (activeFlowLocked) {
return
}
options = options || {};
var point = options.position || lastClickPosition;
var spliceLink = options.splice;
@@ -1240,6 +1274,11 @@ RED.view = (function() {
if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
nn.l = showLabel;
}
if (nn.type === 'junction') {
nn = RED.nodes.addJunction(nn);
} else {
nn = RED.nodes.add(nn);
}
if (quickAddLink) {
var drag_line = quickAddLink;
var src = null,dst,src_port;
@@ -1342,11 +1381,7 @@ RED.view = (function() {
}
}
}
if (nn.type === 'junction') {
RED.nodes.addJunction(nn);
} else {
RED.nodes.add(nn);
}
RED.editor.validateNode(nn);
if (targetGroup) {
@@ -1604,16 +1639,18 @@ RED.view = (function() {
}
var d = (mouse_offset[0]-mousePos[0])*(mouse_offset[0]-mousePos[0]) + (mouse_offset[1]-mousePos[1])*(mouse_offset[1]-mousePos[1]);
if ((d > 3 && !dblClickPrimed) || (dblClickPrimed && d > 10)) {
mouse_mode = RED.state.MOVING_ACTIVE;
clickElapsed = 0;
spliceActive = false;
if (movingSet.length() === 1) {
node = movingSet.get(0);
spliceActive = node.n.hasOwnProperty("_def") &&
((node.n.hasOwnProperty("inputs") && node.n.inputs > 0) || (!node.n.hasOwnProperty("inputs") && node.n._def.inputs > 0)) &&
((node.n.hasOwnProperty("outputs") && node.n.outputs > 0) || (!node.n.hasOwnProperty("outputs") && node.n._def.outputs > 0)) &&
RED.nodes.filterLinks({ source: node.n }).length === 0 &&
RED.nodes.filterLinks({ target: node.n }).length === 0;
if (!activeFlowLocked) {
mouse_mode = RED.state.MOVING_ACTIVE;
spliceActive = false;
if (movingSet.length() === 1) {
node = movingSet.get(0);
spliceActive = node.n.hasOwnProperty("_def") &&
((node.n.hasOwnProperty("inputs") && node.n.inputs > 0) || (!node.n.hasOwnProperty("inputs") && node.n._def.inputs > 0)) &&
((node.n.hasOwnProperty("outputs") && node.n.outputs > 0) || (!node.n.hasOwnProperty("outputs") && node.n._def.outputs > 0)) &&
RED.nodes.filterLinks({ source: node.n }).length === 0 &&
RED.nodes.filterLinks({ target: node.n }).length === 0;
}
}
}
} else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING || mouse_mode == RED.state.DETACHED_DRAGGING) {
@@ -2458,6 +2495,7 @@ RED.view = (function() {
}
function editSelection() {
if (RED.workspaces.isActiveLocked()) { return }
if (movingSet.length() > 0) {
var node = movingSet.get(0).n;
if (node.type === "subflow") {
@@ -2473,6 +2511,9 @@ RED.view = (function() {
if (mouse_mode === RED.state.SELECTING_NODE) {
return;
}
if (activeFlowLocked) {
return
}
if (portLabelHover) {
portLabelHover.remove();
portLabelHover = null;
@@ -2788,6 +2829,7 @@ RED.view = (function() {
function detachSelectedNodes() {
if (RED.workspaces.isActiveLocked()) { return }
var selection = RED.view.selection();
if (selection.nodes) {
const {newLinks, removedLinks} = RED.nodes.detachNodes(selection.nodes);
@@ -2929,7 +2971,7 @@ RED.view = (function() {
mousedown_node = d;
mousedown_port_type = portType;
mousedown_port_index = portIndex || 0;
if (mouse_mode !== RED.state.QUICK_JOINING) {
if (mouse_mode !== RED.state.QUICK_JOINING && !activeFlowLocked) {
mouse_mode = RED.state.JOINING;
document.body.style.cursor = "crosshair";
if (evt.ctrlKey || evt.metaKey) {
@@ -3369,6 +3411,14 @@ RED.view = (function() {
}
if (dblClickPrimed && mousedown_node == d && clickElapsed > 0 && clickElapsed < dblClickInterval) {
mouse_mode = RED.state.DEFAULT;
if (RED.workspaces.isActiveLocked()) {
clickElapsed = 0;
d3.event.stopPropagation();
return
}
// Avoid dbl click causing text selection.
d3.event.preventDefault()
document.getSelection().removeAllRanges()
if (d.type != "subflow") {
if (/^subflow:/.test(d.type) && (d3.event.ctrlKey || d3.event.metaKey)) {
RED.workspaces.show(d.type.substring(8));
@@ -3692,7 +3742,6 @@ RED.view = (function() {
}
// selectedLinks.clear();
if (d3.event.button != 2) {
mouse_mode = RED.state.MOVING;
var mouse = d3.touches(this)[0]||d3.mouse(this);
mouse[0] += d.x-d.w/2;
mouse[1] += d.y-d.h/2;
@@ -3885,6 +3934,7 @@ RED.view = (function() {
if (RED.view.DEBUG) {
console.warn("groupMouseUp", { mouse_mode, event: d3.event });
}
if (RED.workspaces.isActiveLocked()) { return }
if (dblClickPrimed && mousedown_group == g && clickElapsed > 0 && clickElapsed < dblClickInterval) {
mouse_mode = RED.state.DEFAULT;
RED.editor.editGroup(g);
@@ -4055,7 +4105,7 @@ RED.view = (function() {
function isButtonEnabled(d) {
var buttonEnabled = true;
var ws = RED.nodes.workspace(RED.workspaces.active());
if (ws && !ws.disabled && !d.d) {
if (ws && !ws.disabled && !d.d && !ws.locked) {
if (d._def.button.hasOwnProperty('enabled')) {
if (typeof d._def.button.enabled === "function") {
buttonEnabled = d._def.button.enabled.call(d);
@@ -4078,7 +4128,7 @@ RED.view = (function() {
}
var activeWorkspace = RED.workspaces.active();
var ws = RED.nodes.workspace(activeWorkspace);
if (ws && !ws.disabled && !d.d) {
if (ws && !ws.disabled && !d.d && !ws.locked) {
if (d._def.button.toggle) {
d[d._def.button.toggle] = !d[d._def.button.toggle];
d.dirty = true;
@@ -4093,7 +4143,7 @@ RED.view = (function() {
if (d.dirty) {
redraw();
}
} else {
} else if (!ws || !ws.locked){
if (activeSubflow) {
RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.nodeActionDisabledSubflow")}),"warning");
} else {
@@ -4108,14 +4158,15 @@ RED.view = (function() {
function showTouchMenu(obj,pos) {
var mdn = mousedown_node;
var options = [];
options.push({name:"delete",disabled:(movingSet.length()===0 && selectedLinks.length() === 0),onselect:function() {deleteSelection();}});
options.push({name:"cut",disabled:(movingSet.length()===0),onselect:function() {copySelection(true);deleteSelection();}});
options.push({name:"copy",disabled:(movingSet.length()===0),onselect:function() {copySelection();}});
options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard, {generateIds: true, touchImport: true});}});
options.push({name:"edit",disabled:(movingSet.length() != 1),onselect:function() { RED.editor.edit(mdn);}});
const isActiveLocked = RED.workspaces.isActiveLocked()
options.push({name:"delete",disabled:(isActiveLocked || movingSet.length()===0 && selectedLinks.length() === 0),onselect:function() {deleteSelection();}});
options.push({name:"cut",disabled:(isActiveLocked || movingSet.length()===0),onselect:function() {copySelection(true);deleteSelection();}});
options.push({name:"copy",disabled:(isActiveLocked || movingSet.length()===0),onselect:function() {copySelection();}});
options.push({name:"paste",disabled:(isActiveLocked || clipboard.length===0),onselect:function() {importNodes(clipboard, {generateIds: true, touchImport: true});}});
options.push({name:"edit",disabled:(isActiveLocked || movingSet.length() != 1),onselect:function() { RED.editor.edit(mdn);}});
options.push({name:"select",onselect:function() {selectAll();}});
options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
options.push({name:"add",onselect:function() {
options.push({name:"add",disabled:isActiveLocked, onselect:function() {
chartPos = chart.offset();
showQuickAddDialog({
position:[pos[0]-chartPos.left+chart.scrollLeft(),pos[1]-chartPos.top+chart.scrollTop()],
@@ -5606,7 +5657,24 @@ RED.view = (function() {
if (activeSubflow) {
activeSubflowChanged = activeSubflow.changed;
}
var result = RED.nodes.import(nodesToImport,{generateIds:options.generateIds, addFlow: addNewFlow, importMap: options.importMap});
var filteredNodesToImport = nodesToImport;
var globalConfig = null;
var gconf = null;
RED.nodes.eachConfig(function (conf) {
if (conf.type === "global-config") {
gconf = conf;
}
});
if (gconf) {
filteredNodesToImport = nodesToImport.filter(function (n) {
return (n.type !== "global-config");
});
globalConfig = nodesToImport.find(function (n) {
return (n.type === "global-config");
});
}
var result = RED.nodes.import(filteredNodesToImport,{generateIds:options.generateIds, addFlow: addNewFlow, importMap: options.importMap});
if (result) {
var new_nodes = result.nodes;
var new_links = result.links;
@@ -5738,6 +5806,50 @@ RED.view = (function() {
}
}
if (globalConfig) {
// merge global env to existing global-config
var env0 = gconf.env;
var env1 = globalConfig.env;
var newEnv = Array.from(env0);
var changed = false;
env1.forEach(function (item1) {
var index = newEnv.findIndex(function (item0) {
return (item0.name === item1.name);
});
if (index >= 0) {
var item0 = newEnv[index];
if ((item0.type !== item1.type) ||
(item0.value !== item1.value)) {
newEnv[index] = item1;
changed = true;
}
}
else {
newEnv.push(item1);
changed = true;
}
});
if(changed) {
gconf.env = newEnv;
var replaceEvent = {
t: "edit",
node: gconf,
changed: true,
changes: {
env: env0
}
};
historyEvent = {
t:"multi",
events: [
replaceEvent,
historyEvent,
]
};
}
}
RED.history.push(historyEvent);
updateActiveNodes();
@@ -5813,6 +5925,9 @@ RED.view = (function() {
if (mouse_mode === RED.state.SELECTING_NODE) {
return;
}
if (activeFlowLocked) {
return
}
var workspaceSelection = RED.workspaces.selection();
var changed = false;
if (workspaceSelection.length > 0) {
@@ -6140,7 +6255,9 @@ RED.view = (function() {
if (node.z && (node.type === "group" || node._def.category !== 'config')) {
node.dirty = true;
RED.workspaces.show(node.z);
if (node.type === "group" && !node.w && !node.h) {
_redraw();
}
var screenSize = [chart[0].clientWidth/scaleFactor,chart[0].clientHeight/scaleFactor];
var scrollPos = [chart.scrollLeft()/scaleFactor,chart.scrollTop()/scaleFactor];
var cx = node.x;

View File

@@ -58,6 +58,9 @@ RED.workspaces = (function() {
if (!ws.closeable) {
ws.hideable = true;
}
if (!ws.hasOwnProperty('locked')) {
ws.locked = false
}
workspace_tabs.addTab(ws,targetIndex);
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
@@ -75,6 +78,7 @@ RED.workspaces = (function() {
type: "tab",
id: tabId,
disabled: false,
locked: false,
info: "",
label: RED._('workspace.defaultName',{number:workspaceIndex}),
env: [],
@@ -99,6 +103,9 @@ RED.workspaces = (function() {
if (workspaceTabCount === 1) {
return;
}
if (ws.locked) {
return
}
var workspaceOrder = RED.nodes.getWorkspaceOrder();
ws._index = workspaceOrder.indexOf(ws.id);
removeWorkspace(ws);
@@ -119,13 +126,206 @@ RED.workspaces = (function() {
RED.editor.editSubflow(subflow);
}
} else {
RED.editor.editFlow(workspace);
if (!workspace.locked) {
RED.editor.editFlow(workspace);
}
}
}
var workspace_tabs;
var workspaceTabCount = 0;
function getMenuItems(isMenuButton, tab) {
let hiddenFlows = new Set()
for (let i = 0; i < hideStack.length; i++) {
let ids = hideStack[i]
if (!Array.isArray(ids)) {
ids = [ids]
}
ids.forEach(id => {
if (RED.nodes.workspace(id)) {
hiddenFlows.add(id)
}
})
}
const hiddenflowCount = hiddenFlows.size;
let activeWorkspace = tab || RED.nodes.workspace(RED.workspaces.active()) || RED.nodes.subflow(RED.workspaces.active())
let isFlowDisabled = activeWorkspace ? activeWorkspace.disabled : false
const currentTabs = workspace_tabs.listTabs();
let flowCount = 0;
currentTabs.forEach(tab => {
if (RED.nodes.workspace(tab)) {
flowCount++;
}
});
let isCurrentLocked = RED.workspaces.isActiveLocked()
if (tab) {
isCurrentLocked = tab.locked
}
var menuItems = []
if (isMenuButton) {
menuItems.push({
id:"red-ui-tabs-menu-option-search-flows",
label: RED._("workspace.listFlows"),
onselect: "core:list-flows"
},
{
id:"red-ui-tabs-menu-option-search-subflows",
label: RED._("workspace.listSubflows"),
onselect: "core:list-subflows"
},
null)
}
menuItems.push(
{
id:"red-ui-tabs-menu-option-add-flow",
label: RED._("workspace.addFlow"),
onselect: "core:add-flow"
}
)
if (isMenuButton || !!tab) {
menuItems.push(
{
id:"red-ui-tabs-menu-option-add-flow-right",
label: RED._("workspace.addFlowToRight"),
shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"),
onselect: function() {
RED.actions.invoke("core:add-flow-to-right", tab)
}
},
null
)
if (activeWorkspace && activeWorkspace.type === 'tab') {
menuItems.push(
isFlowDisabled ? {
label: RED._("workspace.enableFlow"),
shortcut: RED.keyboard.getShortcut("core:enable-flow"),
onselect: function() {
RED.actions.invoke("core:enable-flow", tab?tab.id:undefined)
},
disabled: isCurrentLocked
} : {
label: RED._("workspace.disableFlow"),
shortcut: RED.keyboard.getShortcut("core:disable-flow"),
onselect: function() {
RED.actions.invoke("core:disable-flow", tab?tab.id:undefined)
},
disabled: isCurrentLocked
},
isCurrentLocked? {
label: RED._("workspace.unlockFlow"),
shortcut: RED.keyboard.getShortcut("core:unlock-flow"),
onselect: function() {
RED.actions.invoke('core:unlock-flow', tab?tab.id:undefined)
}
} : {
label: RED._("workspace.lockFlow"),
shortcut: RED.keyboard.getShortcut("core:lock-flow"),
onselect: function() {
RED.actions.invoke('core:lock-flow', tab?tab.id:undefined)
}
},
null
)
}
const activeIndex = currentTabs.findIndex(id => (activeWorkspace && (id === activeWorkspace.id)));
menuItems.push(
{
label: RED._("workspace.moveToStart"),
shortcut: RED.keyboard.getShortcut("core:move-flow-to-start"),
onselect: function() {
RED.actions.invoke("core:move-flow-to-start", tab?tab.id:undefined)
},
disabled: activeIndex === 0
},
{
label: RED._("workspace.moveToEnd"),
shortcut: RED.keyboard.getShortcut("core:move-flow-to-end"),
onselect: function() {
RED.actions.invoke("core:move-flow-to-end", tab?tab.id:undefined)
},
disabled: activeIndex === currentTabs.length - 1
}
)
}
menuItems.push(null)
if (isMenuButton || !!tab) {
menuItems.push(
{
id:"red-ui-tabs-menu-option-add-hide-flows",
label: RED._("workspace.hideFlow"),
shortcut: RED.keyboard.getShortcut("core:hide-flow"),
onselect: function() {
RED.actions.invoke("core:hide-flow", tab)
}
},
{
id:"red-ui-tabs-menu-option-add-hide-other-flows",
label: RED._("workspace.hideOtherFlows"),
shortcut: RED.keyboard.getShortcut("core:hide-other-flows"),
onselect: function() {
RED.actions.invoke("core:hide-other-flows", tab)
}
}
)
}
menuItems.push(
{
id:"red-ui-tabs-menu-option-add-hide-all-flows",
label: RED._("workspace.hideAllFlows"),
onselect: "core:hide-all-flows",
disabled: (hiddenflowCount === flowCount)
},
{
id:"red-ui-tabs-menu-option-add-show-all-flows",
disabled: hiddenflowCount === 0,
label: RED._("workspace.showAllFlows", { count: hiddenflowCount }),
onselect: "core:show-all-flows"
},
{
id:"red-ui-tabs-menu-option-add-show-last-flow",
disabled: hideStack.length === 0,
label: RED._("workspace.showLastHiddenFlow"),
onselect: "core:show-last-hidden-flow"
}
)
if (tab) {
menuItems.push(
null,
{
label: RED._("common.label.delete"),
onselect: function() {
if (tab.type === 'tab') {
RED.workspaces.delete(tab)
} else if (tab.type === 'subflow') {
RED.subflow.delete(tab.id)
}
},
disabled: isCurrentLocked || (workspaceTabCount === 1)
},
{
label: RED._("menu.label.export"),
shortcut: RED.keyboard.getShortcut("core:show-export-dialog"),
onselect: function() {
RED.workspaces.show(tab.id)
RED.actions.invoke('core:show-export-dialog', null, 'flow')
}
}
)
}
// if (isMenuButton && hiddenflowCount > 0) {
// menuItems.unshift({
// label: RED._("workspace.hiddenFlows",{count: hiddenflowCount}),
// onselect: "core:list-hidden-flows"
// })
// }
return menuItems;
}
function createWorkspaceTabs() {
workspace_tabs = RED.tabs.create({
id: "red-ui-workspace-tabs",
@@ -137,8 +337,9 @@ RED.workspaces = (function() {
$("#red-ui-workspace-chart").show();
activeWorkspace = tab.id;
window.location.hash = 'flow/'+tab.id;
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!tab.disabled);
} else {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked", !!tab.locked);
} else {
$("#red-ui-workspace-chart").hide();
activeWorkspace = 0;
window.location.hash = '';
@@ -169,6 +370,12 @@ RED.workspaces = (function() {
if (tab.disabled) {
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-disabled');
}
$('<span class="red-ui-workspace-locked-icon"><i class="fa fa-lock"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label");
if (tab.locked) {
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-locked');
}
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
if (workspaceTabCount === 1) {
showWorkspace();
@@ -189,13 +396,19 @@ RED.workspaces = (function() {
RED.history.push({
t:'reorder',
workspaces: {
from:oldOrder,
to:newOrder
from: oldOrder,
to: newOrder
},
dirty:RED.nodes.dirty()
});
RED.nodes.dirty(true);
setWorkspaceOrder(newOrder);
// Only mark flows dirty if flow-order has changed (excluding subflows)
const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id))
const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id))
if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) {
RED.nodes.dirty(true);
setWorkspaceOrder(newOrder);
}
},
onselect: function(selectedTabs) {
RED.view.select(false)
@@ -214,12 +427,12 @@ RED.workspaces = (function() {
},
onhide: function(tab) {
hideStack.push(tab.id);
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
hiddenTabs[tab.id] = true;
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
RED.events.emit("workspace:hide",{workspace: tab.id})
if (tab.type === "tab") {
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
hiddenTabs[tab.id] = true;
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
RED.events.emit("workspace:hide",{workspace: tab.id})
}
},
onshow: function(tab) {
removeFromHideStack(tab.id);
@@ -234,77 +447,8 @@ RED.workspaces = (function() {
scrollable: true,
addButton: "core:add-flow",
addButtonCaption: RED._("workspace.addFlow"),
menu: function() {
var menuItems = [
{
id:"red-ui-tabs-menu-option-search-flows",
label: RED._("workspace.listFlows"),
onselect: "core:list-flows"
},
{
id:"red-ui-tabs-menu-option-search-subflows",
label: RED._("workspace.listSubflows"),
onselect: "core:list-subflows"
},
null,
{
id:"red-ui-tabs-menu-option-add-flow",
label: RED._("workspace.addFlow"),
onselect: "core:add-flow"
},
{
id:"red-ui-tabs-menu-option-add-flow-right",
label: RED._("workspace.addFlowToRight"),
onselect: "core:add-flow-to-right"
},
null,
{
id:"red-ui-tabs-menu-option-add-hide-flows",
label: RED._("workspace.hideFlow"),
onselect: "core:hide-flow"
},
{
id:"red-ui-tabs-menu-option-add-hide-other-flows",
label: RED._("workspace.hideOtherFlows"),
onselect: "core:hide-other-flows"
},
{
id:"red-ui-tabs-menu-option-add-show-all-flows",
label: RED._("workspace.showAllFlows"),
onselect: "core:show-all-flows"
},
{
id:"red-ui-tabs-menu-option-add-hide-all-flows",
label: RED._("workspace.hideAllFlows"),
onselect: "core:hide-all-flows"
},
{
id:"red-ui-tabs-menu-option-add-show-last-flow",
label: RED._("workspace.showLastHiddenFlow"),
onselect: "core:show-last-hidden-flow"
}
]
let hiddenFlows = new Set()
for (let i = 0; i < hideStack.length; i++) {
let ids = hideStack[i]
if (!Array.isArray(ids)) {
ids = [ids]
}
ids.forEach(id => {
if (RED.nodes.workspace(id)) {
hiddenFlows.add(id)
}
})
}
const flowCount = hiddenFlows.size;
if (flowCount > 0) {
menuItems.unshift({
label: RED._("workspace.hiddenFlows",{count: flowCount}),
onselect: "core:list-hidden-flows"
})
}
return menuItems;
}
menu: function() { return getMenuItems(true) },
contextmenu: function(tab) { return getMenuItems(false, tab) }
});
workspaceTabCount = 0;
}
@@ -355,16 +499,33 @@ RED.workspaces = (function() {
});
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
RED.actions.add("core:add-flow-to-right",function(opts) { addWorkspace(undefined,undefined,workspace_tabs.activeIndex()+1)});
RED.actions.add("core:add-flow-to-right",function(workspace) {
let index
if (workspace) {
index = workspace_tabs.getTabIndex(workspace.id)+1
} else {
index = workspace_tabs.activeIndex()+1
}
addWorkspace(undefined,undefined,index)
});
RED.actions.add("core:edit-flow",editWorkspace);
RED.actions.add("core:remove-flow",removeWorkspace);
RED.actions.add("core:enable-flow",enableWorkspace);
RED.actions.add("core:disable-flow",disableWorkspace);
RED.actions.add("core:lock-flow",lockWorkspace);
RED.actions.add("core:unlock-flow",unlockWorkspace);
RED.actions.add("core:move-flow-to-start", function(id) { moveWorkspace(id, 'start') });
RED.actions.add("core:move-flow-to-end", function(id) { moveWorkspace(id, 'end') });
RED.actions.add("core:hide-flow", function() {
var selection = workspace_tabs.selection();
if (selection.length === 0) {
selection = [{id:activeWorkspace}]
RED.actions.add("core:hide-flow", function(workspace) {
let selection
if (workspace) {
selection = [workspace]
} else {
selection = workspace_tabs.selection();
if (selection.length === 0) {
selection = [{id:activeWorkspace}]
}
}
var hiddenTabs = [];
selection.forEach(function(ws) {
@@ -378,10 +539,15 @@ RED.workspaces = (function() {
workspace_tabs.clearSelection();
})
RED.actions.add("core:hide-other-flows", function() {
var selection = workspace_tabs.selection();
if (selection.length === 0) {
selection = [{id:activeWorkspace}]
RED.actions.add("core:hide-other-flows", function(workspace) {
let selection
if (workspace) {
selection = [workspace]
} else {
selection = workspace_tabs.selection();
if (selection.length === 0) {
selection = [{id:activeWorkspace}]
}
}
var selected = new Set(selection.map(function(ws) { return ws.id }))
@@ -486,7 +652,7 @@ RED.workspaces = (function() {
}
function setWorkspaceState(id,disabled) {
var workspace = RED.nodes.workspace(id||activeWorkspace);
if (!workspace) {
if (!workspace || workspace.locked) {
return;
}
if (workspace.disabled !== disabled) {
@@ -521,11 +687,58 @@ RED.workspaces = (function() {
}
}
}
function lockWorkspace(id) {
setWorkspaceLockState(id,true);
}
function unlockWorkspace(id) {
setWorkspaceLockState(id,false);
}
function setWorkspaceLockState(id,locked) {
var workspace = RED.nodes.workspace(id||activeWorkspace);
if (!workspace) {
return;
}
if (workspace.locked !== locked) {
var changes = { locked: workspace.locked };
workspace.locked = locked;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked);
if (!id || (id === activeWorkspace)) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked);
}
var historyEvent = {
t: "edit",
changes:changes,
node: workspace,
dirty: RED.nodes.dirty()
}
workspace.changed = true;
RED.history.push(historyEvent);
RED.events.emit("flows:change",workspace);
RED.nodes.dirty(true);
// RED.sidebar.config.refresh();
// var selection = RED.view.selection();
// if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
// RED.sidebar.info.refresh(workspace);
// }
// if (changes.hasOwnProperty('disabled')) {
// RED.nodes.eachNode(function(n) {
// if (n.z === workspace.id) {
// n.dirty = true;
// }
// });
// RED.view.redraw();
// }
}
}
function removeWorkspace(ws) {
if (!ws) {
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
ws = RED.nodes.workspace(activeWorkspace)
if (ws && !ws.locked) {
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
}
} else {
if (ws.locked) { return }
if (workspace_tabs.contains(ws.id)) {
workspace_tabs.removeTab(ws.id);
}
@@ -535,16 +748,46 @@ RED.workspaces = (function() {
}
}
function moveWorkspace(id, direction) {
const workspace = RED.nodes.workspace(id||activeWorkspace) || RED.nodes.subflow(id||activeWorkspace);
if (!workspace) {
return;
}
const currentOrder = workspace_tabs.listTabs()
const oldOrder = [...currentOrder]
const currentIndex = currentOrder.findIndex(id => id === workspace.id)
currentOrder.splice(currentIndex, 1)
if (direction === 'start') {
currentOrder.unshift(workspace.id)
} else if (direction === 'end') {
currentOrder.push(workspace.id)
}
const newOrder = setWorkspaceOrder(currentOrder)
if (JSON.stringify(newOrder) !== JSON.stringify(oldOrder)) {
RED.history.push({
t:'reorder',
workspaces: {
from:oldOrder,
to:newOrder
},
dirty:RED.nodes.dirty()
});
const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id))
const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id))
if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) {
RED.nodes.dirty(true);
}
}
}
function setWorkspaceOrder(order) {
var newOrder = order.filter(function(id) {
return RED.nodes.workspace(id) !== undefined;
})
var newOrder = order.filter(id => !!RED.nodes.workspace(id))
var currentOrder = RED.nodes.getWorkspaceOrder();
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
RED.nodes.setWorkspaceOrder(newOrder);
RED.events.emit("flows:reorder",newOrder);
}
workspace_tabs.order(order);
return newOrder
}
function flashTab(tabId) {
@@ -590,6 +833,10 @@ RED.workspaces = (function() {
active: function() {
return activeWorkspace
},
isActiveLocked: function() {
var ws = RED.nodes.workspace(activeWorkspace) || RED.nodes.subflow(activeWorkspace)
return ws && ws.locked
},
selection: function() {
return workspace_tabs.selection();
},
@@ -646,6 +893,8 @@ RED.workspaces = (function() {
workspace_tabs.resize();
},
enable: enableWorkspace,
disable: disableWorkspace
disable: disableWorkspace,
lock: lockWorkspace,
unlock: unlockWorkspace
}
})();

View File

@@ -37,3 +37,27 @@
}
}
}
#red-ui-image-drop-target {
position: absolute;
top: 0; bottom: 0;
left: 0; right: 0;
background: var(--red-ui-dnd-background);
display:table;
width: 100%;
height: 100%;
display: none;
z-index:100;
div {
pointer-events: none;
display: table-cell;
vertical-align: middle;
text-align: center;
font-size: 40px;
color: var(--red-ui-dnd-color);
i {
pointer-events: none;
font-size: 80px;
}
}
}

View File

@@ -68,6 +68,9 @@
stroke: var(--red-ui-node-border);
cursor: move;
stroke-width: 1;
.red-ui-workspace-locked & {
cursor: pointer;
}
}
.red-ui-workspace-select-mode {
g.red-ui-flow-node.red-ui-flow-node-hovered * {
@@ -287,9 +290,11 @@ g.red-ui-flow-node-selected {
text-anchor:start;
}
.red-ui-flow-port-hovered {
stroke: var(--red-ui-port-selected-color);
fill: var(--red-ui-port-selected-color);
#red-ui-workspace:not(.red-ui-workspace-locked) {
.red-ui-flow-port-hovered {
stroke: var(--red-ui-port-selected-color);
fill: var(--red-ui-port-selected-color);
}
}
.red-ui-flow-subflow-port {

View File

@@ -32,7 +32,8 @@
color: var(--red-ui-primary-text-color);
border: 1px solid var(--red-ui-notification-border-default);
border-left-width: 16px;
overflow: hidden;
overflow: scroll;
max-height: 80vh;
.ui-dialog-buttonset {
margin-top: 20px;
margin-bottom: 10px;

View File

@@ -41,6 +41,7 @@
height: 50px;
background: var(--red-ui-secondary-background);
border: 2px solid var(--red-ui-primary-border-color);
color: var(--red-ui-primary-text-color);
text-align: center;
line-height:50px;
@@ -51,7 +52,7 @@
.red-ui-editor-radial-menu-opt-disabled {
border-color: var(--red-ui-tertiary-border-color);
color: var(--red-ui-tertiary-border-color);
color: var(--red-ui-secondary-text-color-disabled);
}
.red-ui-editor-radial-menu-opt-active {
background: var(--red-ui-secondary-background-hover);

View File

@@ -467,6 +467,9 @@ div.red-ui-info-table {
.fa-eye {
display: none;
}
.fa-unlock-alt {
display: none;
}
}
.red-ui-info-outline-item-control-reveal,
.red-ui-info-outline-item-control-action {
@@ -500,6 +503,25 @@ div.red-ui-info-table {
display: none;
}
}
.fa-lock {
display: none;
}
.red-ui-info-outline-item.red-ui-info-outline-item-locked & {
.fa-lock {
display: inline-block;
}
.fa-unlock-alt {
display: none;
}
}
// If the parent is locked, do not show the display/action buttons when
// hovering in the outline
.red-ui-info-outline-item-locked .red-ui-info-outline-item & {
.red-ui-info-outline-item-control-disable,
.red-ui-info-outline-item-control-action {
display: none;
}
}
button {
margin-right: 3px
}
@@ -517,8 +539,6 @@ div.red-ui-info-table {
}
}
.red-ui-icons {
display: inline-block;
width: 18px;

View File

@@ -106,6 +106,28 @@
}
}
.red-ui-workspace-locked-icon {
display: none;
}
.red-ui-workspace-locked {
&.red-ui-tab {
// border-top-style: dashed;
// border-left-style: dashed;
// border-right-style: dashed;
// a {
// font-style: italic;
// color: var(--red-ui-tab-text-color-disabled-inactive) !important;
// }
// &.active a {
// font-weight: normal;
// color: var(--red-ui-tab-text-color-disabled-active) !important;
// }
.red-ui-workspace-locked-icon {
display: inline;
}
}
}
#red-ui-navigator-canvas {
position: absolute;

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -0,0 +1,155 @@
export default {
version: "3.0.0",
steps: [
{
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 3.0!",
"ja": "Node-RED 3.0へようこそ!"
},
description: {
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>"
}
},
{
title: {
"en-US": "Context Menu",
"ja": "コンテキストメニュー"
},
image: 'images/context-menu.png',
description: {
"en-US": `<p>The editor now has its own context menu when you
right-click in the workspace.</p>
<p>This makes many of the built-in actions much easier
to access.</p>`,
"ja": `<p>ワークスペースで右クリックすると、エディタに独自のコンテキストメニューが表示されるようになりました。</p>
<p>これによって多くの組み込み動作を、より簡単に利用できます。</p>`
}
},
{
title: {
"en-US": "Wire Junctions",
"ja": "分岐点をワイヤーに追加"
},
image: 'images/junction-slice.gif',
description: {
"en-US": `<p>To make it easier to route wires around your flows,
it is now possible to add junction nodes that give
you more control.</p>
<p>Junctions can be added to wires by holding both the Alt key and the Shift key
then click and drag the mouse across the wires.</p>`,
"ja": `<p>フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。</p>
<p>Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`
},
},
{
title: {
"en-US": "Wire Junctions",
"ja": "分岐点をワイヤーに追加"
},
image: 'images/junction-quick-add.png',
description: {
"en-US": `<p>Junctions can also be added using the quick-add dialog.</p>
<p>The dialog is opened by holding the Ctrl (or Cmd) key when
clicking in the workspace.</p>`,
"ja": `<p>クイック追加ダイアログを用いて、分岐点を追加することもできます。</p>
<p>本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。</p>`
},
},
{
title: {
"en-US": "Debug Path Tooltip",
"ja": "デバッグパスのツールチップ"
},
image: 'images/debug-path-tooltip.png',
description: {
"en-US": `<p>When hovering over a node name in the Debug sidebar, a
new tooltip shows the full location of the node.</p>
<p>This is useful when working with subflows, making it
much easier to identify exactly which node generated
the message.</p>
<p>Clicking on any item in the list will reveal it in
the workspace.</p>`,
"ja": `<p>デバックサイドバー内のノード名の上にマウスカーソルを乗せると、新たにツールチップが表示され、ノードの場所が分かるようになっています。</p>
<p>これは、サブフローを用いる時に役立つ機能であり、メッセージがどのノードから出力されたかを正確に特定することが遥かに簡単になります。</p>
<p>本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。</p>`
},
},
{
title: {
"en-US": "Continuous Search",
"ja": "連続した検索"
},
image: 'images/continuous-search.png',
description: {
"en-US": `<p>When searching for things in the editor, a new toolbar in
the workspace provides options to quickly jump between
the search results.</p>`,
"ja": `<p>ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。</p>`
},
},
{
title: {
"en-US": "New wiring actions",
"ja": "新しいワイヤー操作"
},
image: "images/split-wire-with-links.gif",
description: {
"en-US": `<p>A new action has been added that will replace a wire with a pair of connected Link nodes:</p>
<ul>
<li><b><code>Split Wire With Link Nodes</code></b></li>
</ul>
<p>Actions can be accessed from the Action List in the main menu.</p>`,
"ja": `<p>ワイヤーを、接続されたLinkードのペアに置き換える動作が新たに追加されました:</p>
<ul>
<li><b><code>ワイヤーをlinkードで分割</code></b></li>
</ul>
<p>本アクションは、メインメニュー内の動作一覧から呼び出せます。</p>`,
},
},
{
title: {
"en-US": "Default node names",
"ja": "標準ノードの名前"
},
// image: "images/",
description: {
"en-US": `<p>Some nodes have been updated to generate a unique name when
new instances are added to the workspace. This applies to
<code>Debug</code>, <code>Function</code> and <code>Link</code> nodes.</p>
<p>A new action has also been added to generate default names for the selected
nodes:</p>
<ul>
<li><b><code>Generate Node Names</code></b></li>
</ul><p>Actions can be accessed from the Action List in the main menu.</p>
`,
"ja": `<p>一部のノードは、ワークスペース上に新インスタンスとして追加した際に、一意の名前を付けるよう変更されました。この変更は、<code>Debug</code>、<code>Function</code>、<code>Link</code>ノードに適用されています。</p>
<p>選択したノードに対して、標準の名前を生成する動作も新たに追加されました:</p>
<ul>
<li><b><code>ノード名を生成</code></b></li>
</ul><p>本アクションは、メインメニュー内の動作一覧から呼び出せます。</p>
`
}
},
{
title: {
"en-US": "Node Updates",
"ja": "ノードの更新"
},
// image: "images/",
description: {
"en-US": `<ul>
<li>The Debug node can be configured to count messages it receives</li>
<li>The Link Call node can use a message property to dynamically target the link it should call</li>
<li>The HTTP Request node can be preconfigured with HTTP headers</li>
</ul>`,
"ja": `<ul>
<li>Debugードは、受信したメッセージの数をカウントするよう設定できるようになりました。</li>
<li>Link Callードは、メッセージのプロパティによって、呼び出し対象のlinkを動的に指定できるようになりました。</li>
<li>HTTP Requestードは、HTTPヘッダを事前設定できるようになりました。</li>
</ul>`
}
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@@ -1,137 +1,97 @@
export default {
version: "3.0.0",
version: "3.1.0-beta.1",
steps: [
{
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 3.0!",
"ja": "Node-RED 3.0へようこそ!"
"en-US": "Welcome to Node-RED 3.1 Beta 1!",
// "ja": "Node-RED 3.1へようこそ!"
},
description: {
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>"
"en-US": "<p>This is the first beta release for 3.1.0 and we have a few new features to tell you about.</p>",
// "ja": ""
}
},
{
title: {
"en-US": "Context Menu",
"ja": "コンテキストメニュー"
"en-US": "Improved Context Menu",
// "ja": ""
},
image: 'images/context-menu.png',
description: {
"en-US": `<p>The editor now has its own context menu when you
right-click in the workspace.</p>
<p>This makes many of the built-in actions much easier
to access.</p>`,
"ja": `<p>ワークスペースで右クリックすると、エディタに独自のコンテキストメニューが表示されるようになりました。</p>
<p>これによって多くの組み込み動作を、より簡単に利用できます。</p>`
"en-US": `<p>The editor's context menu has been expanded to make lots more of
the built-in actions available.</p>
<p>Adding nodes, working with groups and plenty
of other useful tools are now just a click away.</p>
<p>The flow tab bar also has its own context menu to make working
with your flows much easier.</p>`,
// "ja": ``
}
},
{
title: {
"en-US": "Wire Junctions",
"ja": "分岐点をワイヤーに追加"
"en-US": "Hiding Flows",
// "ja": ""
},
image: 'images/junction-slice.gif',
image: 'images/hiding-flows.png',
description: {
"en-US": `<p>To make it easier to route wires around your flows,
it is now possible to add junction nodes that give
you more control.</p>
<p>Junctions can be added to wires by holding both the Alt key and the Shift key
then click and drag the mouse across the wires.</p>`,
"ja": `<p>フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。</p>
<p>Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`
"en-US": `<p>Hiding flows is now done through the flow context menu.</p>
<p>The 'hide' button in previous releases has been removed from the tabs
as they were being clicked accidentally too often.</p>`,
// "ja": ``
},
},
{
title: {
"en-US": "Wire Junctions",
"ja": "分岐点をワイヤーに追加"
"en-US": "Locking Flows",
// "ja": ""
},
image: 'images/junction-quick-add.png',
image: 'images/locking-flows.png',
description: {
"en-US": `<p>Junctions can also be added using the quick-add dialog.</p>
<p>The dialog is opened by holding the Ctrl (or Cmd) key when
clicking in the workspace.</p>`,
"ja": `<p>クイック追加ダイアログを用いて、分岐点を追加することもできます。</p>
<p>本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。</p>`
"en-US": `<p>Flows can now be locked to prevent accidental changes being made.</p>
<p>When locked you cannot modify the nodes in any way.</p>
<p>The flow context menu provides the options to lock and unlock flows,
as well as in the Info sidebar explorer.</p>`,
// "ja": ``
},
},
{
title: {
"en-US": "Debug Path Tooltip",
"ja": "デバッグパスのツールチップ"
"en-US": "Adding Images to node/flow descriptions",
// "ja": ""
},
image: 'images/debug-path-tooltip.png',
// image: 'images/debug-path-tooltip.png',
description: {
"en-US": `<p>When hovering over a node name in the Debug sidebar, a
new tooltip shows the full location of the node.</p>
<p>This is useful when working with subflows, making it
much easier to identify exactly which node generated
the message.</p>
<p>Clicking on any item in the list will reveal it in
the workspace.</p>`,
"ja": `<p>デバックサイドバー内のノード名の上にマウスカーソルを乗せると、新たにツールチップが表示され、ノードの場所が分かるようになっています。</p>
<p>これは、サブフローを用いる時に役立つ機能であり、メッセージがどのノードから出力されたかを正確に特定することが遥かに簡単になります。</p>
<p>本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。</p>`
"en-US": `<p>You can now add images to a node's or flows's description.</p>
<p>Simply drag the image into the text editor and it will get added inline.</p>
<p>When the description is shown in the Info sidebar, the image will be displayed.`,
// "ja": ``
},
},
{
title: {
"en-US": "Continuous Search",
"ja": "連続した検索"
"en-US": "Adding Mermaid Diagrams",
// "ja": ""
},
image: 'images/continuous-search.png',
image: 'images/mermaid.png',
description: {
"en-US": `<p>When searching for things in the editor, a new toolbar in
the workspace provides options to quickly jump between
the search results.</p>`,
"ja": `<p>ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。</p>`
"en-US": `<p>You can also add <a href="https://github.com/mermaid-js/mermaid">Mermaid</a> diagrams directly into your node or flow descriptions.</p>
<p>This gives you much richer options for documenting your flows.</p>`,
// "ja": ``
},
},
{
title: {
"en-US": "New wiring actions",
"ja": "新しいワイヤー操作"
"en-US": "Managing Global Environment Variables",
// "ja": ""
},
image: "images/split-wire-with-links.gif",
image: 'images/global-env-vars.png',
description: {
"en-US": `<p>A new action has been added that will replace a wire with a pair of connected Link nodes:</p>
<ul>
<li><b><code>Split Wire With Link Nodes</code></b></li>
</ul>
<p>Actions can be accessed from the Action List in the main menu.</p>`,
"ja": `<p>ワイヤーを、接続されたLinkードのペアに置き換える動作が新たに追加されました:</p>
<ul>
<li><b><code>ワイヤーをlinkードで分割</code></b></li>
</ul>
<p>本アクションは、メインメニュー内の動作一覧から呼び出せます。</p>`,
"en-US": `<p>You can set environment variables that apply to all nodes and flows in the new
'Global Environment Variables' section of User Settings.</p>`,
// "ja": ``
},
},
{
title: {
"en-US": "Default node names",
"ja": "標準ノードの名前"
},
// image: "images/",
description: {
"en-US": `<p>Some nodes have been updated to generate a unique name when
new instances are added to the workspace. This applies to
<code>Debug</code>, <code>Function</code> and <code>Link</code> nodes.</p>
<p>A new action has also been added to generate default names for the selected
nodes:</p>
<ul>
<li><b><code>Generate Node Names</code></b></li>
</ul><p>Actions can be accessed from the Action List in the main menu.</p>
`,
"ja": `<p>一部のノードは、ワークスペース上に新インスタンスとして追加した際に、一意の名前を付けるよう変更されました。この変更は、<code>Debug</code>、<code>Function</code>、<code>Link</code>ノードに適用されています。</p>
<p>選択したノードに対して、標準の名前を生成する動作も新たに追加されました:</p>
<ul>
<li><b><code>ノード名を生成</code></b></li>
</ul><p>本アクションは、メインメニュー内の動作一覧から呼び出せます。</p>
`
}
},
{
title: {
"en-US": "Node Updates",
@@ -139,16 +99,9 @@ export default {
},
// image: "images/",
description: {
"en-US": `<ul>
<li>The Debug node can be configured to count messages it receives</li>
<li>The Link Call node can use a message property to dynamically target the link it should call</li>
<li>The HTTP Request node can be preconfigured with HTTP headers</li>
</ul>`,
"ja": `<ul>
<li>Debugードは、受信したメッセージの数をカウントするよう設定できるようになりました。</li>
<li>Link Callードは、メッセージのプロパティによって、呼び出し対象のlinkを動的に指定できるようになりました。</li>
<li>HTTP Requestードは、HTTPヘッダを事前設定できるようになりました。</li>
</ul>`
"en-US": `<p>The core nodes have received lots of minor fixes, documentation updates and
small enhancements. Check the full changelog in the Help sidebar for a full list.</p>`,
// "ja": ``
}
}
]

View File

@@ -95,45 +95,64 @@ module.exports = function(RED) {
}
this.on("input", function(msg, send, done) {
var errors = [];
var props = this.props;
const errors = [];
let props = this.props;
if (msg.__user_inject_props__ && Array.isArray(msg.__user_inject_props__)) {
props = msg.__user_inject_props__;
}
delete msg.__user_inject_props__;
props.forEach(p => {
var property = p.p;
var value = p.v ? p.v : '';
var valueType = p.vt ? p.vt : 'str';
props = [...props]
function evaluateProperty(doneEvaluating) {
if (props.length === 0) {
doneEvaluating()
return
}
const p = props.shift()
const property = p.p;
const value = p.v ? p.v : '';
const valueType = p.vt ? p.vt : 'str';
if (!property) return;
if (valueType === "jsonata") {
if (p.v) {
try {
var exp = RED.util.prepareJSONataExpression(p.v, node);
var val = RED.util.evaluateJSONataExpression(exp, msg);
RED.util.setMessageProperty(msg, property, val, true);
if (property) {
if (valueType === "jsonata") {
if (p.v) {
try {
var exp = RED.util.prepareJSONataExpression(p.v, node);
var val = RED.util.evaluateJSONataExpression(exp, msg);
RED.util.setMessageProperty(msg, property, val, true);
}
catch (err) {
errors.push(err.message);
}
}
catch (err) {
errors.push(err.message);
evaluateProperty(doneEvaluating)
} else {
try {
RED.util.evaluateNodeProperty(value, valueType, node, msg, (err, newValue) => {
if (err) {
errors.push(err.toString())
} else {
RED.util.setMessageProperty(msg,property,newValue,true);
}
evaluateProperty(doneEvaluating)
})
} catch (err) {
errors.push(err.toString());
evaluateProperty(doneEvaluating)
}
}
return;
} else {
evaluateProperty(doneEvaluating)
}
try {
RED.util.setMessageProperty(msg,property,RED.util.evaluateNodeProperty(value, valueType, this, msg),true);
} catch (err) {
errors.push(err.toString());
}
});
if (errors.length) {
done(errors.join('; '));
} else {
send(msg);
done();
}
evaluateProperty(() => {
if (errors.length) {
done(errors.join('; '));
} else {
send(msg);
done();
}
})
});
}

View File

@@ -4,7 +4,7 @@
<label style="width: auto" for="node-input-scope" data-i18n="catch.label.source"></label>
<select id="node-input-scope-select">
<option value="all" data-i18n="catch.scope.all"></option>
<option value="target" data-i18n="catch.scope.selected"></options>
<option value="target" data-i18n="catch.scope.selected"></option>
</select>
</div>
<div class="form-row node-input-uncaught-row">

View File

@@ -4,7 +4,7 @@
<label style="width: auto" for="node-input-scope" data-i18n="status.label.source"></label>
<select id="node-input-scope-select">
<option value="all" data-i18n="status.scope.all"></option>
<option value="target" data-i18n="status.scope.selected"></options>
<option value="target" data-i18n="status.scope.selected"></option>
</select>
</div>
<div class="form-row node-input-target-row">

View File

@@ -0,0 +1,27 @@
<script type="text/html" data-template-name="global-config">
  <div class="form-row">
<label style="width: 100%"><span data-i18n="global-config.label.open-conf"></span>:</label>
</div>
<div class="form-row">
<button class="red-ui-button" type="button" id="node-input-edit-env-var" data-i18n="editor:env-var.header" style="margin-left: 20px"></button>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('global-config',{
category: 'config',
defaults: {
name: { value: "" },
env: { value: [] },
},
credentials: {
map: { type: "map" }
},
oneditprepare: function() {
$('#node-input-edit-env-var').on('click', function(evt) {
RED.actions.invoke('core:show-user-settings', 'envvar')
});
},
hasUsers: false
});
</script>

View File

@@ -0,0 +1,7 @@
module.exports = function(RED) {
"use strict";
function GlobalConfigNode(n) {
RED.nodes.createNode(this,n);
}
RED.nodes.registerType("global-config", GlobalConfigNode);
}

View File

@@ -17,6 +17,8 @@
display: flex;
background: var(--red-ui-tertiary-background);
padding-right: 75px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
#node-input-libs-container-row .red-ui-editableList-header > div {
flex-grow: 1;

View File

@@ -318,7 +318,7 @@ module.exports = function(RED) {
}
var r = node.rules[currentRule];
if (r.t === "move") {
if ((r.tot !== r.pt) || (r.p.indexOf(r.to) !== -1)) {
if ((r.tot !== r.pt) || (r.p.indexOf(r.to) !== -1) && (r.p !== r.to)) {
applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:r.p, tot:r.pt},(err,msg) => {
applyRule(msg,{t:"delete", p:r.p, pt:r.pt}, (err,msg) => {
completeApplyingRules(msg,currentRule,done);

View File

@@ -10,6 +10,7 @@
<option value="scale" data-i18n="range.scale.payload"></option>
<option value="clamp" data-i18n="range.scale.limit"></option>
<option value="roll" data-i18n="range.scale.wrap"></option>
<option value="drop" data-i18n="range.scale.drop"></option>
</select>
</div>
<br/>

View File

@@ -32,11 +32,15 @@ module.exports = function(RED) {
if (value !== undefined) {
var n = Number(value);
if (!isNaN(n)) {
if (node.action == "clamp") {
if (node.action === "drop") {
if (n < node.minin) { done(); return; }
if (n > node.maxin) { done(); return; }
}
if (node.action === "clamp") {
if (n < node.minin) { n = node.minin; }
if (n > node.maxin) { n = node.maxin; }
}
if (node.action == "roll") {
if (node.action === "roll") {
var divisor = node.maxin - node.minin;
n = ((n - node.minin) % divisor + divisor) % divisor + node.minin;
}

View File

@@ -21,6 +21,7 @@
<option value="javascript">JavaScript</option>
<option value="css">CSS</option>
<option value="markdown">Markdown</option>
<option value="php">PHP</option>
<option value="python">Python</option>
<option value="sql">SQL</option>
<option value="yaml">YAML</option>

View File

@@ -201,6 +201,7 @@ module.exports = function(RED) {
});
node.on("close", function() { clearDelayList(); });
}
else if (node.pauseType === "random") {
node.on("input", function(msg, send, done) {
var wait = node.randomFirst + (node.diff * Math.random());
@@ -226,34 +227,19 @@ module.exports = function(RED) {
// The rate limit/queue type modes
else if (node.pauseType === "rate") {
node.on("input", function(msg, send, done) {
if (msg.hasOwnProperty("reset")) {
if (node.intervalID !== -1 ) {
clearInterval(node.intervalID);
node.intervalID = -1;
}
delete node.lastSent;
node.buffer = [];
node.rate = node.fixedrate;
node.status({fill:"blue",shape:"ring",text:0});
done();
return;
}
if (!node.drop) {
var m = RED.util.cloneMessage(msg);
delete m.flush;
delete m.lifo;
if (Object.keys(m).length > 1) {
if (node.intervalID !== -1) {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
node.rate = msg.rate;
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate)) && node.rate !== m.rate) {
node.rate = m.rate;
clearInterval(node.intervalID);
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
}
var max_msgs = maxKeptMsgsCount(node);
if ((max_msgs > 0) && (node.buffer.length >= max_msgs)) {
node.buffer = [];
node.error(RED._("delay.errors.too-many"), msg);
node.error(RED._("delay.errors.too-many"), m);
} else if (msg.toFront === true) {
node.buffer.unshift({msg: m, send: send, done: done});
node.reportDepth();
@@ -263,8 +249,8 @@ module.exports = function(RED) {
}
}
else {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
node.rate = msg.rate;
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) {
node.rate = m.rate;
}
send(m);
node.reportDepth();
@@ -282,6 +268,8 @@ module.exports = function(RED) {
else {
while (len > 0) {
const msgInfo = node.buffer.shift();
delete msgInfo.msg.flush;
delete msgInfo.msg.reset;
if (Object.keys(msgInfo.msg).length > 1) {
node.send(msgInfo.msg);
msgInfo.done();
@@ -335,6 +323,21 @@ module.exports = function(RED) {
}
done();
}
if (msg.hasOwnProperty("reset")) {
if (msg.flush === undefined) {
if (node.intervalID !== -1 ) {
clearInterval(node.intervalID);
node.intervalID = -1;
}
delete node.lastSent;
}
node.buffer = [];
node.rate = node.fixedrate;
node.status({fill:"blue",shape:"ring",text:0});
done();
return;
}
});
node.on("close", function() {
clearInterval(node.intervalID);
@@ -387,6 +390,22 @@ module.exports = function(RED) {
node.buffer.push({msg, send, done}); // if not add to end of queue
node.reportDepth();
}
if (msg.hasOwnProperty("flush")) {
var len = node.buffer.length;
if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush,len)); }
while (len > 0) {
const msgInfo = node.buffer.shift();
delete msgInfo.msg.flush;
delete msgInfo.msg.reset;
if (Object.keys(msgInfo.msg).length > 2) {
node.send(msgInfo.msg);
msgInfo.done();
}
len = len - 1;
}
node.status({});
done();
}
if (msg.hasOwnProperty("reset")) {
while (node.buffer.length > 0) {
const msgInfo = node.buffer.shift();
@@ -397,21 +416,6 @@ module.exports = function(RED) {
node.status({text:"reset"});
done();
}
if (msg.hasOwnProperty("flush")) {
var len = node.buffer.length;
if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush,len)); }
while (len > 0) {
const msgInfo = node.buffer.shift();
delete msgInfo.msg.flush;
if (Object.keys(msgInfo.msg).length > 2) {
node.send(msgInfo.msg);
msgInfo.done();
}
len = len - 1;
}
node.status({});
done();
}
});
node.on("close", function() {
clearInterval(node.intervalID);

View File

@@ -25,7 +25,7 @@
<select id="node-then-type" style="width:70%;">
<option value="block" data-i18n="trigger.wait-reset"></option>
<option value="wait" data-i18n="trigger.wait-for"></option>
<option value="loop" data-i18n="trigger.wait-loop"></option>
<option id="node-trigger-wait-loop" value="loop" data-i18n="trigger.wait-loop"></option>
</select>
</div>
<div class="form-row node-type-duration">
@@ -181,6 +181,13 @@
$("#node-input-op2type").val('str');
}
$("#node-input-op1").on("change", function() {
if ($("#node-input-op1type").val() === "nul") {
$("#node-trigger-wait-loop").hide();
}
else { $("#node-trigger-wait-loop").show(); }
});
var optionNothing = {value:"nul",label:this._("trigger.output.nothing"),hasValue:false};
var optionPayload = {value:"pay",label:this._("trigger.output.existing"),hasValue:false};
var optionOriginalPayload = {value:"pay",label:this._("trigger.output.original"),hasValue:false};

View File

@@ -421,7 +421,11 @@
<script type="text/javascript">
(function() {
var typedInputNoneOpt = { value: 'none', label: '', hasValue: false };
var typedInputNoneOpt = {
value: 'none',
label: RED._("node-red:mqtt.label.none"),
hasValue: false
};
var makeTypedInputOpt = function(value){
return {
value: value,
@@ -436,7 +440,11 @@
makeTypedInputOpt("text/csv"),
makeTypedInputOpt("text/html"),
makeTypedInputOpt("text/plain"),
{value:"other", label:""}
{
value: "other",
label: RED._("node-red:mqtt.label.other"),
icon: "red/images/typedInput/az.svg"
}
];
function getDefaultContentType(value) {
@@ -499,17 +507,17 @@
cleansession: {value: true},
birthTopic: {value:"", validate:validateMQTTPublishTopic},
birthQos: {value:"0"},
birthRetain: {value:false},
birthRetain: {value:"false"},
birthPayload: {value:""},
birthMsg: { value: {}},
closeTopic: {value:"", validate:validateMQTTPublishTopic},
closeQos: {value:"0"},
closeRetain: {value:false},
closeRetain: {value:"false"},
closePayload: {value:""},
closeMsg: { value: {}},
willTopic: {value:"", validate:validateMQTTPublishTopic},
willQos: {value:"0"},
willRetain: {value:false},
willRetain: {value:"false"},
willPayload: {value:""},
willMsg: { value: {}},
userProps: { value: ""},

View File

@@ -295,7 +295,7 @@ module.exports = function(RED) {
/* mute error - it simply isnt JSON, just leave payload as a string */
}
}
} //else {
} //else {
//leave as buffer
//}
}
@@ -357,7 +357,7 @@ module.exports = function(RED) {
return;
}
done(err);
});
});
} else {
done();
}
@@ -366,6 +366,16 @@ module.exports = function(RED) {
}
}
function updateStatus(node, allNodes) {
let setStatus = setStatusDisconnected
if(node.connecting) {
setStatus = setStatusConnecting
} else if(node.connected) {
setStatus = setStatusConnected
}
setStatus(node, allNodes)
}
function setStatusDisconnected(node, allNodes) {
if(allNodes) {
for (var id in node.users) {
@@ -459,7 +469,6 @@ module.exports = function(RED) {
if(!opts || typeof opts !== "object") {
return; //nothing to change, simply return
}
const originalBrokerURL = node.brokerurl;
//apply property changes (only if the property exists in the opts object)
setIfHasProperty(opts, node, "url", init);
@@ -468,7 +477,6 @@ module.exports = function(RED) {
setIfHasProperty(opts, node, "clientid", init);
setIfHasProperty(opts, node, "autoConnect", init);
setIfHasProperty(opts, node, "usetls", init);
setIfHasProperty(opts, node, "usews", init);
setIfHasProperty(opts, node, "verifyservercert", init);
setIfHasProperty(opts, node, "compatmode", init);
setIfHasProperty(opts, node, "protocolVersion", init);
@@ -571,9 +579,6 @@ module.exports = function(RED) {
if (typeof node.usetls === 'undefined') {
node.usetls = false;
}
if (typeof node.usews === 'undefined') {
node.usews = false;
}
if (typeof node.verifyservercert === 'undefined') {
node.verifyservercert = false;
}
@@ -702,16 +707,21 @@ module.exports = function(RED) {
if (Object.keys(node.users).length === 1) {
if(node.autoConnect) {
node.connect();
//update nodes status
setTimeout(function() {
updateStatus(node, true)
}, 1)
}
}
};
node.deregister = function(mqttNode,done) {
node.deregister = function(mqttNode, done, autoDisconnect) {
delete node.users[mqttNode.id];
if (!node.closing && node.connected && Object.keys(node.users).length === 0) {
node.disconnect();
if (autoDisconnect && !node.closing && node.connected && Object.keys(node.users).length === 0) {
node.disconnect(done);
} else {
done();
}
done();
};
node.canConnect = function() {
return !node.connected && !node.connecting;
@@ -845,7 +855,7 @@ module.exports = function(RED) {
let waitEnd = (client, ms) => {
return new Promise( (resolve, reject) => {
node.closing = true;
if(!client) {
if(!client) {
resolve();
} else {
const t = setTimeout(() => {
@@ -1000,7 +1010,7 @@ module.exports = function(RED) {
node.client.publish(msg.topic, msg.payload, options, function (err) {
if (done) {
done(err)
} else {
} else if(err) {
node.error(err, msg)
}
})
@@ -1024,7 +1034,7 @@ module.exports = function(RED) {
/**
* Add event handlers to the MQTT.js client and track them so that
* we do not remove any handlers that the MQTT client uses internally.
* we do not remove any handlers that the MQTT client uses internally.
* Use {@link node._clientRemoveListeners `node._clientRemoveListeners`} to remove handlers
* @param {string} event The name of the event
* @param {function} handler The handler for this event
@@ -1032,11 +1042,11 @@ module.exports = function(RED) {
node._clientOn = function(event, handler) {
node.clientListeners.push({event, handler})
node.client.on(event, handler)
}
}
/**
* Remove event handlers from the MQTT.js client & only the events
* that we attached in {@link node._clientOn `node._clientOn`}.
* Remove event handlers from the MQTT.js client & only the events
* that we attached in {@link node._clientOn `node._clientOn`}.
* * If `event` is omitted, then all events matching `handler` are removed
* * If `handler` is omitted, then all events named `event` are removed
* * If both parameters are omitted, then all events are removed
@@ -1225,7 +1235,7 @@ module.exports = function(RED) {
} else {
node.brokerConn.unsubscribe(node.topic,node.id, removed);
}
node.brokerConn.deregister(node, done);
node.brokerConn.deregister(node, done, removed);
node.brokerConn = null;
} else {
done();
@@ -1288,9 +1298,9 @@ module.exports = function(RED) {
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
}
node.brokerConn.register(node);
node.on('close', function(done) {
node.on('close', function(removed, done) {
if (node.brokerConn) {
node.brokerConn.deregister(node,done);
node.brokerConn.deregister(node, done, removed)
node.brokerConn = null;
} else {
done();

View File

@@ -46,7 +46,7 @@ module.exports = function(RED) {
isText = true;
} else if (parsedType.type !== "application") {
isText = false;
} else if ((parsedType.subtype !== "octet-stream")
} else if ((parsedType.subtype !== "octet-stream")
&& (parsedType.subtype !== "cbor")
&& (parsedType.subtype !== "x-protobuf")) {
checkUTF = true;
@@ -200,6 +200,15 @@ module.exports = function(RED) {
this.callback = function(req,res) {
var msgid = RED.util.generateId();
res._msgid = msgid;
// Since Node 15, req.headers are lazily computed and the property
// marked as non-enumerable.
// That means it doesn't show up in the Debug sidebar.
// This redefines the property causing it to be evaluated *and*
// marked as enumerable again.
Object.defineProperty(req, 'headers', {
value: req.headers,
enumerable: true
})
if (node.method.match(/^(post|delete|put|options|patch)$/)) {
node.send({_msgid:msgid,req:req,res:createResponseWrapper(node,res),payload:req.body});
} else if (node.method == "get") {

View File

@@ -435,6 +435,10 @@ in your Node-RED user directory (${RED.settings.userDir}).
formData.append(opt, val);
} else if (typeof val === 'object' && val.hasOwnProperty('value')) {
formData.append(opt,val.value,val.options || {});
} else if (Array.isArray(val)) {
for (var i=0; i<val.length; i++) {
formData.append(opt, val[i])
}
} else {
formData.append(opt,JSON.stringify(val));
}

View File

@@ -86,7 +86,7 @@ module.exports = function(RED) {
this.topic = n.topic;
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
this.newline = (n.newline||"").replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t");
this.base64 = n.base64;
this.trim = n.trim || false;
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");

View File

@@ -19,9 +19,9 @@ module.exports = function(RED) {
function CSVNode(n) {
RED.nodes.createNode(this,n);
this.template = (n.temp || "");
this.sep = (n.sep || ',').replace("\\t","\t").replace("\\n","\n").replace("\\r","\r");
this.sep = (n.sep || ',').replace(/\\t/g,"\t").replace(/\\n/g,"\n").replace(/\\r/g,"\r");
this.quo = '"';
this.ret = (n.ret || "\n").replace("\\n","\n").replace("\\r","\r");
this.ret = (n.ret || "\n").replace(/\\n/g,"\n").replace(/\\r/g,"\r");
this.winflag = (this.ret === "\r\n");
this.lineend = "\n";
this.multi = n.multi || "one";
@@ -110,7 +110,12 @@ module.exports = function(RED) {
if (msg.payload[s].hasOwnProperty(p)) {
/* istanbul ignore else */
if (typeof msg.payload[s][p] !== "object") {
var q = "" + msg.payload[s][p];
// Fix to honour include null values flag
//if (typeof msg.payload[s][p] !== "object" || (node.include_null_values === true && msg.payload[s][p] === null)) {
var q = "";
if (msg.payload[s][p] !== undefined) {
q += msg.payload[s][p];
}
if (q.indexOf(node.quo) !== -1) { // add double quotes if any quotes
q = q.replace(/"/g, '""');
ou += node.quo + q + node.quo + node.sep;
@@ -130,9 +135,15 @@ module.exports = function(RED) {
ou += node.sep;
}
else {
var p = RED.util.ensureString(RED.util.getMessageProperty(msg,"payload["+s+"]['"+template[t]+"']"));
var tt = template[t];
if (template[t].indexOf('"') >=0 ) { tt = "'"+tt+"'"; }
else { tt = '"'+tt+'"'; }
var p = RED.util.getMessageProperty(msg,'payload["'+s+'"]['+tt+']');
/* istanbul ignore else */
if (p === "undefined") { p = ""; }
if (p === undefined) { p = ""; }
// fix to honour include null values flag
//if (p === null && node.include_null_values !== true) { p = "";}
p = RED.util.ensureString(p);
if (p.indexOf(node.quo) !== -1) { // add double quotes if any quotes
p = p.replace(/"/g, '""');
ou += node.quo + p + node.quo + node.sep;

View File

@@ -224,7 +224,12 @@
outputs:1,
icon: "join.svg",
label: function() {
return this.name||this._("join.join");
var nam = this.name||this._("join.join");
if (this.mode === "custom" && !isNaN(Number(this.count))) {
nam += " "+this.count;
if (this.accumulate === true) { nam+= "+"; }
}
return nam;
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -251,7 +251,9 @@ module.exports = function(RED) {
}
else {
node.buffer = buff.slice(p,buff.length);
node.pendingDones.push(done);
if (node.buffer.length > 0) {
node.pendingDones.push(done);
}
}
if (node.buffer.length == 0) {
done();

View File

@@ -107,7 +107,14 @@
outputs:1,
icon: "batch.svg",
label: function() {
return this.name||this._("batch.batch");;
var nam = this.name||this._("batch.batch");
if (this.mode === "count" && !isNaN(Number(this.count))) {
nam += " "+this.count;
}
if (this.mode === "interval" && !isNaN(Number(this.interval))) {
nam += " "+this.interval+"s";
}
return nam;
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";

0
packages/node_modules/@node-red/nodes/core/storage/10-file.html vendored Executable file → Normal file
View File

View File

View File

View File

View File

View File

View File

View File

View File

Some files were not shown because too many files have changed in this diff Show More