Compare commits
360 Commits
fix-monaco
...
310-tour
Author | SHA1 | Date | |
---|---|---|---|
|
df19e54555 | ||
|
6d717a21cf | ||
|
fc251d005e | ||
|
4624e28675 | ||
|
3a1cc38aaf | ||
|
68bb38b8d7 | ||
|
2ca3b3e99d | ||
|
67c8354f76 | ||
|
384377782a | ||
|
8382665bbb | ||
|
e799cfc16a | ||
|
055d0081e1 | ||
|
9035de32c8 | ||
|
af62a520d3 | ||
|
1824108d09 | ||
|
149e8ce9b0 | ||
|
f4661eec75 | ||
|
0f7a1a42e4 | ||
|
5bda221f9d | ||
|
fd42becbdc | ||
|
2759c1616c | ||
|
55ac98c989 | ||
|
c42c6a7b08 | ||
|
b99bd38649 | ||
|
013ee2f1f4 | ||
|
7b79d79f84 | ||
|
66f9686e48 | ||
|
9b1b7437b3 | ||
|
720d44d53e | ||
|
7dca148349 | ||
|
47bacaf58a | ||
|
ffff8aeb91 | ||
|
9a856f50d7 | ||
|
e7540de85d | ||
|
ba9ddefbee | ||
|
f1801f9662 | ||
|
ae92ea9476 | ||
|
c7017ee84b | ||
|
0346294c59 | ||
|
8d240ca797 | ||
|
a607ee90e0 | ||
|
7dbbafec1b | ||
|
428132ea3b | ||
|
c49330f9d1 | ||
|
937c5fe893 | ||
|
d2c9f12c3a | ||
|
10324d8260 | ||
|
8f27dae7ea | ||
|
94ae511a6d | ||
|
038f75e48f | ||
|
b9fe4c5cd3 | ||
|
7e8b7602b4 | ||
|
7c306a8430 | ||
|
dd2bc44c2d | ||
|
74794fea09 | ||
|
1efd1a52a7 | ||
|
928131cf08 | ||
|
4d202a7a37 | ||
|
e0d71abdc6 | ||
|
550eb6ee2f | ||
|
a661bc1d23 | ||
|
f737162697 | ||
|
ce57ba80eb | ||
|
99bd957ea0 | ||
|
270eb56718 | ||
|
b3ce0c0079 | ||
|
e6cee58e0d | ||
|
4adc6b269c | ||
|
920b0178ec | ||
|
3583b40e02 | ||
|
7870830367 | ||
|
4c1d7ad2d2 | ||
|
661b07c856 | ||
|
5670bd8265 | ||
|
93a1911232 | ||
|
2429191838 | ||
|
f6901cd19f | ||
|
156c3984a7 | ||
|
f91af2153a | ||
|
805f8a5ee7 | ||
|
2ab8121a4a | ||
|
601a4ec70d | ||
|
707b831c30 | ||
|
72ae375e44 | ||
|
3c1ddb5c9d | ||
|
817db23146 | ||
|
a8c820f558 | ||
|
6d09c81f11 | ||
|
192e537e5d | ||
|
7b52ef34be | ||
|
7117472e73 | ||
|
c24b123917 | ||
|
9eb8cf121c | ||
|
41ef9ae010 | ||
|
1674bbbde9 | ||
|
0fb739f7cd | ||
|
169fa940e4 | ||
|
c9664cc425 | ||
|
e61cdff655 | ||
|
a479b8a5d7 | ||
|
26462e684b | ||
|
113d42ef35 | ||
|
c18018f017 | ||
|
e804addf0a | ||
|
04cea003b9 | ||
|
65fcc56a56 | ||
|
c065d253e9 | ||
|
4bb2b91ee6 | ||
|
b3f761776d | ||
|
dce1cccbde | ||
|
3630056ed8 | ||
|
2d6e1d7089 | ||
|
71db79ba53 | ||
|
5bb66ed7d4 | ||
|
14e74afb07 | ||
|
c4e216f839 | ||
|
752fdfedf2 | ||
|
2a49e7c8ef | ||
|
02af01d2ca | ||
|
07c05c1f2a | ||
|
ee4af4c7bf | ||
|
3d565e74a5 | ||
|
3cb84222f8 | ||
|
1b013bb73b | ||
|
fd54e625d5 | ||
|
77f6412d3b | ||
|
c81cd5450f | ||
|
0b663abe50 | ||
|
3b27fb2aa7 | ||
|
6bd67ae68c | ||
|
14c362d4ba | ||
|
f28bc1bff7 | ||
|
de8a5ea262 | ||
|
339013434b | ||
|
8a3ad331d2 | ||
|
e3892dc26d | ||
|
b95df6d883 | ||
|
11ad03b21e | ||
|
9cb474ea9c | ||
|
fce43b4e1d | ||
|
1d547500e8 | ||
|
f23d0480e4 | ||
|
fe9c630572 | ||
|
ce94226c3c | ||
|
f12d36b5ed | ||
|
3cb5259494 | ||
|
a351cd9d9f | ||
|
d8e01584f3 | ||
|
dd76840568 | ||
|
94690fad7a | ||
|
d693af9615 | ||
|
4cc18c25fe | ||
|
8b398f49c0 | ||
|
902ce68164 | ||
|
cd0474ce7b | ||
|
946def022f | ||
|
fb499be979 | ||
|
c62a101635 | ||
|
69a575097d | ||
|
b40551a8fa | ||
|
5b27bcd781 | ||
|
75725a38df | ||
|
c4e277853c | ||
|
24b055b1b8 | ||
|
7da3773f7f | ||
|
32999ffa84 | ||
|
f06c53f1f1 | ||
|
a9eec28360 | ||
|
5cda972872 | ||
|
087946876b | ||
|
318f0f1b7e | ||
|
6d1a12af4b | ||
|
a40e5dbcd4 | ||
|
7c79ca7878 | ||
|
93c1600980 | ||
|
c3d1e6181f | ||
|
87e7f3a61c | ||
|
e724f216bf | ||
|
e6b379358a | ||
|
b0abba15a6 | ||
|
81b4874a7c | ||
|
f11b9c1e18 | ||
|
e15ecc00ce | ||
|
3e4c45ac6a | ||
|
fc657ecc71 | ||
|
4115c13a65 | ||
|
f872e2ab80 | ||
|
a81b1aa0cb | ||
|
efc0f1ab91 | ||
|
ce31edc803 | ||
|
199caccbc3 | ||
|
313bab37e2 | ||
|
f060309002 | ||
|
fc3d86e6ff | ||
|
9fd4989142 | ||
|
7507a7b459 | ||
|
d657817211 | ||
|
954649007c | ||
|
0caa308757 | ||
|
b0d9903fe2 | ||
|
6375f3c445 | ||
|
2328f418be | ||
|
22b6564847 | ||
|
25c8bfefe2 | ||
|
30f4524821 | ||
|
9e4c3a7200 | ||
|
5b7e84c1b0 | ||
|
e6097e4968 | ||
|
0f2829097b | ||
|
e2a9f940e2 | ||
|
3eb2b2ac5d | ||
|
ce7b0a3b5e | ||
|
7bd7c99dd4 | ||
|
b0d12c4125 | ||
|
1fa8f30550 | ||
|
745607b5bc | ||
|
cc5a770b16 | ||
|
fbde0091de | ||
|
a533943a40 | ||
|
e11f17672c | ||
|
c038c99f9d | ||
|
5f159c1fbd | ||
|
6a19d8246c | ||
|
d6bb3a558f | ||
|
cd8ca8981b | ||
|
44300dbb34 | ||
|
a5d7f7acce | ||
|
a032c2e326 | ||
|
9d770ed436 | ||
|
ae753940f3 | ||
|
d0d22c333c | ||
|
266ba17ebb | ||
|
0d0d5bafb0 | ||
|
58b951e134 | ||
|
30956b5441 | ||
|
9540cfe749 | ||
|
31b17faa2a | ||
|
5c6b8e9e50 | ||
|
5a36e8fb11 | ||
|
7d4c857a43 | ||
|
598bcf675f | ||
|
5365786386 | ||
|
c9b0a7c2dd | ||
|
371d8042d6 | ||
|
be343cb21e | ||
|
e9eabd6881 | ||
|
abccdc7f21 | ||
|
4ae914f729 | ||
|
86ac955b79 | ||
|
9734691cac | ||
|
d94f3a477d | ||
|
d53cd209f7 | ||
|
65cacb39d2 | ||
|
b008a6a2aa | ||
|
5c29feec63 | ||
|
d8e350d603 | ||
|
14a3366850 | ||
|
5ea0c6fca1 | ||
|
f454c29b8c | ||
|
1ddbeaa50f | ||
|
fe5132be1d | ||
|
b50ba3e0e4 | ||
|
4fb40f9077 | ||
|
dc7fef6395 | ||
|
da65bf7292 | ||
|
17d9c2577e | ||
|
bc7852c1cc | ||
|
51d8792f62 | ||
|
bfdbeb0964 | ||
|
ede82ad0d5 | ||
|
f50dcb9e40 | ||
|
676c5e5df5 | ||
|
d52be76c8a | ||
|
c6a517c88c | ||
|
96eb8719b8 | ||
|
bcd31610f6 | ||
|
a4d66622a5 | ||
|
af4f07cb26 | ||
|
f7120b32f5 | ||
|
273404e24d | ||
|
1b53b5b927 | ||
|
7c5413e568 | ||
|
39b2fe45a5 | ||
|
8d3c5d09f6 | ||
|
5944fdb5dc | ||
|
e120bad779 | ||
|
d546a4a15b | ||
|
93a88a83a8 | ||
|
660a2e0ed6 | ||
|
30ea300f65 | ||
|
04f4d5274d | ||
|
1f9695abd7 | ||
|
1b94cc3ac0 | ||
|
4698d5d2fc | ||
|
92bc9d81c5 | ||
|
952cfaec14 | ||
|
637c44aa59 | ||
|
6e5fc29dca | ||
|
8bd02d0c36 | ||
|
c6cfbb8755 | ||
|
75d3444391 | ||
|
c648e1e8d6 | ||
|
e2f42fddb5 | ||
|
f93fe684c0 | ||
|
ee378ea0c4 | ||
|
613d34e6e6 | ||
|
4c784af55d | ||
|
b28595c814 | ||
|
fca7beec01 | ||
|
f813f03a46 | ||
|
6ff2232df3 | ||
|
e3b1f058cd | ||
|
542e9cacc2 | ||
|
0a0a7ca39b | ||
|
cee287da99 | ||
|
c8e4df94f9 | ||
|
c86e4f52a0 | ||
|
44216310ca | ||
|
5c69599e78 | ||
|
e4098d3991 | ||
|
55a94d659b | ||
|
7a048d5b32 | ||
|
e14dd06a94 | ||
|
62332a2b56 | ||
|
639030924f | ||
|
241b47fe19 | ||
|
69beecf334 | ||
|
e308e02f9d | ||
|
87258e485a | ||
|
0682c346ea | ||
|
5ae566952b | ||
|
18f9ab0cda | ||
|
bd4a5ac844 | ||
|
257b1f89f3 | ||
|
962672564e | ||
|
7216c6d62a | ||
|
21d3261eec | ||
|
03f758720c | ||
|
eaa85ae8d5 | ||
|
8cb212d897 | ||
|
a38d3981df | ||
|
af08c077d2 | ||
|
84e2489585 | ||
|
744375bd5d | ||
|
6c1f63bfbb | ||
|
7d0267c924 | ||
|
daa9cb65e5 | ||
|
7072265225 | ||
|
8daade0021 | ||
|
b4d30b462f | ||
|
18acd67b4f | ||
|
78ed53f4fb | ||
|
d95314c754 | ||
|
277cc19ec3 | ||
|
67f4553213 | ||
|
b2bb656d30 | ||
|
02308f9e2f | ||
|
0fdcbb4611 | ||
|
829ccc3466 | ||
|
9ac83cf62e |
3
.github/workflows/release.yml
vendored
@@ -5,6 +5,9 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
name: 'Update node-red-docker image'
|
||||
|
6
.github/workflows/tests.yml
vendored
@@ -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:
|
||||
|
@@ -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)
|
||||
}
|
||||
|
685
CHANGELOG.md
@@ -1,3 +1,166 @@
|
||||
#### 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
|
||||
|
||||
- Fix workspace chart bottom property (#3812) @bonanitech
|
||||
- Update german translation (#3802) @Dennis14e
|
||||
- Support color reset to the default in subflow and group (#3801) @kazuhitoyokoi
|
||||
- Allow generateNodeNames to handle names containing regex control chars (#3817) @knolleary
|
||||
- Hide scrollbars until they're needed (#3808) @bonanitech
|
||||
- Include junctions/groups when exporting subflows plus related fixes (#3816) @knolleary
|
||||
- remove console.log (#3820) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Register subflow module instance node with parent flow (#3818) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request: Allow HTTP Headers not in spec (#3776) @hardillb
|
||||
|
||||
#### 3.0.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Allow codeEditor theme to be set even if `codeEditor` is not set in settings.js (#3794) @Steve-Mcl
|
||||
- Sys info (diagnostics report) amendments (#3793) @Steve-Mcl
|
||||
- Allow `mode` and `title` to be omitted in `options` argument for `createEditor` (#3791) @Steve-Mcl
|
||||
- Fix focus issues (#3789) @Steve-Mcl
|
||||
- Ensure all typedInput buttons have button type set (#3788) @knolleary
|
||||
- Do not flag hasUsers=false nodes as unused in search (#3787) @knolleary
|
||||
- Properly position quick-add dialog in all cases (#3786) @knolleary
|
||||
- Ensure quick-add dialog does not obscure ghost node when shifted (#3785) @knolleary
|
||||
- Remove use of Object.hasOwn (#3784) @knolleary
|
||||
|
||||
#### 3.0.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Use theme page and header values if settings.js values are not present (#3767) @Steve-Mcl
|
||||
- Focus editor for undo after some actions in menu (#3759) @kazuhitoyokoi
|
||||
- Ensure node icon shade has properly rounded corners (#3763) @knolleary
|
||||
- Fix storing subflow credential type when input has multiple types (#3762) @knolleary
|
||||
- Ensure global-config and flow-config have info in the hierarchy popover (#3752) @Steve-Mcl
|
||||
- Include dirty state in history event (#3748) @Steve-Mcl
|
||||
- Fix display direction of context sub-menu (#3746) @knolleary
|
||||
- Fix clear pinned paths of debug sidebar menu (#3745) @HiroyasuNishiyama
|
||||
- prevent exception generating tooltip for deleted nodes (#3742) @Steve-Mcl
|
||||
- Fix context menu issues ready for v3 beta.5 (#3741) @Steve-Mcl
|
||||
- Do not generate new node-ids when pasting a cut flow (#3729) @knolleary
|
||||
- Fix to prevent node from moving out of workspace (#3731) @HiroyasuNishiyama
|
||||
- Don't let themes change disabled config node background color (#3736) @bonanitech
|
||||
- Move colors left behind in #3692 to CSS variables (#3737) @bonanitech
|
||||
- Fix handling of global debug message (#3733) @HiroyasuNishiyama
|
||||
- Fix label overflow @ config-node palette (#3730) @ralphwetzel
|
||||
- Fix defaulting to monaco if settings does not contain codeEditor (#3732) @knolleary
|
||||
- Disable keyboard shortcut mapping when showing Edit[..]Dialog (#3700) @ralphwetzel
|
||||
- Update add-junction menu to work in more cases (#3727) @knolleary
|
||||
- Ensure importMap is not null when using import UI (#3723) @Steve-Mcl
|
||||
- Add Japanese translations for v3.0-beta.4 (#3724) @kazuhitoyokoi
|
||||
- Fix "split with" on virtual links (#3766) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Do not remove unknown credentials of Subflow Modules (#3728) @knolleary
|
||||
- Add missing entries from beta.4 changelog (#3721) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Fix change node, not handling from field properly when using context (#3754) @Fadoli
|
||||
- Link Call: Fix linkcall registry bugs (#3751) @Steve-Mcl
|
||||
- WebSocket: Fix close timeout of websocket node (#3734) @HiroyasuNishiyama
|
||||
|
||||
#### 3.0.0-beta.4: Beta Release
|
||||
|
||||
Editor
|
||||
@@ -185,528 +348,6 @@ Nodes
|
||||
- Watch: Update Watch node to use node-watch module (#3559 #3569) @knolleary
|
||||
- WebSocket: call done after ws disconnects (#3531) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.2: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- Fix "close timed out" error when performing full deploy or modifying broker node. (#3451) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Handle mixed-cased filter terms in keyboard shortcut dialog (#3444) @knolleary
|
||||
- Prevent duplicate links being added between nodes (#3442) @knolleary
|
||||
- Fix to hide tooltip after removing subflow tab (#3391) @HiroyasuNishiyama
|
||||
- Fix node validation to be applied to config node (#3397) @HiroyasuNishiyama
|
||||
- Fix: Dont add wires to undo buffer twice (#3437) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Improve module location parsing (of stack info) when adding hook (#3447) @Steve-Mcl
|
||||
- Fix substitution of NR_NODE_PATH (#3445) @HiroyasuNishiyama
|
||||
- Remove console.log when ignoring disabled module (#3439) @knolleary
|
||||
- Improve "Unexpected Node Error" logging (#3446) @Steve-Mcl
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Fix no-prototype-builtins bug in debug node and utils (#3394) @Alkarex
|
||||
- Delay: Fix Japanese message of delay node (#3434)
|
||||
- Allow nbRateUnits to be undefined when validating (#3443) @knolleary
|
||||
- Coding help for recently added node-red Predefined Environment Variables (#3440) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add editorTheme.tours property to default settings file (#3375) @knolleary
|
||||
- Remember Zoom level and Sidebar tab selection between sessions (#3361) @knolleary
|
||||
- Fix timing issue when merging background changes fixes #3364 (#3373) @Steve-Mcl
|
||||
- Use a nodes palette label in help tree (#3372) @Steve-Mcl
|
||||
- Subflow: Add labels to OUTPUT nodes (#3352) @ralphwetzel
|
||||
- Fix vertical align subflow port (#3370) @knolleary
|
||||
- Make actions list i18n ready and Japanese translation (#3359) @HiroyasuNishiyama
|
||||
- Update tour for 2.2.0 (#3378) @knolleary
|
||||
- Include paletteLabel when building search index (#3380) @Steve-Mcl
|
||||
- Fix opening/closing subflow template not to make subflow changed (#3382) @HiroyasuNishiyama
|
||||
- Add Japanese translations for v2.2.0 (#3353, #3381) @kazuhitoyokoi
|
||||
|
||||
Runtime
|
||||
|
||||
- Add support for accessing node id & name as environment variable (#3356) @HiroyasuNishiyama
|
||||
- Clear context contents when switching projects (#3243) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- MQTT: reject invalid topics (#3374) @Steve-Mcl
|
||||
- Function: Expose node.path property (#3371) @knolleary
|
||||
- Function: Update `node` declarations in func.d.ts (#3377) @Steve-Mcl
|
||||
|
||||
#### 2.2.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add search history to main search box (#3262) @knolleary
|
||||
- Check availability of type of config node on deploy (#3304) @k-toumura
|
||||
- Add wire-slice mode to delete wires with Ctrl-RHClick-Drag (#3340) @knolleary
|
||||
- Wiring keyboard shortcuts (#3288) @knolleary
|
||||
- Snap nodes on grid using either edge as reference (#3289) @knolleary
|
||||
- Detach node action (#3338) @knolleary
|
||||
- Highlight links when selecting nodes (#3323) @knolleary
|
||||
- Allow multiple links to be selected by ctrl-click (#3294) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- JSON: Let JSON node attempt to parse buffer if it contains a valid string (#3296) @dceejay
|
||||
- Remove use of verbose flag in core nodes - and use node.debug level instead (#3300) @dceejay
|
||||
- TCP: Add TLS option to tcp client nodes (#3307) @dceejay
|
||||
- WebSocket: Implemented support for Websocket Subprotocols in WS Client Node. (#3333) @tobiasoort
|
||||
|
||||
#### 2.1.6: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Revert copy-text change and apply alternative fix (#3363) @knolleary
|
||||
- Update marked to latest (#3362) @knolleary
|
||||
- fix to make start of property error tooltip messages aligned (#3358) @HiroyasuNishiyama
|
||||
|
||||
Nodes
|
||||
|
||||
- Inject: fix JSON propety validation of inject node (#3349) @HiroyasuNishiyama
|
||||
- Delay: fix unit value validation of delay node (#3351) @HiroyasuNishiyama
|
||||
|
||||
#### 2.1.5: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Handle reporting error location when stack is truncated (#3346) @knolleary
|
||||
- Initialize passport when only adminAuth.tokens is set (#3343) @knolleary
|
||||
- Add log logging (#3342) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Fix copy buttons on the debug window (another method) (#3331) @kazuhitoyokoi
|
||||
- Add Japanese translations for hidden flow (#3302) @kazuhitoyokoi
|
||||
- Improve jsonata legacy mode detection regex (#3345) @knolleary
|
||||
- Fix generating flow name with incrementing number (#3347) @knolleary
|
||||
- resume focus after import/export dialog close (#3337) @HiroyasuNishiyama
|
||||
- Fix findPreviousVisibleTab action (#3321) @knolleary
|
||||
- Fix storing hidden tab state when not hidden via action (#3312) @knolleary
|
||||
- Avoid adding empty env properties to tabs/groups (#3311) @knolleary
|
||||
- Fix hide icon in tour guide (#3301) @kazuhitoyokoi
|
||||
|
||||
Nodes
|
||||
|
||||
- File: Update file node examples according to node name change (#3335) @HiroyasuNishiyama
|
||||
- Filter (RBE): Fix for filter node narrrowbandEq mode start condition failure (#3339) @dceejay
|
||||
- Function: Prevent function scrollbar from obscuring expand button (#3348) @knolleary
|
||||
- Function: load extralibs when expanding monaco. fixes #3319 (#3334) @Steve-Mcl
|
||||
- Function: Update Function to use correct api to access env vars (#3310) @knolleary
|
||||
- HTTP Request: Fix basic auth with empty username or password (#3325) @hardillb
|
||||
- Inject: Fix incorrect clearing of blank payload property in Inject node (#3322) @knolleary
|
||||
- Link Call: add link call example (#3336) @HiroyasuNishiyama
|
||||
- WebSocket: Only setup ws client heartbeat once it is connected (#3344) @knolleary
|
||||
- Update Japanese translations in node help (#3332) @kazuhitoyokoi
|
||||
|
||||
#### 2.1.4: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- fix env var access using $parent for groups (#3278) @HiroyasuNishiyama
|
||||
- Add proper error handling for 404 errors when serving debug files (#3277) @knolleary
|
||||
- Add Japanese translations for Node-RED v2.1.0-beta.1 (#3179) @kazuhitoyokoi
|
||||
- Include full user object on login audit events (#3269) @knolleary
|
||||
- Remove styling from de locale files (#3237) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Change tab hide button icon to an eye and add search option (#3282) @knolleary
|
||||
- Fix i18n handling of namespaces with spaces in (#3281) @knolleary
|
||||
- Trigger change event when autoComplete fills in input (#3280) @knolleary
|
||||
- Apply CN i18n fix (#3279) @knolleary
|
||||
- fix select menu label of config node to use paletteLabel (#3273) @HiroyasuNishiyama
|
||||
- fix removed tab not to cause node conflict (#3275) @HiroyasuNishiyama
|
||||
- Group diff fix (#3239) @knolleary
|
||||
- Only toggle disabled workspace flag if on activeWorkspace (#3252) @knolleary
|
||||
- Do not show status for disabled nodes (#3253) @knolleary
|
||||
- Set dimension value for tour guide (#3265) @kazuhitoyokoi
|
||||
- Avoid redundant initialisation of TypedInput type (#3263) @knolleary
|
||||
- Don't let themes change flow port label color (#3270) @bonanitech
|
||||
- Fix treeList gutter calculation to handle floating gutters (#3238) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Handle RegExp types in Debug sidebar (#3251) @knolleary
|
||||
- Delay: fix 2nd output when in rate limit per topic modes (#3261) @dceejay
|
||||
- Link: fix to show link target when selected (#3267) @HiroyasuNishiyama
|
||||
- Inject: Do not modify inject node props in oneditprepare (#3242) @knolleary
|
||||
- HTTP Request: HTTP Basic Auth should always add : between username and password even if empty (#3236) @hardillb
|
||||
|
||||
#### 2.1.3: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Update gen-publish script to update 'next' tag for main releases
|
||||
- Add environment variable to enable/disable tours (#3221) @hardillb
|
||||
- Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Refresh editor settings whenever a node is added or enabled (#3227) @knolleary
|
||||
- Revert spinner css change that made it shrink in some cases (#3229) @knolleary
|
||||
- Fix import notification message when importing config nodes (#3224) @knolleary
|
||||
- Handle changing types of TypedInput repeatedly (#3223) @knolleary
|
||||
|
||||
|
||||
#### 2.1.2: Maintenance Release
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- node-red-pi: Remove bash dependency (#3216) @a16bitsysop
|
||||
|
||||
Editor
|
||||
|
||||
- Improved regex for markdown renderer (#3213) @GerwinvBeek
|
||||
- Fix TypedInput initialisation (#3220) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- MQTT: fix datatype in node config not used. fixes #3215 (#3219) @Steve-Mcl
|
||||
|
||||
#### 2.1.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Ensure tourGuide popover doesn't fall offscreen (#3212) @knolleary
|
||||
- Fix issue with old inject nodes that migrated topic to 'string' type (#3210) @knolleary
|
||||
- Add cache-busting query params to index.mst (#3211) @knolleary
|
||||
- Fix TypedInput validation of type without options (#3207) @knolleary
|
||||
|
||||
#### 2.1.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Position popover properly on a scrolled page
|
||||
- Fixes from 2.1.0-beta.2 (#3202) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Link Out: Fix saving link out node links (#3201) @knolleary
|
||||
- Switch: Refix #3170 - copy switch rule type when adding new rule
|
||||
- TCP Request: Add string option to TCP request node output (#3204) @dceejay
|
||||
|
||||
#### 2.1.0-beta.2: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix switching projects (#3199) @knolleary
|
||||
- Use locale setting when installing/enabling node (#3198) @knolleary
|
||||
- Do not show projects-wecome dialog until welcome tour completes (#3197) @knolleary
|
||||
- Fix converting selection to subflow (#3196) @knolleary
|
||||
- Avoid conflicts with native browser cmd-ctrl type shortcuts (#3195) @knolleary
|
||||
- Ensure message tools stay attached to top-level entry in Debug/Context (#3186) @knolleary
|
||||
- Ensure tab state updates properly when toggling enable state (#3175) @knolleary
|
||||
- Improve handling of long labels in TreeList (#3176) @knolleary
|
||||
- Shift-click tab scroll arrows to jump to start/end (#3177) @knolleary
|
||||
|
||||
Runtime
|
||||
|
||||
- Update package dependencies
|
||||
- Update to latest node-red-admin
|
||||
|
||||
Nodes
|
||||
|
||||
- Dynamic MQTT connections (#3189)
|
||||
- Link: Filter out Link Out Return nodes in Link In edit dialog Fixes #3187
|
||||
- Link: Fix link call label (#3200) @knolleary
|
||||
- Debug: Redesign debug filter options and make them persistant (#3183) @knolleary
|
||||
- Inject: Widen Inject interval box for >1 digit (#3184) @knolleary
|
||||
- Switch: Fix rule focus when switch 'otherwise' rule is used (#3185) @knolleary
|
||||
|
||||
#### 2.1.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add Tour Guide component (#3136) @knolleary
|
||||
- Allow tabs to be hidden (#3120) @knolleary
|
||||
- Add align actions to editor (#3110) @knolleary
|
||||
- Add support of environment variable for tab & group (#3112) @HiroyasuNishiyama
|
||||
- Add autoComplete widget and add to TypedInput for msg. props (#3171) @knolleary
|
||||
- Render node documentation to node-red style guide when written in markdown. (#3169) @Steve-Mcl
|
||||
- Allow colouring of tab icon svg (#3140) @harmonic7
|
||||
- Restore tab selection after merging conflicts (#3151) @GerwinvBeek
|
||||
- Fix serving of theme files on Windows (#3154) @knolleary
|
||||
- Ensure config-node select inherits width properly from input (#3155) @knolleary
|
||||
- Do better remembering TypedInput values whilst switching types (#3159) @knolleary
|
||||
- Update monaco to 0.28.1 (#3153) @knolleary
|
||||
- Improve themeing of tourGuide (#3161) @knolleary
|
||||
- Allow a node to specify a filter for the config nodes it can pick from (#3160) @knolleary
|
||||
- Allow RED.notify.update to modify any notification setting (#3163) @knolleary
|
||||
- Fix typo in ko editor.json Fixes #3119
|
||||
- Improve RED.actions api to ensure actions cannot be overridden
|
||||
- Ensure treeList row has suitable min-height when no content Fixes #3109
|
||||
- Refactor edit dialogs to use separate edit panes
|
||||
- Ensure type select button is not focussable when TypedInput only has one type
|
||||
- Place close tab link in front of fade
|
||||
|
||||
Runtime
|
||||
|
||||
- Improve error reporting with oauth login strategies (#3148) @knolleary
|
||||
- Add allowUpdate feature to externalModules.palette (#3143) @knolleary
|
||||
- Improve node install error reporting (#3158) @knolleary
|
||||
- Improve unit test coverage (#3168) @knolleary
|
||||
- Allow coreNodesDir to be set to false (#3149) @hardillb
|
||||
- Update package dependencies
|
||||
- uncaughtException debug improvements (#3146) @renatojuniorrs
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Add option to deep-clone properties in Change node (#3156) @knolleary
|
||||
- Delay: Add push to front of rate limit queue. (#3069) @dceejay
|
||||
- File: Add paletteLabel to file nodes to make read/write more obvious (#3157) @knolleary
|
||||
- HTTP Request: Extend HTTP request node to log detailed timing information (#3116) @k-toumura
|
||||
- HTTP Response: Fix sizing of HTTP Response header fields (#3164) @knolleary
|
||||
- Join: Support for msg.restartTimeout (#3121) @magma1447
|
||||
- Link Call: Add Link Call node (#3152) @knolleary
|
||||
- Switch: Copy previous rule type when adding rule to switch node (#3170) @knolleary
|
||||
- Delay node: add option to send intermediate messages on separate output (#3166) @knolleary
|
||||
- Typo in http request set method translation (#3173) @mailsvb
|
||||
|
||||
#### 2.0.6: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix typo in ko editor.json Fixes #3119
|
||||
- Change fade color when hovering an inactive tab (#3106) @bonanitech
|
||||
- Ensure treeList row has suitable min-height when no content Fixes #3109
|
||||
|
||||
Runtime
|
||||
|
||||
- Update tar to latest (#3128) @aksswami
|
||||
- Give passport verify callback the same arity as the original callback (#3117) @dschmidt
|
||||
- Handle HTTPS Key and certificate as string or buffer (#3115) @bartbutenaers
|
||||
|
||||
#### 2.0.5: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Remove default ctrl-enter keybinding from monaco editor Fixes #3093
|
||||
|
||||
Runtime
|
||||
|
||||
- Update tar dependency
|
||||
- Add support for maintenance streams in generate-publish-script
|
||||
|
||||
|
||||
Nodes
|
||||
|
||||
- Fix regression in Join node when manual joining array with msg.parts present Fixes #3096
|
||||
|
||||
#### 2.0.4: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix tab fade CSS for when using themes (#3085) @bonanitech
|
||||
- Handle just-copied-but-not-deployed node with credentials in editor Fixes #3090
|
||||
|
||||
Nodes
|
||||
|
||||
- Filter: Fix RBE node handling of default topi property Fixes #3087
|
||||
- HTTP Request: Handle partially encoded url query strings in request node
|
||||
- HTTP Request: Fix support for supplied CA certs (#3089) @hardillb
|
||||
- HTTP Request: Ensure TLS Cert is used (#3092) @hardillb
|
||||
- Inject: Fix inject now button unable to send empty props
|
||||
- Inject: Inject now button success notification should use label with updated props
|
||||
|
||||
#### 2.0.3: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- HTML: Fix HTML parsing when body is included in the select tag Fixes #3079
|
||||
- HTTP Request: Preserve case of user-provided http headers in request node Fixes #3081
|
||||
- HTTP Request: Set decompress to false for HTTP Request to keep 1.x compatibility Fixes #3083
|
||||
- HTTP Request: Add unit tests for HTTP Request encodeURI and error response
|
||||
- HTTP Request: Do not throw HTTP errors in request node Fixes #3082
|
||||
- HTTP Request: Ensure uri is properly encoded before passing to got module Fixes #3080
|
||||
|
||||
#### 2.0.2: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Use file:// url with dynamic import
|
||||
- Detect if agent-base has patched https.request and undo it Fixes #3072
|
||||
|
||||
Editor
|
||||
|
||||
- Fix tab fade css because Safari Fixes #3073
|
||||
- Fix error closing library dialog with monaco
|
||||
- Handle other error types in Manage Palette view
|
||||
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request node - ignore invalid cookies rather than fail request Fixes #3075
|
||||
- Fix msg.reset handling in Delay node Fixes #3074
|
||||
|
||||
#### 2.0.1: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- Function: Ensure default module export is exposed in Function node
|
||||
|
||||
#### 2.0.0: Milestone Release
|
||||
|
||||
**Migration from 1.x**
|
||||
|
||||
- Node-RED now requires Node.js 12.x or later.
|
||||
|
||||
- The following nodes have had significant dependency updates. Unless stated,
|
||||
they should be fully backward compatible.
|
||||
|
||||
- RBE: Relabelled as 'filter' to make it more discoverable and made part of
|
||||
the core palette, rather than as a separate module.
|
||||
- Tail: This node has been removed from the default palette. You can reinstall it
|
||||
from node-red-node-tail
|
||||
- HTTP Request: Reimplemented with a different underlying module. We have
|
||||
tried to maintain 100% functional compatibility, but it is possible
|
||||
some edge cases remain.
|
||||
- JSON: The schema validation option no longer supports JSON-Schema draft-04
|
||||
- HTML: Its underlying module has had a major version update. Should be fully
|
||||
backward compatible.
|
||||
|
||||
- `functionExternalModules` is now enabled by default for new installs.
|
||||
If you have an existing settings file that contains this setting, you will
|
||||
need to set it to `true` yourself.
|
||||
|
||||
The external modules will now get installed in your Node-RED user directory,
|
||||
(`~/.node-red`) rather than in a subdirectory. This means all dependencies will
|
||||
be listed in your top-level `package.json`. If you have existing external modules,
|
||||
they will get reinstalled to the new location when you first run Node-RED 2.0.
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- Fix missing dependencies (#3052, #2057) @kazuhitoyokoi
|
||||
- Ensure node.types is defined if node html file missing
|
||||
- Fix reporting of type_already_registered error
|
||||
- Move install location of external modules (#3064) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Update translations (#3063) @kazuhitoyokoi
|
||||
- Add a slight fade to tab labels that overflow
|
||||
- Show config node details when selected in outliner
|
||||
- Fix layout of info outliner for subflow entries
|
||||
|
||||
Nodes
|
||||
|
||||
- Delay: let `msg.flush` specify how many messages to flush from node (#3059) @dceejay
|
||||
- Function: external modules is now enabled by default (#3065) @knolleary
|
||||
- Function: external modules now supports both ES6 and CJS modules (#3065) @knolleary
|
||||
- WebSocket: add option for client node to send automatic pings (#3056) @knolleary
|
||||
|
||||
|
||||
##### 2.0.0-beta.2: Beta Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Add `node-red admin init` (via `node-red-admin@2.1.0`)
|
||||
- Move to GH Actions rather than Travis for build (#3042) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Include hasUser=false config nodes when exporting whole flow (#3048)
|
||||
- Emit nodes:change for any updated config node when node deleted/added
|
||||
- Fix padding of compact notification Closes #3045
|
||||
- Ensure any html in changelog is escaped before displaying
|
||||
- Add support for Map/Set property types on Debug (#3040) @knolleary
|
||||
- Add 'theme' to default settings file
|
||||
- Add RED.view.annotations api (#3032) @knolleary
|
||||
- Update monaco editor to V0.25.2 (#3031) @Steve-Mcl
|
||||
- Lower tray zIndex when overlay tray being opened Fixes #3019
|
||||
- Reduce z-Index of Function expand buttons to prevent overlap Part of #3019
|
||||
- Ensure RED.clipboard.import displays the right library Fixes #3021
|
||||
- Batch messages sent over comms to prevent flooding (#3025) @knolleary
|
||||
- Allow RED.popover.panel to specify a closeButton to ignore click events on
|
||||
- Use browser default language for initial page load
|
||||
- Add css var for node font color
|
||||
- Fix label padding of toggleButton
|
||||
- Give sidebar open tab a bit more room for its label
|
||||
- Various Monaco updates (#3015) @Steve-Mcl
|
||||
- Log readOnly on startup (#3024) @sammachin
|
||||
- Translation updates (#3020 #3022) @HiroyasuNishiyama @kazuhitoyokoi
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request: Fix proxy handling (#3044) @hardillb
|
||||
- HTTP Request: Handle basic auth with @ in username (#3017) @hardillb
|
||||
- Add Japanese translation for file-in node (#3037 #3039) @kazuhitoyokoi
|
||||
- File In: Add option for file-in node to include all properties (default off) (#3035) @dceejay
|
||||
- Exec: add windowsHide option to hide windows under Windows (#3026) @natcl
|
||||
- Support loading external module sub path Fixes #3023
|
||||
|
||||
##### 2.0.0-beta.1: Beta Release
|
||||
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- [MAJOR] Set minimum node version to 12.
|
||||
- [MAJOR] Fix flowfile name to flows.json in settings (#2951) @dceejay
|
||||
- [MAJOR] Update to latest i18n in editor and runtime (#2940) @knolleary
|
||||
- [MAJOR] Deprecate usage of httpRoot (#2953) @knolleary
|
||||
- Add pre/postInstall hooks to npm install handling (#2936) @knolleary
|
||||
- Add engine-strict flag to npm install args (#2965) @nileio
|
||||
- Restructure default settings.js to be more organised (#3012) @knolleary
|
||||
- Ensure httpServerOptions gets applied to ALL the express apps
|
||||
- Allow RED.settings.set to replace string property with object property
|
||||
- Update debug tests to handle compact comms format
|
||||
- Updates to encode/decode message when passed over debug comms link
|
||||
- Remove all input event listeners on a node once it is closed
|
||||
- Move hooks to util package
|
||||
- Rework hooks structure to be a linkedlist
|
||||
- Update dependencies (#2922) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- [MAJOR] Change node id generation to give fixed length values without '.' (#2987) @knolleary
|
||||
- [MAJOR] Add Monaco code editor (#2971) @Steve-Mcl
|
||||
- Update to latest Monaco (#3007) @Steve-Mcl
|
||||
- Update Node-RED Function typings in Monaco (#3008) @Steve-Mcl
|
||||
- Add css named variables for certain key colours (#2994) @knolleary
|
||||
- Improve contrast of export dialog JSON font color
|
||||
- Switch editableList buttons from <a> to <button> elements
|
||||
- Add option to RED.nodes.createCompleteNodeSet to include node dimensions
|
||||
- Fix css of node help table of contents elements
|
||||
- Improve red-ui-node-icon css and add red-ui-node-icon-small modifier class
|
||||
- Add RED.hooks to editor
|
||||
- Add viewAddPort viewRemovePort viewAddNode viewRemoveNode hooks to view
|
||||
- Use paletteLabel if set in help sidebar
|
||||
- Add missing args from JSONata $now signature
|
||||
|
||||
Nodes
|
||||
|
||||
- [MAJOR] Relabel RBE node as 'filter' and move into core. Also remove tail (#2944) @dceejay
|
||||
- [MAJOR] HTTP Request: migrate to 'got' module (#2952) @knolleary
|
||||
- [MAJOR] Move Inject node to CronosJS module (#2959) @knolleary
|
||||
- [MAJOR] JSON: Update ajv to 8.2.0 - drop support for JSON-Schema draft-04 (#2969) @knolleary
|
||||
- [MAJOR] HTML node: cheerio update to 1.x (#3011) @knolleary
|
||||
- Join: change default manual mode to object (#2931) @knolleary
|
||||
- File node: Add fileWorkingDirectory (#2932) @knolleary
|
||||
- Delay node enhancements (#2294) @kazuhitoyokoi (#2949) @dceejay
|
||||
- Add Japanese translations for delay node enhancements (#2958) @kazuhitoyokoi
|
||||
- Inject node: reorder TypedInput options (#2961) @dceejay
|
||||
- HTTP Request: update to work with proxies (#2983) @hardillb (#3009) @hardillb
|
||||
- HTTP Request: fix msg.responseUrl (#2986) @hardillb
|
||||
- TLS: Add ALPN support to TLS node (#2988) @hardillb
|
||||
- Inject: add "Inject now" button to edit dialog (#2990) @Steve-Mcl
|
||||
|
||||
|
||||
|
||||
#### Older Releases
|
||||
|
||||
Change logs for older releases are available on GitHub: https://github.com/node-red/node-red/releases
|
||||
|
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
47
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.0.0-beta.4",
|
||||
"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",
|
||||
@@ -40,16 +40,16 @@
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "2.0.1",
|
||||
"express": "4.18.1",
|
||||
"denque": "2.1.0",
|
||||
"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.10",
|
||||
"i18next": "21.10.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "4.1.0",
|
||||
@@ -59,8 +59,8 @@
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.7",
|
||||
"mime": "3.0.0",
|
||||
"moment": "2.29.3",
|
||||
"moment-timezone": "0.5.34",
|
||||
"moment": "2.29.4",
|
||||
"moment-timezone": "0.5.39",
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
@@ -69,23 +69,23 @@
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.5.2",
|
||||
"passport": "0.6.0",
|
||||
"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.0",
|
||||
"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.8",
|
||||
"dompurify": "2.4.1",
|
||||
"grunt": "1.5.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.4.3",
|
||||
@@ -95,7 +95,7 @@
|
||||
"grunt-contrib-concat": "2.1.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-jshint": "3.2.0",
|
||||
"grunt-contrib-uglify": "5.2.1",
|
||||
"grunt-contrib-uglify": "5.2.2",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"grunt-jsdoc": "2.4.1",
|
||||
"grunt-jsdoc-to-markdown": "6.0.0",
|
||||
@@ -108,17 +108,18 @@
|
||||
"i18next-http-backend": "1.4.1",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "4.0.17",
|
||||
"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.16",
|
||||
"nodemon": "2.0.20",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.52.3",
|
||||
"sass": "1.56.1",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "6.2.3"
|
||||
"supertest": "6.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
@@ -266,9 +266,69 @@ module.exports = {
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.scripts = scriptFiles.concat(theme.page._.scripts || [])
|
||||
}
|
||||
if(theme.codeEditor) {
|
||||
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
|
||||
// check and load page settings from theme
|
||||
if (themePlugin.page) {
|
||||
if (themePlugin.page.favicon && !theme.page.favicon) {
|
||||
const result = serveFilesFromTheme(
|
||||
[themePlugin.page.favicon],
|
||||
themeApp,
|
||||
"/",
|
||||
themePlugin.path
|
||||
)
|
||||
if(result && result.length > 0) {
|
||||
// update themeContext page favicon
|
||||
themeContext.page.favicon = result[0]
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.favicon = result[0]
|
||||
}
|
||||
}
|
||||
if (themePlugin.page.tabicon && themePlugin.page.tabicon.icon && !theme.page.tabicon) {
|
||||
const result = serveFilesFromTheme(
|
||||
[themePlugin.page.tabicon.icon],
|
||||
themeApp,
|
||||
"/page/",
|
||||
themePlugin.path
|
||||
)
|
||||
if(result && result.length > 0) {
|
||||
// update themeContext page tabicon
|
||||
themeContext.page.tabicon.icon = result[0]
|
||||
themeContext.page.tabicon.colour = themeContext.page.tabicon.colour || themeContext.page.tabicon.colour
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.tabicon = theme.page._.tabicon || {}
|
||||
theme.page._.tabicon.icon = themeContext.page.tabicon.icon
|
||||
theme.page._.tabicon.colour = themeContext.page.tabicon.colour
|
||||
}
|
||||
}
|
||||
// if the plugin has a title AND the users settings.js does NOT
|
||||
if (themePlugin.page.title && !theme.page.title) {
|
||||
themeContext.page.title = themePlugin.page.title || themeContext.page.title
|
||||
}
|
||||
}
|
||||
// check and load header settings from theme
|
||||
if (themePlugin.header) {
|
||||
if (themePlugin.header.image && !theme.header.image) {
|
||||
const result = serveFilesFromTheme(
|
||||
[themePlugin.header.image],
|
||||
themeApp,
|
||||
"/header/",
|
||||
themePlugin.path
|
||||
)
|
||||
if(result && result.length > 0) {
|
||||
// update themeContext header image
|
||||
themeContext.header.image = result[0]
|
||||
}
|
||||
}
|
||||
// if the plugin has a title AND the users settings.js does NOT have a title
|
||||
if (themePlugin.header.title && !theme.header.title) {
|
||||
themeContext.header.title = themePlugin.header.title || themeContext.header.title
|
||||
}
|
||||
// if the plugin has a header url AND the users settings.js does NOT
|
||||
if (themePlugin.header.url && !theme.header.url) {
|
||||
themeContext.header.url = themePlugin.header.url || themeContext.header.url
|
||||
}
|
||||
}
|
||||
theme.codeEditor = theme.codeEditor || {}
|
||||
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
|
||||
}
|
||||
activeThemeInitialised = true;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "3.0.0-beta.4",
|
||||
"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.0-beta.4",
|
||||
"@node-red/editor-client": "3.0.0-beta.4",
|
||||
"@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",
|
||||
@@ -31,10 +31,10 @@
|
||||
"oauth2orize": "1.11.1",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.5.2",
|
||||
"passport": "0.6.0",
|
||||
"ws": "7.5.6"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.0.1"
|
||||
"bcrypt": "5.1.0"
|
||||
}
|
||||
}
|
||||
|
77
packages/node_modules/@node-red/editor-client/locales/de/editor.json
vendored
Executable file → Normal file
@@ -105,7 +105,7 @@
|
||||
"search": "Flows durchsuchen",
|
||||
"searchInput": "Flows durchsuchen",
|
||||
"subflows": "Subflow",
|
||||
"createSubflow": "Subflow",
|
||||
"createSubflow": "Hinzufügen",
|
||||
"selectionToSubflow": "Auswahl in Subflow umwandeln",
|
||||
"flows": "Flow",
|
||||
"add": "Hinzufügen",
|
||||
@@ -152,7 +152,8 @@
|
||||
"zoom-in": "Vergrößern",
|
||||
"search-flows": "Flows durchsuchen",
|
||||
"search-prev": "Vorherige",
|
||||
"search-next": "Nächste"
|
||||
"search-next": "Nächste",
|
||||
"search-counter": "\"__term__\" __result__ von __count__"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "Angemeldet als __name__",
|
||||
@@ -168,7 +169,11 @@
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"warning": "<strong>Warnung:</strong> __message__",
|
||||
"state": {
|
||||
"flowsStopped": "Flows gestoppt",
|
||||
"flowsStarted": "Flows gestartet"
|
||||
},
|
||||
"warning": "<strong>Warnung</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "Node hat nicht übernommene (deploy) Änderungen",
|
||||
"nodeActionDisabled": "Node-Aktionen deaktiviert",
|
||||
@@ -177,15 +182,15 @@
|
||||
"missing-modules": "<p>Flows angehalten aufgrund fehlender Module</p>",
|
||||
"safe-mode": "<p>Flows sind im abgesicherten Modus gestoppt.</p><p>Flows können bearbeitet und übernommen (deploy) werden, um sie neu zu starten.</p>",
|
||||
"restartRequired": "Node-RED muss neu gestartet werden, damit die Module nach Upgrade aktiviert werden",
|
||||
"credentials_load_failed": "<p>Flows gestoppt, da die Berechtigungen nicht entschlüsselt werden konnten.</p><p>Die Datei mit dem Flow-Berechtigungen ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p>",
|
||||
"credentials_load_failed_reset": "<p>Die Berechtigungen konnten nicht entschlüsselt werden.</p><p>Die Datei mit den Flow-Berechtigungen ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p><p>Die Datei mit den Flow-Berechtigungen wird bei der nächsten Übernahme (deploy) zurückgesetzt. Alle vorhandenen Flow-Berechtigungen werden gelöscht.</p>",
|
||||
"credentials_load_failed": "<p>Flows gestoppt, da die Credentials nicht entschlüsselt werden konnten.</p><p>Die Datei mit den Flow-Credentials ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p>",
|
||||
"credentials_load_failed_reset": "<p>Die Credentials konnten nicht entschlüsselt werden.</p><p>Die Datei mit den Flow-Credentials ist verschlüsselt, aber der Schlüssel des Projekts fehlt oder ist ungültig.</p><p>Die Datei mit den Flow-Credentials wird bei der nächsten Übernahme (deploy) zurückgesetzt. Alle vorhandenen Flow-Credentials werden gelöscht.</p>",
|
||||
"missing_flow_file": "<p>Die Flow-Datei des Projekts wurde nicht gefunden.</p><p>Das Projekt ist nicht mit einer Flow-Datei konfiguriert.</p>",
|
||||
"missing_package_file": "<p>Die Paket-Datei des Projekts wurde nicht gefunden.</p><p>In dem Projekt fehlt die 'package.json'-Datei.</p>",
|
||||
"project_empty": "<p>Das Projekt ist leer.</p><p>Soll ein Standardsatz an Projektdateien erstellen werden?<br/>Andernfalls müssen die Dateien manuell außerhalb des Editors dem Projekt hinzugefügt werden.</p>",
|
||||
"project_not_found": "<p>Das Projekt '__project__' wurde nicht gefunden.</p>",
|
||||
"git_merge_conflict": "<p>Der automatische Merge der Änderungen ist fehlgeschlagen.</p><p>Die Merge-Konflikte müssen behoben und die Ergebnisse ins Repository übertragen werden (commit).</p>"
|
||||
},
|
||||
"error": "<strong>Fehler:</strong> __message__",
|
||||
"error": "<strong>Fehler</strong>: __message__",
|
||||
"errors": {
|
||||
"lostConnection": "Verbindung zum Server verloren. Verbindung wird erneut hergestellt ...",
|
||||
"lostConnectionReconnect": "Verbindung zum Server verloren. Wiederherstellung der Verbindung in __time__s.",
|
||||
@@ -203,7 +208,7 @@
|
||||
"pull": "Projekt '__project__' erneut geladen",
|
||||
"revert": "Änderungen im Projekt '__project__' rückgängig gemacht",
|
||||
"merge-complete": "Git-Merge abgeschlossen",
|
||||
"setupCredentials": "Berechtigungen einrichten",
|
||||
"setupCredentials": "Credentials einrichten",
|
||||
"setupProjectFiles": "Projektdateien einrichten",
|
||||
"no": "Nein, Danke",
|
||||
"createDefault": "Standardprojektdateien erstellen",
|
||||
@@ -211,7 +216,7 @@
|
||||
},
|
||||
"label": {
|
||||
"manage-project-dep": "Projektabhängigkeiten verwalten",
|
||||
"setup-cred": "Berechtigungen einrichten",
|
||||
"setup-cred": "Credentials einrichten",
|
||||
"setup-project": "Projektdateien einrichten",
|
||||
"create-default-package": "Standardpaketdatei erstellen",
|
||||
"no-thanks": "Nein, Danke",
|
||||
@@ -295,6 +300,10 @@
|
||||
"modifiedFlowsDesc": "Übernimmt nur Flows, die geänderte Nodes enthalten",
|
||||
"modifiedNodes": "Geänderte Nodes",
|
||||
"modifiedNodesDesc": "Übernimmt nur Nodes, die sich geändert haben",
|
||||
"startFlows": "Start",
|
||||
"startFlowsDesc": "Flows starten",
|
||||
"stopFlows": "Stop",
|
||||
"stopFlowsDesc": "Flows stoppen",
|
||||
"restartFlows": "Flows neustarten",
|
||||
"restartFlowsDesc": "Startet die aktuell übernommenen Flows (ohne vorheriges Deploy)",
|
||||
"successfulDeploy": "Erfolgreich übernommen (deploy)",
|
||||
@@ -376,7 +385,7 @@
|
||||
"confirmDelete": "Sind Sie sicher mit dem Löschen dieses Subflows?",
|
||||
"info": "Beschreibung",
|
||||
"category": "Kategorie",
|
||||
"module": "Module",
|
||||
"module": "Modul",
|
||||
"license": "Lizenz",
|
||||
"licenseNone": "Keine",
|
||||
"licenseOther": "Andere",
|
||||
@@ -434,7 +443,7 @@
|
||||
"icon": "Icon",
|
||||
"inputType": "Eingangstyp",
|
||||
"selectType": "Wähle Typen ...",
|
||||
"loadCredentials": "Lade Node-Berechtigungen",
|
||||
"loadCredentials": "Lade Node-Credentials",
|
||||
"inputs": {
|
||||
"input": "Eingang",
|
||||
"select": "Auswahl",
|
||||
@@ -450,7 +459,7 @@
|
||||
"json": "JSON",
|
||||
"bin": "buffer",
|
||||
"env": "Umgebungsvariable",
|
||||
"cred": "Berechtigung"
|
||||
"cred": "Credentials"
|
||||
},
|
||||
"menu": {
|
||||
"input": "Eingang",
|
||||
@@ -470,7 +479,7 @@
|
||||
"errors": {
|
||||
"scopeChange": "Wenn Sie den Geltungsbereich (scope) ändern, wird er für Nodes in anderen Flows nicht verfügbar sein",
|
||||
"invalidProperties": "Ungültige Eigenschaften:",
|
||||
"credentialLoadFailed": "Laden der Node-Berechtigungen fehlgeschlagen"
|
||||
"credentialLoadFailed": "Laden der Node-Credentials fehlgeschlagen"
|
||||
}
|
||||
},
|
||||
"keyboard": {
|
||||
@@ -683,7 +692,8 @@
|
||||
"showHelp": "Hilfe zeigen",
|
||||
"showInOutline": "Zeige im Editor",
|
||||
"showTopics": "Zeige Hilfethemen",
|
||||
"noHelp": "Kein Hilfethema ausgewählt"
|
||||
"noHelp": "Kein Hilfethema ausgewählt",
|
||||
"changeLog": "Änderungsprotokoll"
|
||||
},
|
||||
"config": {
|
||||
"name": "Konfigurations-Node",
|
||||
@@ -737,7 +747,7 @@
|
||||
"addToProject": "Zu Projekt hinzufügen",
|
||||
"files": "Dateien",
|
||||
"flow": "Flow",
|
||||
"credentials": "Berechtigungen",
|
||||
"credentials": "Credentials",
|
||||
"package": "Paket",
|
||||
"packageCreate": "Datei wird erstellt beim Speichern der Änderungen",
|
||||
"fileNotExist": "Datei existiert nicht",
|
||||
@@ -750,7 +760,7 @@
|
||||
"changeTheEncryptionKey": "Schlüssel ändern",
|
||||
"currentKey": "Aktueller Schlüssel",
|
||||
"newKey": "Neuer Schlüssel",
|
||||
"credentialsAlert": "Dadurch werden alle vorhandenen Berechtigungen gelöscht",
|
||||
"credentialsAlert": "Dadurch werden alle vorhandenen Credentials gelöscht",
|
||||
"versionControl": "Versionsverwaltung (Git)",
|
||||
"branches": "Branches",
|
||||
"noBranches": "Keine Branches",
|
||||
@@ -886,7 +896,7 @@
|
||||
"date": "timestamp",
|
||||
"jsonata": "JSONata",
|
||||
"env": "Umgebungsvariable",
|
||||
"cred": "Berechtigung"
|
||||
"cred": "Credentials"
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
@@ -1026,7 +1036,7 @@
|
||||
"passphrase": "Passphrase",
|
||||
"ssh-key-desc": "Bevor Sie ein Repository über SSH lokal klonen können, müssen Sie einen SSH-Schlüssel hinzufügen, um auf diesen zugreifen zu können",
|
||||
"ssh-key-add": "SSH-Schlüssel hinzufügen",
|
||||
"credential-key": "Schlüssel für Berechtigungen",
|
||||
"credential-key": "Schlüssel für Credentials",
|
||||
"cant-get-ssh-key": "Fehler! Der ausgewählte SSH-Schlüsselpfad kann nicht abgerufen werden",
|
||||
"already-exists2": "bereits vorhanden",
|
||||
"git-error": "Git-Fehler",
|
||||
@@ -1038,27 +1048,27 @@
|
||||
"create": "Erstellen Sie Ihre Projektdateien",
|
||||
"desc0": "Ein Projekt enthält Ihre Flow-Dateien, eine README-Datei und die 'package.json'-Datei.",
|
||||
"desc1": "Es kann alle anderen Dateien enthalten, die im Git-Repository verwaltet werden sollen.",
|
||||
"desc2": "Ihre vorhandenen Flow- und Berechtigungs-Dateien werden in das Projekt kopiert.",
|
||||
"desc2": "Ihre vorhandenen Flow- und Credential-Dateien werden in das Projekt kopiert.",
|
||||
"flow-file": "Flow-Datei",
|
||||
"credentials-file": "Datei mit Berechtigungen"
|
||||
"credentials-file": "Datei mit Credentials"
|
||||
},
|
||||
"encryption-config": {
|
||||
"setup": "Einrichtung der Verschlüsselung Ihrer Datei mit den Berechtigungen",
|
||||
"desc0": "Die Datei mit den Flow-Berechtigungen kann verschlüsselt werden, um ihren Inhalt zu schützen.",
|
||||
"desc1": "Wenn Sie diese Berechtigungen in einem öffentlichen Repository speichern möchten, müssen Sie sie mit einen geheimen Schlüsselausdruck verschlüsseln.",
|
||||
"desc2": "Die Datei mit den Flow-Berechtigungen ist derzeit nicht verschlüsselt.",
|
||||
"setup": "Einrichtung der Verschlüsselung Ihrer Datei mit den Credentials",
|
||||
"desc0": "Die Datei mit den Flow-Credentials kann verschlüsselt werden, um ihren Inhalt zu schützen.",
|
||||
"desc1": "Wenn Sie diese Credentials in einem öffentlichen Repository speichern möchten, müssen Sie sie mit einen geheimen Schlüsselausdruck verschlüsseln.",
|
||||
"desc2": "Die Datei mit den Flow-Credentials ist derzeit nicht verschlüsselt.",
|
||||
"desc3": "D.h. ihr Inhalt (z.B. Passwörter und Zugriffs-Tokens) kann von jedem mit Zugriff auf die Datei gelesen werden.",
|
||||
"desc4": "Wenn Sie diese Berechtigungen in einen öffentlichen Repository speichern möchten, müssen Sie diese verschlüsseln, indem Sie einen geheimen Schlüsselausdruck eingeben.",
|
||||
"desc5": "Ihre Datei mit den Flow-Berechtigungen wird derzeit mit dem Eintrag 'credentialSecret' Ihrer Einstellungsdatei als Schlüssel verschlüsselt.",
|
||||
"desc6": "Die Datei mit den Flow-Berechtigungen wird derzeit mit einem vom System generierten Schlüssel verschlüsselt. Sie sollten einen neuen geheimen Schlüssel für dieses Projekt vorgeben.",
|
||||
"desc4": "Wenn Sie diese Credentials in einen öffentlichen Repository speichern möchten, müssen Sie diese verschlüsseln, indem Sie einen geheimen Schlüsselausdruck eingeben.",
|
||||
"desc5": "Ihre Datei mit den Flow-Credentials wird derzeit mit dem Eintrag 'credentialSecret' Ihrer Einstellungsdatei als Schlüssel verschlüsselt.",
|
||||
"desc6": "Die Datei mit den Flow-Credentials wird derzeit mit einem vom System generierten Schlüssel verschlüsselt. Sie sollten einen neuen geheimen Schlüssel für dieses Projekt vorgeben.",
|
||||
"desc7": "Der Schlüssel wird separat von den Projektdateien gespeichert. Sie müssen den Schlüssel angeben, damit dieses Projekt auch in einem anderen Node-RED-System verwendet werden kann.",
|
||||
"credentials": "Berechtigung",
|
||||
"credentials": "Credentials",
|
||||
"enable": "Verschlüsselung aktivieren",
|
||||
"disable": "Verschlüsselung deaktivieren",
|
||||
"disabled": "deaktiviert",
|
||||
"copy": "Vorhandenen Schlüssel ersetzen",
|
||||
"use-custom": "Eigenen Schlüssel verwenden",
|
||||
"desc8": "Die Datei mit den Berechtigungen wird nicht verschlüsselt, und ihr Inhalt kann leicht gelesen werden",
|
||||
"desc8": "Die Datei mit den Credentials wird nicht verschlüsselt und ihr Inhalt kann leicht gelesen werden",
|
||||
"create-project-files": "Projektdateien erstellen",
|
||||
"create-project": "Projekt erstellen",
|
||||
"already-exists": "bereits vorhanden",
|
||||
@@ -1083,12 +1093,12 @@
|
||||
"desc": "Beschreibung",
|
||||
"opt": "Optional",
|
||||
"flow-file": "Flow-Datei",
|
||||
"credentials": "Berechtigungen",
|
||||
"credentials": "Credentials",
|
||||
"enable-encryption": "Verschlüsselung aktivieren",
|
||||
"disable-encryption": "Verschlüsselung deaktivieren",
|
||||
"encryption-key": "Schlüssel",
|
||||
"desc0": "Eine Floskel, mit der Sie Ihre Berechtigungen schützen",
|
||||
"desc1": "Die Datei mit den Berechtigungen wird nicht verschlüsselt, und ihr Inhalt kann leicht gelesen werden",
|
||||
"desc0": "Eine Ausdruck, mit der Sie Ihre Credentials schützen",
|
||||
"desc1": "Die Datei mit den Credentials wird nicht verschlüsselt und ihr Inhalt kann leicht gelesen werden",
|
||||
"git-url": "Git-Repository-URL",
|
||||
"protocols": "https://, ssh:// oder file://",
|
||||
"auth-failed": "Authentifizierung fehlgeschlagen",
|
||||
@@ -1098,7 +1108,7 @@
|
||||
"passphrase": "Passphrase",
|
||||
"desc2": "Bevor Sie ein Repository über SSH klonen können, müssen Sie einen SSH-Schlüssel hinzufügen, um auf diesen zu zugreifen",
|
||||
"add-ssh-key": "Einen SSH-Schlüssel hinzufügen",
|
||||
"credentials-encryption-key": "Schlüssel für Berechtigungen",
|
||||
"credentials-encryption-key": "Schlüssel für Credentials",
|
||||
"already-exists-2": "bereits vorhanden",
|
||||
"git-error": "Git-Fehler",
|
||||
"con-failed": "Verbindung fehlgeschlagen",
|
||||
@@ -1156,7 +1166,8 @@
|
||||
"tourGuide": {
|
||||
"takeATour": "Tour starten",
|
||||
"start": "Start",
|
||||
"next": "Nächste"
|
||||
"next": "Nächste",
|
||||
"welcomeTours": "Welcome Tours"
|
||||
},
|
||||
"diagnostics": {
|
||||
"title": "System-Informationen"
|
||||
|
0
packages/node_modules/@node-red/editor-client/locales/de/infotips.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/de/jsonata.json
vendored
Executable file → Normal file
33
packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
vendored
Executable file → Normal 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",
|
||||
@@ -936,6 +948,9 @@
|
||||
"invalid-expr": "Invalid JSONata expression:\n __message__",
|
||||
"invalid-msg": "Invalid example JSON message:\n __message__",
|
||||
"context-unsupported": "Cannot test context functions\n $flowContext or $globalContext",
|
||||
"env-unsupported": "Cannot test $env function",
|
||||
"moment-unsupported": "Cannot test $moment function",
|
||||
"clone-unsupported": "Cannot test $clone function",
|
||||
"eval": "Error evaluating expression:\n __message__"
|
||||
}
|
||||
},
|
||||
@@ -981,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",
|
||||
@@ -1203,5 +1221,10 @@
|
||||
"node": "Node",
|
||||
"junction": "Junction",
|
||||
"linkNodes": "Link Nodes"
|
||||
},
|
||||
"env-var": {
|
||||
"environment": "Environment",
|
||||
"header": "Global Environment Variables",
|
||||
"revert": "Revert"
|
||||
}
|
||||
}
|
||||
|
0
packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json
vendored
Executable file → Normal 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": "ヘルプ",
|
||||
@@ -935,8 +943,11 @@
|
||||
"errors": {
|
||||
"invalid-expr": "不正なJSONata式:\n __message__",
|
||||
"invalid-msg": "不正なJSONメッセージ例:\n __message__",
|
||||
"context-unsupported": "$flowContext や $globalContextの\nコンテキスト機能をテストできません",
|
||||
"eval": "表現評価エラー:\n __message__"
|
||||
"context-unsupported": "$flowContext や $globalContextの\nコンテキスト関数をテストできません",
|
||||
"env-unsupported": "$env関数はテストできません",
|
||||
"moment-unsupported": "$moment関数はテストできません",
|
||||
"clone-unsupported": "$clone関数はテストできません",
|
||||
"eval": "式評価エラー:\n __message__"
|
||||
}
|
||||
},
|
||||
"monaco": {
|
||||
@@ -981,7 +992,10 @@
|
||||
"quote": "引用",
|
||||
"link": "リンク",
|
||||
"horizontal-rule": "区切り線",
|
||||
"toggle-preview": "プレビュー表示切替え"
|
||||
"toggle-preview": "プレビュー表示切替え",
|
||||
"mermaid": {
|
||||
"summary": "Mermaid図"
|
||||
}
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "バッファエディタ",
|
||||
@@ -1168,8 +1182,7 @@
|
||||
"takeATour": "ツアーを開始",
|
||||
"start": "開始",
|
||||
"next": "次へ",
|
||||
"welcomeTours": "ウェルカムツアー",
|
||||
"tours": "ツアー"
|
||||
"welcomeTours": "ウェルカムツアー"
|
||||
},
|
||||
"diagnostics": {
|
||||
"title": "システム情報"
|
||||
@@ -1348,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": "破棄"
|
||||
}
|
||||
}
|
||||
|
0
packages/node_modules/@node-red/editor-client/locales/ko/editor.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/ko/infotips.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/ko/jsonata.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/ru/editor.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/ru/infotips.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/ru/jsonata.json
vendored
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -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 = {};
|
||||
|
@@ -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]) {
|
||||
@@ -868,14 +902,7 @@ RED.nodes = (function() {
|
||||
var node;
|
||||
|
||||
if (allNodes.hasTab(id)) {
|
||||
removedNodes = allNodes.getNodes(id).filter(n => {
|
||||
if (n.type === 'junction') {
|
||||
removedJunctions.push(n)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
removedNodes = allNodes.getNodes(id).slice()
|
||||
}
|
||||
for (i in configNodes) {
|
||||
if (configNodes.hasOwnProperty(i)) {
|
||||
@@ -885,6 +912,7 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
removedJunctions = RED.nodes.junctions(id)
|
||||
|
||||
for (i=0;i<removedNodes.length;i++) {
|
||||
var result = removeNode(removedNodes[i].id);
|
||||
@@ -1052,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];
|
||||
}
|
||||
}
|
||||
@@ -1331,7 +1362,6 @@ RED.nodes = (function() {
|
||||
} else {
|
||||
nodeSet = [sf];
|
||||
}
|
||||
console.log(nodeSet);
|
||||
return createExportableNodeSet(nodeSet);
|
||||
}
|
||||
/**
|
||||
@@ -1367,6 +1397,10 @@ RED.nodes = (function() {
|
||||
exportedConfigNodes[n.id] = true;
|
||||
}
|
||||
});
|
||||
|
||||
subflowSet = subflowSet.concat(RED.nodes.junctions(subflowId))
|
||||
subflowSet = subflowSet.concat(RED.nodes.groups(subflowId))
|
||||
|
||||
var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes);
|
||||
nns = exportableSubflow.concat(nns);
|
||||
}
|
||||
@@ -1968,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;
|
||||
}
|
||||
@@ -2070,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) {
|
||||
@@ -2318,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;
|
||||
}
|
||||
@@ -2353,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
|
||||
@@ -2375,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();
|
||||
|
||||
@@ -2503,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]);
|
||||
});
|
||||
@@ -2528,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);
|
||||
@@ -2552,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;
|
||||
@@ -2559,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)
|
||||
@@ -2743,6 +2812,7 @@ RED.nodes = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
const nodeGroupMap = {}
|
||||
var replaceNodeIds = Object.keys(replaceNodes);
|
||||
if (replaceNodeIds.length > 0) {
|
||||
var reimportList = [];
|
||||
@@ -2753,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);
|
||||
});
|
||||
@@ -2774,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)) {
|
||||
@@ -2834,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,
|
||||
|
||||
|
@@ -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()
|
||||
@@ -766,7 +796,7 @@ var RED = (function() {
|
||||
$('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header);
|
||||
$('<div id="red-ui-main-container" class="red-ui-sidebar-closed hide">'+
|
||||
'<div id="red-ui-workspace"></div>'+
|
||||
'<div id="red-ui-editor-stack"></div>'+
|
||||
'<div id="red-ui-editor-stack" tabindex="-1"></div>'+
|
||||
'<div id="red-ui-palette"></div>'+
|
||||
'<div id="red-ui-sidebar"></div>'+
|
||||
'<div id="red-ui-sidebar-separator"></div>'+
|
||||
|
@@ -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();
|
||||
|
@@ -160,7 +160,7 @@
|
||||
this.element.css("maxHeight",null);
|
||||
}
|
||||
if (this.options.height !== 'auto') {
|
||||
this.uiContainer.css("overflow-y","scroll");
|
||||
this.uiContainer.css("overflow-y","auto");
|
||||
if (!isNaN(this.options.height)) {
|
||||
this.uiHeight = this.options.height;
|
||||
}
|
||||
|
@@ -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"));
|
||||
}
|
||||
|
@@ -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;
|
||||
},
|
||||
|
@@ -90,10 +90,10 @@
|
||||
optEl.append(generateSpans(srcMatch));
|
||||
optEl.appendTo(element);
|
||||
}
|
||||
matches.push({
|
||||
value: optVal,
|
||||
label: element,
|
||||
i: (valMatch.found ? valMatch.index : srcMatch.index)
|
||||
matches.push({
|
||||
value: optVal,
|
||||
label: element,
|
||||
i: (valMatch.found ? valMatch.index : srcMatch.index)
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -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"] },
|
||||
@@ -501,7 +501,7 @@
|
||||
this.options.types = this.options.types||Object.keys(allOptions);
|
||||
}
|
||||
|
||||
this.selectTrigger = $('<button class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
|
||||
this.selectTrigger = $('<button type="button" class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
|
||||
$('<i class="red-ui-typedInput-icon fa fa-caret-down"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
|
||||
|
||||
this.selectLabel = $('<span class="red-ui-typedInput-type-label"></span>').appendTo(this.selectTrigger);
|
||||
@@ -570,7 +570,7 @@
|
||||
})
|
||||
|
||||
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
|
||||
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
|
||||
this.optionSelectTrigger = $('<button type="button" tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
|
||||
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
|
||||
// RED.popover.tooltip(this.optionSelectLabel,function() {
|
||||
// return that.optionValue;
|
||||
@@ -591,7 +591,7 @@
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
});
|
||||
|
||||
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
|
||||
this.optionExpandButton = $('<button type="button" tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
|
||||
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
|
||||
|
||||
this.type(this.typeField.val() || this.options.default||this.typeList[0].value);
|
||||
|
@@ -1,25 +1,6 @@
|
||||
RED.contextMenu = (function() {
|
||||
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");
|
||||
@@ -32,138 +13,185 @@ 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 hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
const hasLinks = selection.links && selection.links.length > 0;
|
||||
const isSingleLink = !hasSelection && hasLinks && selection.links.length === 1
|
||||
const isMultipleLinks = !hasSelection && hasLinks && selection.links.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()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
},
|
||||
( hasSelection || hasLinks ) ? {
|
||||
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.redraw(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: RED._("contextMenu.linkNodes"),
|
||||
onselect: 'core:split-wire-with-link-nodes',
|
||||
disabled: hasSelection || !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(
|
||||
// {
|
||||
// label: (isSingleLink || isMultipleLinks)?'Insert into wire...':'Add node...',
|
||||
// onselect: function() {
|
||||
// RED.view.showQuickAddDialog({
|
||||
// position: [ options.x - offset.left, options.y - offset.top ],
|
||||
// touchTrigger: true,
|
||||
// splice: isSingleLink?selection.links[0]:undefined,
|
||||
// spliceMultiple: isMultipleLinks
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// )
|
||||
// if (hasLinks && !hasSelection) {
|
||||
// menuItems.push({ onselect: 'core:split-wires-with-junctions', label: 'Insert junction'})
|
||||
// }
|
||||
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(
|
||||
{ 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,
|
||||
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";
|
||||
var MENU_WIDTH = 500; // can not use menu width here
|
||||
if ((options.x -$(document).scrollLeft()) >
|
||||
($(window).width() -MENU_WIDTH)) {
|
||||
direction = "left";
|
||||
}
|
||||
|
||||
menu = RED.menu.init({
|
||||
direction: 'right',
|
||||
direction: direction,
|
||||
onpreselect: function() {
|
||||
disposeMenu()
|
||||
},
|
||||
onpostselect: function() {
|
||||
onpostselect: function () {
|
||||
RED.view.focus()
|
||||
},
|
||||
options: menuItems
|
||||
});
|
||||
|
||||
menu.attr("id","red-ui-workspace-context-menu");
|
||||
menu.attr("id", "red-ui-workspace-context-menu");
|
||||
menu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
@@ -174,34 +202,35 @@ RED.contextMenu = (function() {
|
||||
var top = options.y
|
||||
var left = options.x
|
||||
|
||||
if (top+menu.height()-$(document).scrollTop() > $(window).height()) {
|
||||
top -= (top+menu.height())-$(window).height() + 22;
|
||||
if (top + menu.height() - $(document).scrollTop() > $(window).height()) {
|
||||
top -= (top + menu.height()) - $(window).height() + 22;
|
||||
}
|
||||
if (left+menu.width()-$(document).scrollLeft() > $(window).width()) {
|
||||
left -= (left+menu.width())-$(window).width() + 18;
|
||||
if (left + menu.width() - $(document).scrollLeft() > $(window).width()) {
|
||||
left -= (left + menu.width()) - $(window).width() + 18;
|
||||
}
|
||||
menu.css({
|
||||
top: top+"px",
|
||||
left: left+"px"
|
||||
top: top + "px",
|
||||
left: left + "px"
|
||||
})
|
||||
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
||||
$(document).on("mousedown.red-ui-workspace-context-menu", function(evt) {
|
||||
$(document).on("mousedown.red-ui-workspace-context-menu", function (evt) {
|
||||
if (menu && menu[0].contains(evt.target)) {
|
||||
return
|
||||
}
|
||||
disposeMenu()
|
||||
});
|
||||
menu.show();
|
||||
|
||||
// menu.show({
|
||||
// target: $('#red-ui-main-container'),
|
||||
// x: options.x,
|
||||
// y: options.y
|
||||
// })
|
||||
|
||||
// set focus to first item so that pressing escape key closes the menu
|
||||
$("#red-ui-workspace-context-menu :first(ul) > a").trigger("focus")
|
||||
|
||||
}
|
||||
|
||||
// Allow escape key hook and other editor events to close context menu
|
||||
RED.keyboard.add("red-ui-workspace-context-menu", "escape", function () { RED.contextMenu.hide() })
|
||||
RED.events.on("editor:open", function () { RED.contextMenu.hide() });
|
||||
RED.events.on("search:open", function () { RED.contextMenu.hide() });
|
||||
RED.events.on("type-search:open", function () { RED.contextMenu.hide() });
|
||||
RED.events.on("actionList:open", function () { RED.contextMenu.hide() });
|
||||
RED.events.on("view:selection-changed", function () { RED.contextMenu.hide() });
|
||||
return {
|
||||
show: show,
|
||||
hide: disposeMenu
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
@@ -1105,6 +1107,10 @@ RED.editor = (function() {
|
||||
if (editing_node) {
|
||||
RED.sidebar.info.refresh(editing_node);
|
||||
RED.sidebar.help.show(editing_node.type, false);
|
||||
//ensure focused element is NOT body (for keyboard scope to operate correctly)
|
||||
if (document.activeElement.tagName === 'BODY') {
|
||||
$('#red-ui-editor-stack').trigger('focus')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1847,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",
|
||||
@@ -1892,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',
|
||||
@@ -1906,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();
|
||||
|
@@ -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 {
|
||||
|
@@ -100,7 +100,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
"node-red-util": {package: "node-red", module: "util", path: "node-red/util.d.ts" },
|
||||
"node-red-func": {package: "node-red", module: "func", path: "node-red/func.d.ts" },
|
||||
}
|
||||
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"] ];
|
||||
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"] , knownModules["util"] ];
|
||||
|
||||
const modulesCache = {};
|
||||
|
||||
@@ -764,7 +764,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
|
||||
|
||||
if(!options.stateId && options.stateId !== false) {
|
||||
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title).split("/").pop());
|
||||
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title || "").split("/").pop());
|
||||
}
|
||||
var el = options.element || $("#"+options.id)[0];
|
||||
var toolbarRow = $("<div>").appendTo(el);
|
||||
|
@@ -76,6 +76,9 @@ RED.editor.colorPicker = RED.colorPicker = (function() {
|
||||
var focusTarget = colorInput;
|
||||
colorInput.on("change", function (e) {
|
||||
var color = colorInput.val();
|
||||
if (options.defaultValue && !color.match(/^([a-z]+|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3})$/)) {
|
||||
color = options.defaultValue;
|
||||
}
|
||||
colorHiddenInput.val(color).trigger('change');
|
||||
refreshDisplay(color);
|
||||
});
|
||||
|
@@ -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
|
||||
|
@@ -255,6 +255,9 @@
|
||||
var currentExpression = expressionEditor.getValue();
|
||||
var expr;
|
||||
var usesContext = false;
|
||||
var usesEnv = false;
|
||||
var usesMoment = false;
|
||||
var usesClone = false;
|
||||
var legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
|
||||
$(".red-ui-editor-type-expression-legacy").toggle(legacyMode);
|
||||
try {
|
||||
@@ -267,6 +270,18 @@
|
||||
usesContext = true;
|
||||
return null;
|
||||
});
|
||||
expr.assign("env", function(name) {
|
||||
usesEnv = true;
|
||||
return null;
|
||||
});
|
||||
expr.assign("moment", function(name) {
|
||||
usesMoment = true;
|
||||
return null;
|
||||
});
|
||||
expr.assign("clone", function(name) {
|
||||
usesClone = true;
|
||||
return null;
|
||||
});
|
||||
} catch(err) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.invalid-expr",{message:err.message}),-1);
|
||||
return;
|
||||
@@ -284,6 +299,18 @@
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
|
||||
return;
|
||||
}
|
||||
if (usesEnv) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.env-unsupported"),-1);
|
||||
return;
|
||||
}
|
||||
if (usesMoment) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.moment-unsupported"),-1);
|
||||
return;
|
||||
}
|
||||
if (usesClone) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.clone-unsupported"),-1);
|
||||
return;
|
||||
}
|
||||
|
||||
var formattedResult;
|
||||
if (result !== undefined) {
|
||||
|
@@ -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);
|
||||
})();
|
||||
|
@@ -235,6 +235,7 @@
|
||||
RED.editor.colorPicker.create({
|
||||
id: "red-ui-editor-node-color",
|
||||
value: color,
|
||||
defaultValue: "#DDAA99",
|
||||
palette: recommendedColors,
|
||||
sortPalette: function (a, b) {return a.l - b.l;}
|
||||
}).appendTo(colorRow);
|
||||
|
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
175
packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
vendored
Normal 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,
|
||||
};
|
||||
|
||||
})();
|
@@ -101,6 +101,7 @@ RED.group = (function() {
|
||||
RED.editor.colorPicker.create({
|
||||
id:"node-input-style-stroke",
|
||||
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
|
||||
defaultValue: "#a4a4a4",
|
||||
palette: colorPalette,
|
||||
cellPerRow: colorCount,
|
||||
cellWidth: 16,
|
||||
@@ -112,6 +113,7 @@ RED.group = (function() {
|
||||
RED.editor.colorPicker.create({
|
||||
id:"node-input-style-fill",
|
||||
value: style.fill || defaultGroupStyle.fill ||"none",
|
||||
defaultValue: "none",
|
||||
palette: colorPalette,
|
||||
cellPerRow: colorCount,
|
||||
cellWidth: 16,
|
||||
@@ -129,6 +131,7 @@ RED.group = (function() {
|
||||
RED.editor.colorPicker.create({
|
||||
id:"node-input-style-color",
|
||||
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
|
||||
defaultValue: "#a4a4a4",
|
||||
palette: colorPalette,
|
||||
cellPerRow: colorCount,
|
||||
cellWidth: 16,
|
||||
@@ -185,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) {
|
||||
@@ -199,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() })
|
||||
@@ -261,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();
|
||||
@@ -295,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) {
|
||||
@@ -308,10 +315,12 @@ RED.group = (function() {
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:[group]});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
function ungroupSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -330,10 +339,12 @@ RED.group = (function() {
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:newSelection})
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function ungroup(g) {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
var nodes = [];
|
||||
var parentGroup = RED.nodes.group(g.g);
|
||||
g.nodes.forEach(function(n) {
|
||||
@@ -360,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) {
|
||||
@@ -424,10 +436,12 @@ RED.group = (function() {
|
||||
});
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function removeSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -451,9 +465,11 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
RED.view.select({nodes:selection.nodes})
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
function createGroup(nodes) {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -476,7 +492,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
group.z = nodes[0].z;
|
||||
RED.nodes.addGroup(group);
|
||||
group = RED.nodes.addGroup(group);
|
||||
|
||||
try {
|
||||
addToGroup(group,nodes);
|
||||
@@ -559,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
46
packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js
vendored
Normal 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,
|
||||
};
|
||||
})();
|
180
packages/node_modules/@node-red/editor-client/src/js/ui/palette.js
vendored
Executable file → Normal file
@@ -175,9 +175,19 @@ RED.palette = (function() {
|
||||
$('<button type="button" onclick="RED.workspaces.show(\''+type.substring(8).replace(/'/g,"\\'")+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-pencil"></i></button>').appendTo(popOverContent)
|
||||
}
|
||||
|
||||
var safeType = type.replace(/'/g,"\\'");
|
||||
const safeType = type.replace(/'/g,"\\'");
|
||||
const wrapStr = function (str) {
|
||||
if(str.indexOf(' ') >= 0) {
|
||||
return '"' + str + '"'
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
$('<button type="button" onclick="RED.search.show(\'type:'+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>').appendTo(popOverContent)
|
||||
$('<button type="button"; return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>')
|
||||
.appendTo(popOverContent)
|
||||
.on('click', function() {
|
||||
RED.search.show('type:' + wrapStr(safeType))
|
||||
})
|
||||
$('<button type="button" onclick="RED.sidebar.help.show(\''+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
|
||||
|
||||
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
|
||||
@@ -282,6 +292,7 @@ RED.palette = (function() {
|
||||
var hoverGroup;
|
||||
var paletteWidth;
|
||||
var paletteTop;
|
||||
var dropEnabled;
|
||||
$(d).draggable({
|
||||
helper: 'clone',
|
||||
appendTo: '#red-ui-editor',
|
||||
@@ -289,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;
|
||||
@@ -299,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,6 +438,7 @@ RED.palette = (function() {
|
||||
categoryNode.find(".red-ui-palette-content").slideToggle();
|
||||
categoryNode.find("i").toggleClass("expanded");
|
||||
}
|
||||
categoryNode.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,6 +517,7 @@ RED.palette = (function() {
|
||||
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
|
||||
currentCategoryNode.find("i").toggleClass("expanded");
|
||||
}
|
||||
currentCategoryNode.hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
22
packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js
vendored
Executable file → Normal file
@@ -545,7 +545,7 @@ RED.projects = (function() {
|
||||
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
|
||||
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.clone-project.ssh-key-desc")+'</div>').appendTo(sshwarningRow);
|
||||
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
dialog.dialog( "close" );
|
||||
RED.userSettings.show('gitconfig');
|
||||
@@ -1171,11 +1171,11 @@ RED.projects = (function() {
|
||||
|
||||
row = $('<div class="form-row button-group"></div>').appendTo(container);
|
||||
|
||||
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
|
||||
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
|
||||
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
|
||||
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
|
||||
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
|
||||
var openProject = $('<button type="button" data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
|
||||
var createAsEmpty = $('<button type="button" data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
|
||||
// var createAsCopy = $('<button type="button" data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
|
||||
var createAsClone = $('<button type="button" data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
|
||||
// var createAsClone = $('<button type="button" data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
|
||||
row.find(".red-ui-projects-dialog-screen-create-type").on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
container.find(".red-ui-projects-dialog-screen-create-type").removeClass('selected');
|
||||
@@ -1271,7 +1271,7 @@ RED.projects = (function() {
|
||||
var credentialsLeftBox = $('<div class="red-ui-projects-dialog-credentials-box-left">').appendTo(credentialsBox);
|
||||
|
||||
var credentialsEnabledBox = $('<div class="form-row red-ui-projects-dialog-credentials-box-enabled"></div>').appendTo(credentialsLeftBox);
|
||||
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="enabled"> <i class="fa fa-lock"></i> <span>'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
|
||||
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="enabled" checked> <i class="fa fa-lock"></i> <span>'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
|
||||
var credentialsDisabledBox = $('<div class="form-row red-ui-projects-dialog-credentials-box-disabled disabled"></div>').appendTo(credentialsLeftBox);
|
||||
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="disabled"> <i class="fa fa-unlock"></i> <span>'+RED._("projects.encryption-config.disable")+'</span></label>').appendTo(credentialsDisabledBox);
|
||||
|
||||
@@ -1397,7 +1397,7 @@ RED.projects = (function() {
|
||||
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
|
||||
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.create.desc2")+'</div>').appendTo(sshwarningRow);
|
||||
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
$('#red-ui-projects-dialog-cancel').trigger("click");
|
||||
RED.userSettings.show('gitconfig');
|
||||
@@ -1631,14 +1631,14 @@ RED.projects = (function() {
|
||||
function deleteProject(row,name,done) {
|
||||
var cover = $('<div class="red-ui-projects-dialog-project-list-entry-delete-confirm"></div>').on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
|
||||
$('<span>').text(RED._("projects.delete.confirm")).appendTo(cover);
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
|
||||
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
|
||||
.appendTo(cover)
|
||||
.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
cover.remove();
|
||||
done(true);
|
||||
});
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
|
||||
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
|
||||
.appendTo(cover)
|
||||
.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
@@ -1822,7 +1822,7 @@ RED.projects = (function() {
|
||||
header.addClass("selectable");
|
||||
|
||||
var tools = $('<div class="red-ui-projects-dialog-project-list-entry-tools"></div>').appendTo(header);
|
||||
$('<button class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
|
||||
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
|
||||
.appendTo(tools)
|
||||
.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
|
@@ -106,38 +106,51 @@ RED.search = (function() {
|
||||
return val;
|
||||
}
|
||||
|
||||
function search(val) {
|
||||
var results = [];
|
||||
var typeFilter;
|
||||
var m = /(?:^| )type:([^ ]+)/.exec(val);
|
||||
if (m) {
|
||||
val = val.replace(/(?:^| )type:[^ ]+/,"");
|
||||
typeFilter = m[1];
|
||||
function extractType(val, flags) {
|
||||
// extracts: type:XYZ & type:"X Y Z"
|
||||
const regEx = /(?:type):\s*(?:"([^"]+)"|([^" ]+))/;
|
||||
let m
|
||||
while ((m = regEx.exec(val)) !== null) {
|
||||
// avoid infinite loops with zero-width matches
|
||||
if (m.index === regEx.lastIndex) {
|
||||
regEx.lastIndex++;
|
||||
}
|
||||
val = val.replace(m[0]," ").trim()
|
||||
const flag = m[2] || m[1] // quoted entries in capture group 1, unquoted in capture group 2
|
||||
flags.type = flags.type || [];
|
||||
flags.type.push(flag);
|
||||
}
|
||||
var flags = {};
|
||||
return val;
|
||||
}
|
||||
|
||||
function search(val) {
|
||||
const results = [];
|
||||
const flags = {};
|
||||
val = extractFlag(val,"invalid",flags);
|
||||
val = extractFlag(val,"unused",flags);
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
val = extractFlag(val,"modified",flags);
|
||||
val = extractValue(val,"flow",flags);// flow:active or flow:<flow-id>
|
||||
val = extractValue(val,"flow",flags);// flow:current or flow:<flow-id>
|
||||
val = extractValue(val,"uses",flags);// uses:<node-id>
|
||||
val = extractType(val,flags);// type:<node-type>
|
||||
val = val.trim();
|
||||
var hasFlags = Object.keys(flags).length > 0;
|
||||
const hasFlags = Object.keys(flags).length > 0;
|
||||
const hasTypeFilter = flags.type && flags.type.length > 0
|
||||
if (flags.flow && flags.flow.indexOf("current") >= 0) {
|
||||
let idx = flags.flow.indexOf("current");
|
||||
flags.flow[idx] = RED.workspaces.active();//convert active to flow ID
|
||||
flags.flow[idx] = RED.workspaces.active();//convert 'current' to active flow ID
|
||||
}
|
||||
if (flags.flow && flags.flow.length) {
|
||||
flags.flow = [ ...new Set(flags.flow) ]; //deduplicate
|
||||
}
|
||||
if (val.length > 0 || typeFilter || hasFlags) {
|
||||
if (val.length > 0 || hasFlags) {
|
||||
val = val.toLowerCase();
|
||||
var i;
|
||||
var j;
|
||||
var list = [];
|
||||
var nodes = {};
|
||||
let i;
|
||||
let j;
|
||||
let list = [];
|
||||
const nodes = {};
|
||||
let keys = [];
|
||||
if (flags.uses) {
|
||||
keys = flags.uses;
|
||||
@@ -145,10 +158,10 @@ RED.search = (function() {
|
||||
keys = Object.keys(index);
|
||||
}
|
||||
for (i=0;i<keys.length;i++) {
|
||||
var key = keys[i];
|
||||
var kpos = keys[i].indexOf(val);
|
||||
if (kpos > -1) {
|
||||
var ids = Object.keys(index[key]||{});
|
||||
const key = keys[i];
|
||||
const kpos = val ? keys[i].indexOf(val) : -1;
|
||||
if (kpos > -1 || (val === "" && hasFlags)) {
|
||||
const ids = Object.keys(index[key]||{});
|
||||
for (j=0;j<ids.length;j++) {
|
||||
var node = index[key][ids[j]];
|
||||
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
|
||||
@@ -156,7 +169,7 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
if (flags.hasOwnProperty("invalid")) {
|
||||
var nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
|
||||
const nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
|
||||
if (flags.invalid === nodeIsValid) {
|
||||
continue;
|
||||
}
|
||||
@@ -186,8 +199,8 @@ RED.search = (function() {
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("unused")) {
|
||||
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
|
||||
(isConfigNode && node.node.users.length === 0)
|
||||
const isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
|
||||
(isConfigNode && node.node.users.length === 0 && node.node._def.hasUsers !== false)
|
||||
if (flags.unused !== isUnused) {
|
||||
continue;
|
||||
}
|
||||
@@ -197,12 +210,16 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!typeFilter || node.node.type === typeFilter) {
|
||||
nodes[node.node.id] = nodes[node.node.id] = {
|
||||
let typeIndex = -1
|
||||
if(hasTypeFilter) {
|
||||
typeIndex = flags.type.indexOf(node.node.type)
|
||||
}
|
||||
if (!hasTypeFilter || typeIndex > -1) {
|
||||
nodes[node.node.id] = nodes[node.node.id] || {
|
||||
node: node.node,
|
||||
label: node.label
|
||||
};
|
||||
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
|
||||
nodes[node.node.id].index = Math.min(nodes[node.node.id].index || Infinity, typeIndex > -1 ? typeIndex : kpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +555,7 @@ RED.search = (function() {
|
||||
$(previousActiveElement).trigger("focus");
|
||||
}
|
||||
previousActiveElement = null;
|
||||
}
|
||||
}
|
||||
if(!keepSearchToolbar) {
|
||||
clearActiveSearch();
|
||||
}
|
||||
@@ -630,7 +647,7 @@ RED.search = (function() {
|
||||
$("#red-ui-sidebar-shade").on('mousedown',hide);
|
||||
|
||||
$("#red-ui-view-searchtools-close").on("click", function close() {
|
||||
clearActiveSearch();
|
||||
clearActiveSearch();
|
||||
updateSearchToolbar();
|
||||
});
|
||||
$("#red-ui-view-searchtools-close").trigger("click");
|
||||
|
@@ -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 = [];
|
||||
@@ -506,6 +521,13 @@ RED.subflow = (function() {
|
||||
RED.nodes.groups(id).forEach(function(n) {
|
||||
removedGroups.push(n);
|
||||
})
|
||||
|
||||
var removedJunctions = RED.nodes.junctions(id)
|
||||
for (var i=0;i<removedJunctions.length;i++) {
|
||||
var removedEntities = RED.nodes.removeJunction(removedJunctions[i])
|
||||
removedLinks = removedLinks.concat(removedEntities.links)
|
||||
}
|
||||
|
||||
var removedConfigNodes = [];
|
||||
for (var i=0;i<removedNodes.length;i++) {
|
||||
var removedEntities = RED.nodes.remove(removedNodes[i].id);
|
||||
@@ -536,6 +558,7 @@ RED.subflow = (function() {
|
||||
nodes:removedNodes,
|
||||
links:removedLinks,
|
||||
groups: removedGroups,
|
||||
junctions: removedJunctions,
|
||||
subflows: [activeSubflow]
|
||||
}
|
||||
}
|
||||
@@ -550,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);
|
||||
@@ -613,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");
|
||||
@@ -768,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);
|
||||
@@ -877,6 +903,7 @@ RED.subflow = (function() {
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.updateActive();
|
||||
RED.view.select(null);
|
||||
RED.view.focus();
|
||||
}
|
||||
|
||||
|
||||
@@ -991,6 +1018,17 @@ RED.subflow = (function() {
|
||||
default: inputType
|
||||
})
|
||||
input.typedInput('value',val.value)
|
||||
if (inputType === 'cred') {
|
||||
if (node.credentials) {
|
||||
if (node.credentials[tenv.name]) {
|
||||
input.typedInput('value', node.credentials[tenv.name]);
|
||||
} else if (node.credentials['has_'+tenv.name]) {
|
||||
input.typedInput('value', "__PWRD__")
|
||||
} else {
|
||||
input.typedInput('value', "");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
input.val(val.value)
|
||||
}
|
||||
@@ -1310,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,
|
||||
|
@@ -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 {
|
||||
|
@@ -50,7 +50,7 @@ RED.sidebar.help = (function() {
|
||||
|
||||
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
|
||||
var helpPanel = $("<div>").css({
|
||||
"overflow-y": "scroll"
|
||||
"overflow-y": "auto"
|
||||
}).appendTo(stackContainer);
|
||||
|
||||
panels = RED.panels.create({
|
||||
@@ -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) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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'
|
||||
@@ -98,7 +108,7 @@ RED.sidebar.info = (function() {
|
||||
|
||||
propertiesPanelContent = $("<div>").css({
|
||||
"flex":"1 1 auto",
|
||||
"overflow-y":"scroll",
|
||||
"overflow-y":"auto",
|
||||
}).appendTo(propertiesPanel);
|
||||
|
||||
|
||||
@@ -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> </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() {
|
||||
|
@@ -436,18 +436,23 @@ RED.tourGuide = (function() {
|
||||
function listTour() {
|
||||
return [
|
||||
{
|
||||
id: "3_0",
|
||||
label: "3.0.0-beta.4",
|
||||
id: "3_1",
|
||||
label: "3.1",
|
||||
path: "./tours/welcome.js"
|
||||
},
|
||||
{
|
||||
id: "3_0",
|
||||
label: "3.0",
|
||||
path: "./tours/3.0/welcome.js"
|
||||
},
|
||||
{
|
||||
id: "2_2",
|
||||
label: "2.2.0",
|
||||
label: "2.2",
|
||||
path: "./tours/2.2/welcome.js"
|
||||
},
|
||||
{
|
||||
id: "2_1",
|
||||
label: "2.1.0",
|
||||
label: "2.1",
|
||||
path: "./tours/2.1/welcome.js"
|
||||
}
|
||||
];
|
||||
|
@@ -269,8 +269,8 @@ RED.typeSearch = (function() {
|
||||
moveCallback = opts.move;
|
||||
RED.events.emit("type-search:open");
|
||||
//shade.show();
|
||||
if ($("#red-ui-main-container").height() - opts.y - 150 < 0) {
|
||||
opts.y = opts.y - 235;
|
||||
if ($("#red-ui-main-container").height() - opts.y - 195 < 0) {
|
||||
opts.y = opts.y - 275;
|
||||
}
|
||||
dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
|
||||
searchResultsDiv.slideDown(300);
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
@@ -105,6 +111,9 @@ RED.view.tools = (function() {
|
||||
$(document).one('keyup',endKeyboardMove);
|
||||
endMoveSet = true;
|
||||
}
|
||||
var dim = RED.view.dimensions();
|
||||
var space_width = dim.width;
|
||||
var space_height = dim.height;
|
||||
var minX = 0;
|
||||
var minY = 0;
|
||||
var node;
|
||||
@@ -120,6 +129,12 @@ RED.view.tools = (function() {
|
||||
node.n.dirty = true;
|
||||
node.n.x += dx;
|
||||
node.n.y += dy;
|
||||
if ((node.n.x +node.n.w/2) >= space_width) {
|
||||
node.n.x = space_width -node.n.w/2;
|
||||
}
|
||||
if ((node.n.y +node.n.h/2) >= space_height) {
|
||||
node.n.y = space_height -node.n.h/2;
|
||||
}
|
||||
node.n.dirty = true;
|
||||
if (node.n.type === "group") {
|
||||
RED.group.markDirty(node.n);
|
||||
@@ -144,6 +159,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function setSelectedNodeLabelState(labelShown) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
var historyEvents = [];
|
||||
var nodes = [];
|
||||
@@ -430,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) {
|
||||
@@ -530,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) {
|
||||
@@ -690,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 = [];
|
||||
@@ -725,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) {
|
||||
@@ -767,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) {
|
||||
@@ -814,7 +845,10 @@ RED.view.tools = (function() {
|
||||
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
||||
*/
|
||||
function splitWiresWithLinkNodes(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
}
|
||||
@@ -868,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) {
|
||||
|
||||
@@ -883,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
|
||||
@@ -904,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
|
||||
@@ -982,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,
|
||||
@@ -1006,7 +1043,7 @@ RED.view.tools = (function() {
|
||||
const nodeDef = n._def || RED.nodes.getType(n.type)
|
||||
if (nodeDef && nodeDef.defaults && nodeDef.defaults.name) {
|
||||
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
|
||||
const defaultNodeNameRE = new RegExp('^'+paletteLabel+' (\\d+)$')
|
||||
const defaultNodeNameRE = new RegExp('^'+paletteLabel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')+' (\\d+)$')
|
||||
if (!typeIndex.hasOwnProperty(n.type)) {
|
||||
const existingNodes = RED.nodes.filterNodes({type: n.type})
|
||||
let maxNameNumber = 0;
|
||||
@@ -1052,7 +1089,10 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function addJunctionsToWires(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
}
|
||||
@@ -1080,6 +1120,7 @@ RED.view.tools = (function() {
|
||||
linkGroups.sort(function(A,B) {
|
||||
return groupedLinks[B].length - groupedLinks[A].length
|
||||
})
|
||||
const wasDirty = RED.nodes.dirty()
|
||||
linkGroups.forEach(function(gid) {
|
||||
var links = groupedLinks[gid]
|
||||
var junction = {
|
||||
@@ -1121,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) {
|
||||
@@ -1170,16 +1211,42 @@ RED.view.tools = (function() {
|
||||
})
|
||||
if (addedJunctions.length > 0) {
|
||||
RED.history.push({
|
||||
dirty: wasDirty,
|
||||
t: 'add',
|
||||
links: addedLinks,
|
||||
junctions: addedJunctions,
|
||||
removedLinks: Array.from(removedLinks)
|
||||
})
|
||||
RED.nodes.dirty(true)
|
||||
RED.view.select({nodes: addedJunctions });
|
||||
}
|
||||
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); })
|
||||
@@ -1246,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() })
|
||||
},
|
||||
/**
|
||||
|
277
packages/node_modules/@node-red/editor-client/src/js/ui/view.js
vendored
Executable file → Normal file
@@ -54,6 +54,7 @@ RED.view = (function() {
|
||||
var spliceTimer;
|
||||
var groupHoverTimer;
|
||||
|
||||
var activeFlowLocked = false;
|
||||
var activeSubflow = null;
|
||||
var activeNodes = [];
|
||||
var activeLinks = [];
|
||||
@@ -95,6 +96,7 @@ RED.view = (function() {
|
||||
let flashingNodeId;
|
||||
|
||||
var clipboard = "";
|
||||
let clipboardSource
|
||||
|
||||
// Note: these are the permitted status colour aliases. The actual RGB values
|
||||
// are set in the CSS - flow.scss/colors.scss
|
||||
@@ -210,6 +212,7 @@ RED.view = (function() {
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
RED.contextMenu.show({
|
||||
type: 'workspace',
|
||||
x:evt.clientX-5,
|
||||
y:evt.clientY-5
|
||||
})
|
||||
@@ -409,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);
|
||||
@@ -437,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",
|
||||
@@ -494,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);
|
||||
@@ -501,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")) {
|
||||
@@ -628,30 +652,40 @@ RED.view = (function() {
|
||||
});
|
||||
|
||||
RED.actions.add("core:copy-selection-to-internal-clipboard",copySelection);
|
||||
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection();deleteSelection();});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard,{generateIds: true, generateDefaultNames: true});});
|
||||
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'});
|
||||
});
|
||||
|
||||
RED.actions.add("core:detach-selected-nodes", function() { detachSelectedNodes() })
|
||||
|
||||
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);
|
||||
@@ -1041,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;
|
||||
@@ -1055,6 +1089,9 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function showQuickAddDialog(options) {
|
||||
if (activeFlowLocked) {
|
||||
return
|
||||
}
|
||||
options = options || {};
|
||||
var point = options.position || lastClickPosition;
|
||||
var spliceLink = options.splice;
|
||||
@@ -1068,12 +1105,15 @@ RED.view = (function() {
|
||||
RED.view.redraw();
|
||||
}
|
||||
|
||||
// `point` is the place in the workspace the mouse has clicked.
|
||||
// This takes into account scrolling and scaling of the workspace.
|
||||
var ox = point[0];
|
||||
var oy = point[1];
|
||||
|
||||
// Need to map that to browser location to position the pop-up
|
||||
const offset = $("#red-ui-workspace-chart").offset()
|
||||
var clientX = ox + offset.left - $("#red-ui-workspace-chart").scrollLeft()
|
||||
var clientY = oy + offset.top - $("#red-ui-workspace-chart").scrollTop()
|
||||
var clientX = (ox * scaleFactor) + offset.left - $("#red-ui-workspace-chart").scrollLeft()
|
||||
var clientY = (oy * scaleFactor) + offset.top - $("#red-ui-workspace-chart").scrollTop()
|
||||
|
||||
if (RED.settings.get("editor").view['view-snap-grid']) {
|
||||
// eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
|
||||
@@ -1234,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;
|
||||
@@ -1336,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) {
|
||||
@@ -1598,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) {
|
||||
@@ -2149,6 +2192,9 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||
if (clipboardSource === 'cut') {
|
||||
clipboardSource = 'copy'
|
||||
}
|
||||
updateActiveNodes();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
@@ -2449,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") {
|
||||
@@ -2464,6 +2511,9 @@ RED.view = (function() {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
return;
|
||||
}
|
||||
if (activeFlowLocked) {
|
||||
return
|
||||
}
|
||||
if (portLabelHover) {
|
||||
portLabelHover.remove();
|
||||
portLabelHover = null;
|
||||
@@ -2703,7 +2753,7 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function copySelection() {
|
||||
function copySelection(isCut) {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
return;
|
||||
}
|
||||
@@ -2767,6 +2817,7 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
clipboard = JSON.stringify(nns);
|
||||
clipboardSource = isCut ? 'cut' : 'copy'
|
||||
RED.menu.setDisabled("menu-item-edit-paste", false);
|
||||
if (nodeCount > 0) {
|
||||
RED.notify(RED._("clipboard.nodeCopied",{count:nodeCount}),{id:"clipboard"});
|
||||
@@ -2778,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);
|
||||
@@ -2919,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) {
|
||||
@@ -3286,11 +3338,17 @@ RED.view = (function() {
|
||||
|
||||
if (active && ((portType === PORT_TYPE_INPUT && ((d._def && d._def.inputLabels)||d.inputLabels)) || (portType === PORT_TYPE_OUTPUT && ((d._def && d._def.outputLabels)||d.outputLabels)))) {
|
||||
portLabelHoverTimeout = setTimeout(function() {
|
||||
const n = port && port.node()
|
||||
const nId = n && n.__data__ && n.__data__.id
|
||||
//check see if node has been deleted since timeout started
|
||||
if(!n || !n.parentNode || !RED.nodes.node(n.__data__.id)) {
|
||||
return; //node is gone!
|
||||
}
|
||||
var tooltip = getPortLabel(d,portType,portIndex);
|
||||
if (!tooltip) {
|
||||
return;
|
||||
}
|
||||
var pos = getElementPosition(port.node());
|
||||
var pos = getElementPosition(n);
|
||||
portLabelHoverTimeout = null;
|
||||
portLabelHover = showTooltip(
|
||||
(pos[0]+(portType===PORT_TYPE_INPUT?-2:12)),
|
||||
@@ -3353,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));
|
||||
@@ -3477,6 +3543,9 @@ RED.view = (function() {
|
||||
updateSelection();
|
||||
RED.nodes.dirty(true);
|
||||
redraw();
|
||||
if (clipboardSource === 'cut') {
|
||||
clipboardSource = 'copy'
|
||||
}
|
||||
resetMouseVars();
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
@@ -3673,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;
|
||||
@@ -3724,6 +3792,10 @@ RED.view = (function() {
|
||||
if (d.hasOwnProperty('l')?!d.l : (d.type === "link in" || d.type === "link out")) {
|
||||
var parentNode = this.parentNode;
|
||||
portLabelHoverTimeout = setTimeout(function() {
|
||||
//check see if node has been deleted since timeout started
|
||||
if(!parentNode || !parentNode.parentNode || !RED.nodes.node(parentNode.id)) {
|
||||
return; //node is gone!
|
||||
}
|
||||
var tooltip;
|
||||
if (d._def.label) {
|
||||
tooltip = d._def.label;
|
||||
@@ -3862,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);
|
||||
@@ -4032,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);
|
||||
@@ -4055,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;
|
||||
@@ -4070,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 {
|
||||
@@ -4085,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();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()],
|
||||
@@ -4560,12 +4634,10 @@ RED.view = (function() {
|
||||
icon_groupEl.setAttribute("y",0);
|
||||
icon_groupEl.style["pointer-events"] = "none";
|
||||
node[0][0].__iconGroup__ = icon_groupEl;
|
||||
var icon_shade = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
var icon_shade = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
icon_shade.setAttribute("x",0);
|
||||
icon_shade.setAttribute("y",0);
|
||||
icon_shade.setAttribute("class","red-ui-flow-node-icon-shade")
|
||||
icon_shade.setAttribute("width",30);
|
||||
icon_shade.setAttribute("height",Math.min(50,d.h-4));
|
||||
icon_groupEl.appendChild(icon_shade);
|
||||
node[0][0].__iconShade__ = icon_shade;
|
||||
|
||||
@@ -4858,9 +4930,20 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
icon.attr("y",function(){return (d.h-d3.select(this).attr("height"))/2;});
|
||||
this.__iconShade__.setAttribute("height", d.h );
|
||||
|
||||
|
||||
const iconShadeHeight = d.h
|
||||
const iconShadeWidth = 30
|
||||
this.__iconShade__.setAttribute("d", hideLabel ?
|
||||
`M5 0 h${iconShadeWidth-10} a 5 5 0 0 1 5 5 v${iconShadeHeight-10} a 5 5 0 0 1 -5 5 h-${iconShadeWidth-10} a 5 5 0 0 1 -5 -5 v-${iconShadeHeight-10} a 5 5 0 0 1 5 -5` : (
|
||||
"right" === d._def.align ?
|
||||
`M 0 0 h${iconShadeWidth-5} a 5 5 0 0 1 5 5 v${iconShadeHeight-10} a 5 5 0 0 1 -5 5 h-${iconShadeWidth-5} v-${iconShadeHeight}` :
|
||||
`M5 0 h${iconShadeWidth-5} v${iconShadeHeight} h-${iconShadeWidth-5} a 5 5 0 0 1 -5 -5 v-${iconShadeHeight-10} a 5 5 0 0 1 5 -5`
|
||||
)
|
||||
)
|
||||
this.__iconShadeBorder__.style.display = hideLabel?'none':''
|
||||
this.__iconShadeBorder__.setAttribute("d",
|
||||
"M " + (((!d._def.align && d.inputs !== 0 && d.outputs === 0) || "right" === d._def.align) ? 0 : 30) + " 1 l 0 " + (d.h - 2)
|
||||
"M " + (((!d._def.align && d.inputs !== 0 && d.outputs === 0) || "right" === d._def.align) ? 0.5 : 29.5) + " "+(d.selected?1:0.5)+" l 0 " + (d.h - (d.selected?2:1))
|
||||
);
|
||||
faIcon.attr("y",(d.h+13)/2);
|
||||
}
|
||||
@@ -4877,7 +4960,7 @@ RED.view = (function() {
|
||||
if (d._def.button) {
|
||||
var buttonEnabled = isButtonEnabled(d);
|
||||
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-disabled", !buttonEnabled);
|
||||
if (RED.runtime && Object.hasOwn(RED.runtime,'started')) {
|
||||
if (RED.runtime && RED.runtime.started !== undefined) {
|
||||
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-stopped", !RED.runtime.started);
|
||||
}
|
||||
|
||||
@@ -5574,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;
|
||||
@@ -5706,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();
|
||||
@@ -5781,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) {
|
||||
@@ -6108,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;
|
||||
@@ -6236,6 +6385,12 @@ RED.view = (function() {
|
||||
showQuickAddDialog:showQuickAddDialog,
|
||||
calculateNodeDimensions: calculateNodeDimensions,
|
||||
getElementPosition:getElementPosition,
|
||||
showTooltip:showTooltip
|
||||
showTooltip:showTooltip,
|
||||
dimensions: function() {
|
||||
return {
|
||||
width: space_width,
|
||||
height: space_height
|
||||
};
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@@ -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
|
||||
}
|
||||
})();
|
||||
|
@@ -217,6 +217,7 @@ $node-icon-border-color: #000;
|
||||
$node-icon-border-color-opacity: 0.1;
|
||||
|
||||
$node-config-background: #f3f3f3;
|
||||
$node-config-icon-container-disabled: #aaa;
|
||||
|
||||
$node-link-port-background: #eee;
|
||||
|
||||
|
@@ -30,7 +30,7 @@
|
||||
bottom: 0px;
|
||||
left:0px;
|
||||
right: 0px;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.red-ui-debug-filter-box {
|
||||
position:absolute;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -63,11 +63,14 @@
|
||||
padding: 4px 12px 4px 12px;
|
||||
}
|
||||
|
||||
&.red-ui-menu-dropdown-submenus > li > a,
|
||||
&.red-ui-menu-dropdown-submenus > li > a:focus {
|
||||
&.red-ui-menu-dropdown-submenus.red-ui-menu-dropdown-direction-right > li > a,
|
||||
&.red-ui-menu-dropdown-submenus.red-ui-menu-dropdown-direction-right > li > a:focus {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
&.red-ui-menu-dropdown-submenus.red-ui-menu-dropdown-direction-left > li > a,
|
||||
&.red-ui-menu-dropdown-submenus.red-ui-menu-dropdown-direction-left > li > a:focus {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
|
||||
& > .active > a,
|
||||
@@ -199,7 +202,7 @@
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-top: 5px;
|
||||
margin-left: -30px;
|
||||
margin-left: -15px;
|
||||
/* Caret Arrow */
|
||||
border-color: transparent;
|
||||
border-right-color: var(--red-ui-menuCaret);
|
||||
@@ -220,7 +223,7 @@
|
||||
margin-right: -15px;
|
||||
/* Caret Arrow */
|
||||
border-color: transparent;
|
||||
border-left-color: $menuCaret;
|
||||
border-left-color: var(--red-ui-menuCaret);
|
||||
border-style: solid;
|
||||
border-width: 5px 0 5px 5px;
|
||||
content: " ";
|
||||
|
@@ -368,7 +368,7 @@ button.red-ui-button-small
|
||||
border:1px solid var(--red-ui-secondary-border-color);
|
||||
border-radius:5px;
|
||||
height: calc(100% - 21px);
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
background: var(--red-ui-secondary-background);
|
||||
}
|
||||
|
||||
@@ -562,7 +562,7 @@ div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
|
||||
.red-ui-icon-list {
|
||||
width: 308px;
|
||||
height: 200px;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
line-height: 0px;
|
||||
position: relative;
|
||||
&.red-ui-icon-list-dark {
|
||||
|
@@ -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 {
|
||||
|
@@ -191,7 +191,7 @@
|
||||
margin-top: 0;
|
||||
li a {
|
||||
color: var(--red-ui-header-menu-color);
|
||||
padding: 3px 10px 3px 40px;
|
||||
padding: 3px 10px 3px 30px;
|
||||
img {
|
||||
max-width: 100%;
|
||||
margin-right: 10px;
|
||||
@@ -243,6 +243,7 @@
|
||||
}
|
||||
.red-ui-menu-dropdown-submenu>a:before {
|
||||
border-right-color: var(--red-ui-headerMenuCaret);
|
||||
margin-left: -25px !important;
|
||||
}
|
||||
|
||||
/* Deploy menu customisations */
|
||||
|
@@ -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;
|
||||
|
@@ -171,6 +171,7 @@
|
||||
left:0;
|
||||
width: 30px;
|
||||
border-right: 1px solid var(--red-ui-node-icon-background-color);
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
background-color: var(--red-ui-node-icon-background-color);
|
||||
}
|
||||
.red-ui-palette-icon-container-right {
|
||||
@@ -178,6 +179,7 @@
|
||||
right: 0;
|
||||
border-right: none;
|
||||
border-left: 1px solid var(--red-ui-node-icon-background-color);
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
}
|
||||
.red-ui-palette-icon {
|
||||
display: inline-block;
|
||||
|
@@ -26,7 +26,7 @@
|
||||
}
|
||||
}
|
||||
#red-ui-project-settings-tab-settings {
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.red-ui-sidebar-vc-shade {
|
||||
background: var(--red-ui-primary-background);
|
||||
@@ -183,7 +183,7 @@
|
||||
}
|
||||
.red-ui-projects-dialog-project-list-inner-container {
|
||||
flex-grow: 1 ;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
position:relative;
|
||||
.red-ui-editableList-border {
|
||||
border: none;
|
||||
@@ -711,7 +711,9 @@
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
.red-ui-projects-dialog-file-list-entry-file-type-git { color: $tertiary-text-color }
|
||||
.red-ui-projects-dialog-file-list-entry-file-type-git {
|
||||
color: var(--red-ui-tertiary-text-color);
|
||||
}
|
||||
|
||||
.red-ui-projects-dialog-remote-list {
|
||||
.red-ui-editableList-container {
|
||||
|
@@ -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);
|
||||
|
@@ -84,7 +84,7 @@
|
||||
.red-ui-search-result-node-port {
|
||||
position: absolute;
|
||||
border-radius: 2px;
|
||||
border: 1px solid $node-border;
|
||||
border: 1px solid var(--red-ui-node-border);
|
||||
width: 6px;
|
||||
height: 7px;
|
||||
top:4px;
|
||||
|
@@ -54,6 +54,9 @@ ul.red-ui-sidebar-node-config-list {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
&:not(:last-child) {
|
||||
width: calc(100% - 38px);
|
||||
}
|
||||
}
|
||||
.red-ui-palette-icon-container {
|
||||
font-size: 12px;
|
||||
@@ -98,15 +101,15 @@ ul.red-ui-sidebar-node-config-list li.red-ui-palette-node-config-type {
|
||||
}
|
||||
.red-ui-palette-node-config-unused,.red-ui-palette-node-config-disabled {
|
||||
border-color: var(--red-ui-primary-border-color);
|
||||
background: var(--red-ui-secondary-background-inactive);
|
||||
background: var(--red-ui-node-config-background);
|
||||
border-style: dashed;
|
||||
color: var(--red-ui-tertiary-text-color);
|
||||
color: var(--red-ui-node-config-icon-container-disabled);
|
||||
}
|
||||
.red-ui-palette-node-config-disabled {
|
||||
opacity: 0.6;
|
||||
font-style: italic;
|
||||
i {
|
||||
color: var(--red-ui-secondary-text-color);
|
||||
color: var(--red-ui-node-port-label-color);
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
|
||||
.red-ui-palette-category {
|
||||
&:not(.expanded) button {
|
||||
|
@@ -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;
|
||||
|
@@ -67,7 +67,7 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
padding: 8px 20px 20px;
|
||||
overflow-y: scroll;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.red-ui-settings-row {
|
||||
padding: 5px 10px 2px;
|
||||
|
@@ -203,6 +203,7 @@
|
||||
--red-ui-node-icon-border-color-opacity: #{$node-icon-border-color-opacity};
|
||||
|
||||
--red-ui-node-config-background: #{$node-config-background};
|
||||
--red-ui-node-config-icon-container-disabled: #{$node-config-icon-container-disabled};
|
||||
|
||||
--red-ui-node-link-port-background: #{$node-link-port-background};
|
||||
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#red-ui-workspace-chart {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
bottom:25px;
|
||||
bottom:26px;
|
||||
top: 35px;
|
||||
left:0px;
|
||||
right:0px;
|
||||
@@ -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;
|
||||
|
BIN
packages/node_modules/@node-red/editor-client/src/tours/3.0/images/context-menu.png
vendored
Normal file
After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
155
packages/node_modules/@node-red/editor-client/src/tours/3.0/welcome.js
vendored
Normal 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>`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 93 KiB |
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/global-env-vars.png
vendored
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/hiding-flows.png
vendored
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/locking-flows.png
vendored
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/mermaid.png
vendored
Normal file
After Width: | Height: | Size: 189 KiB |
@@ -1,137 +1,97 @@
|
||||
export default {
|
||||
version: "3.0.0-beta.4",
|
||||
version: "3.1.0-beta.1",
|
||||
steps: [
|
||||
{
|
||||
titleIcon: "fa fa-map-o",
|
||||
title: {
|
||||
"en-US": "Welcome to Node-RED 3.0 Beta 4!",
|
||||
"ja": "Node-RED 3.0 ベータ4へようこそ!"
|
||||
"en-US": "Welcome to Node-RED 3.1 Beta 1!",
|
||||
// "ja": "Node-RED 3.1へようこそ!"
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>This is another final beta release of Node-RED 3.0.</p><p>Let's take a moment to discover the new features in this release.</p>",
|
||||
"ja": "<p>これはNode-RED 3.0のもう一つの最後のベータリリースです。</p><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": ``
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@@ -14,6 +14,9 @@ declare var msg: NodeMessage;
|
||||
/** @type {string} the id of the incoming `msg` (alias of msg._msgid) */
|
||||
declare const __msgid__:string;
|
||||
|
||||
declare const util:typeof import('util')
|
||||
declare const promisify:typeof import('util').promisify
|
||||
|
||||
/**
|
||||
* @typedef NodeStatus
|
||||
* @type {object}
|
||||
|
@@ -160,6 +160,7 @@
|
||||
'$base64encode':{ args:[ ]},
|
||||
'$boolean':{ args:[ 'arg' ]},
|
||||
'$ceil':{ args:[ 'number' ]},
|
||||
'$clone': { args:[ 'arg' ]},
|
||||
'$contains':{ args:[ 'str', 'pattern' ]},
|
||||
'$count':{ args:[ 'array' ]},
|
||||
'$decodeUrl':{ args:[ 'str' ]},
|
||||
|
@@ -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();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -245,44 +245,37 @@
|
||||
// complete parentage of the node that generated this message.
|
||||
// flow-id/subflow-A-instance/subflow-B-instance
|
||||
|
||||
// If it has one id, that is a top level flow
|
||||
// If it has one id, that is a top level flow or config node/global
|
||||
// each subsequent id is the instance id of a subflow node
|
||||
//
|
||||
pathParts = o.path.split("/");
|
||||
if (pathParts.length === 1) {
|
||||
// The source node is on a flow - so can use its id to find
|
||||
// The source node is on a flow or is a global/config - so can use its id to find
|
||||
sourceNode = RED.nodes.node(o.id);
|
||||
} else if (pathParts.length > 1) {
|
||||
// Highlight the subflow instance node.
|
||||
sourceNode = RED.nodes.node(pathParts[1]);
|
||||
}
|
||||
const getNodeLabel = (n) => n.name || (typeof n.label === "function" && n.label()) || (typeof n.label === "string" && n.label) || (n.type + ":" + n.id);
|
||||
pathHierarchy = pathParts.map((id,index) => {
|
||||
if (index === 0) {
|
||||
return {
|
||||
id: id,
|
||||
label: RED.nodes.workspace(id).label
|
||||
}
|
||||
if (id === "global") {
|
||||
return { id: sourceNode.id, label: getNodeLabel(sourceNode) }
|
||||
}
|
||||
return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
|
||||
} else {
|
||||
var instanceNode = RED.nodes.node(id)
|
||||
return {
|
||||
id: id,
|
||||
label: (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
|
||||
}
|
||||
const instanceNode = RED.nodes.node(id)
|
||||
const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
|
||||
return { id: id, label: pathLabel }
|
||||
}
|
||||
})
|
||||
if (pathParts.length === 1) {
|
||||
pathHierarchy.push({
|
||||
id: o.id,
|
||||
label: sourceNode.name || sourceNode.type+":"+sourceNode.id
|
||||
})
|
||||
if (pathParts.length === 1 && pathParts[0] !== "global") {
|
||||
pathHierarchy.push({ id: o.id, label: getNodeLabel(sourceNode) })
|
||||
}
|
||||
if (o._alias) {
|
||||
let aliasNode = RED.nodes.node(o._alias)
|
||||
if (aliasNode) {
|
||||
pathHierarchy.push({
|
||||
id: o._alias,
|
||||
label: aliasNode.name || aliasNode.type+":"+aliasNode.id
|
||||
})
|
||||
pathHierarchy.push({ id: o._alias, label: getNodeLabel(aliasNode) })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script type="text/html" data-template-name="complete">
|
||||
<div class="form-row node-input-target-row">
|
||||
<button id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
<button type="button" id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
</div>
|
||||
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
|
||||
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-complete-target-filter"></div>
|
||||
|
@@ -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">
|
||||
@@ -12,7 +12,7 @@
|
||||
<label for="node-input-uncaught" style="width: auto" data-i18n="catch.label.uncaught"></label>
|
||||
</div>
|
||||
<div class="form-row node-input-target-row">
|
||||
<button id="node-input-catch-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
<button type="button" id="node-input-catch-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
</div>
|
||||
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
|
||||
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-catch-target-filter"></div>
|
||||
|
@@ -4,11 +4,11 @@
|
||||
<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">
|
||||
<button id="node-input-status-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
<button type="button" id="node-input-status-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
|
||||
</div>
|
||||
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
|
||||
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-status-target-filter"></div>
|
||||
|
@@ -29,23 +29,23 @@ module.exports = function(RED) {
|
||||
"use strict";
|
||||
const crypto = require("crypto");
|
||||
const targetCache = (function () {
|
||||
const registry = { id: {}, name: {} };
|
||||
function getIndex(/** @type {[LinkTarget]}*/ targets, id) {
|
||||
let registry = { id: {}, name: {} }
|
||||
function getIndex (/** @type {[LinkTarget]} */ targets, id) {
|
||||
for (let index = 0; index < (targets || []).length; index++) {
|
||||
const element = targets[index];
|
||||
const element = targets[index]
|
||||
if (element.id === id) {
|
||||
return index;
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
/**
|
||||
* Generate a target object from a node
|
||||
* @param {LinkInNode} node
|
||||
* @param {LinkInNode} node
|
||||
* @returns {LinkTarget} a link target object
|
||||
*/
|
||||
function generateTarget(node) {
|
||||
const isSubFlow = node._flow.TYPE === "subflow";
|
||||
function generateTarget (node) {
|
||||
const isSubFlow = node._flow.TYPE === 'subflow'
|
||||
return {
|
||||
id: node.id,
|
||||
name: node.name || node.id,
|
||||
@@ -58,72 +58,72 @@ module.exports = function(RED) {
|
||||
/**
|
||||
* Get a list of targets registerd to this name
|
||||
* @param {string} name Name of the target
|
||||
* @param {boolean} [excludeSubflows] set `true` to exclude
|
||||
* @param {boolean} [excludeSubflows] set `true` to exclude
|
||||
* @returns {[LinkTarget]} Targets registerd to this name.
|
||||
*/
|
||||
getTargets(name, excludeSubflows) {
|
||||
const targets = registry.name[name] || [];
|
||||
getTargets (name, excludeSubflows) {
|
||||
const targets = registry.name[name] || []
|
||||
if (excludeSubflows) {
|
||||
return targets.filter(e => e.isSubFlow != true);
|
||||
return targets.filter(e => e.isSubFlow !== true)
|
||||
}
|
||||
return targets;
|
||||
return targets
|
||||
},
|
||||
/**
|
||||
* Get a single target by registered name.
|
||||
* To restrict to a single flow, include the `flowId`
|
||||
* If there is no targets OR more than one target, null is returned
|
||||
* @param {string} name Name of the node
|
||||
* @param {string} [flowId]
|
||||
* @param {string} [flowId]
|
||||
* @returns {LinkTarget} target
|
||||
*/
|
||||
getTarget(name, flowId) {
|
||||
/** @type {[LinkTarget]}*/
|
||||
let possibleTargets = this.getTargets(name);
|
||||
/** @type {LinkTarget}*/
|
||||
let target;
|
||||
getTarget (name, flowId) {
|
||||
/** @type {[LinkTarget]} */
|
||||
let possibleTargets = this.getTargets(name)
|
||||
/** @type {LinkTarget} */
|
||||
let target
|
||||
if (possibleTargets.length && flowId) {
|
||||
possibleTargets = possibleTargets.filter(e => e.flowId == flowId);
|
||||
possibleTargets = possibleTargets.filter(e => e.flowId === flowId)
|
||||
}
|
||||
if (possibleTargets.length === 1) {
|
||||
target = possibleTargets[0];
|
||||
target = possibleTargets[0]
|
||||
}
|
||||
return target;
|
||||
return target
|
||||
},
|
||||
/**
|
||||
* Get a target by node ID
|
||||
* @param {string} nodeId ID of the node
|
||||
* @returns {LinkTarget} target
|
||||
*/
|
||||
getTargetById(nodeId) {
|
||||
return registry.id[nodeId];
|
||||
getTargetById (nodeId) {
|
||||
return registry.id[nodeId]
|
||||
},
|
||||
register(/** @type {LinkInNode} */ node) {
|
||||
const target = generateTarget(node);
|
||||
const tByName = this.getTarget(target.name, target.flowId);
|
||||
register (/** @type {LinkInNode} */ node) {
|
||||
const target = generateTarget(node)
|
||||
const tByName = this.getTarget(target.name, target.flowId)
|
||||
if (!tByName || tByName.id !== target.id) {
|
||||
registry.name[target.name] = registry.name[target.name] || [];
|
||||
registry.name[target.name] = registry.name[target.name] || []
|
||||
registry.name[target.name].push(target)
|
||||
}
|
||||
registry.id[target.id] = target;
|
||||
return target;
|
||||
registry.id[target.id] = target
|
||||
return target
|
||||
},
|
||||
remove(node) {
|
||||
const target = generateTarget(node);
|
||||
const targs = this.getTargets(target.name);
|
||||
const idx = getIndex(targs, target.id);
|
||||
remove (node) {
|
||||
const target = generateTarget(node)
|
||||
const targs = this.getTargets(target.name)
|
||||
const idx = getIndex(targs, target.id)
|
||||
if (idx > -1) {
|
||||
targs.splice(idx, 1);
|
||||
targs.splice(idx, 1)
|
||||
}
|
||||
if (targs.length === 0) {
|
||||
delete registry.name[tn.name];
|
||||
delete registry.name[target.name]
|
||||
}
|
||||
delete registry.id[target.id];
|
||||
delete registry.id[target.id]
|
||||
},
|
||||
clear() {
|
||||
registry = { id: {}, name: {} };
|
||||
clear () {
|
||||
registry = { id: {}, name: {} }
|
||||
}
|
||||
}
|
||||
})();
|
||||
})()
|
||||
|
||||
function LinkInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
27
packages/node_modules/@node-red/nodes/core/common/91-global-config.html
vendored
Normal 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>
|
7
packages/node_modules/@node-red/nodes/core/common/91-global-config.js
vendored
Normal 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);
|
||||
}
|