Merge pull request #4320 from node-red/dev
Sync `dev` to `master` for 3.1.0 release
4
.github/workflows/tests.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [14, 16]
|
node-version: [16, 18, 20]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
@ -30,7 +30,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
npm run test
|
npm run test
|
||||||
# - name: Publish to coveralls.io
|
# - name: Publish to coveralls.io
|
||||||
# if: ${{ matrix.node-version == 14 }}
|
# if: ${{ matrix.node-version == 16 }}
|
||||||
# uses: coverallsapp/github-action@v1.1.2
|
# uses: coverallsapp/github-action@v1.1.2
|
||||||
# with:
|
# with:
|
||||||
# github-token: ${{ github.token }}
|
# github-token: ${{ github.token }}
|
||||||
|
@ -15,5 +15,5 @@
|
|||||||
"shadow": true, // allow variable shadowing (re-use of names...)
|
"shadow": true, // allow variable shadowing (re-use of names...)
|
||||||
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
||||||
"proto": true, // allow setting of __proto__ in node < v0.12,
|
"proto": true, // allow setting of __proto__ in node < v0.12,
|
||||||
"esversion": 6 // allow es6
|
"esversion": 11 // allow es11(ES2020)
|
||||||
}
|
}
|
||||||
|
239
CHANGELOG.md
@ -1,3 +1,242 @@
|
|||||||
|
#### 3.1.0: Milestone Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Default filter to All Catalogues and show nodes for small lists (#4318) @knolleary
|
||||||
|
- Better distinguish between ctrl and meta keys on mac (#4310) @knolleary
|
||||||
|
- Ensure junction appears when filtering quick-add list (#4297) @knolleary
|
||||||
|
- Update message catalogs for JSONata Expression editor (#4287) @kazuhitoyokoi
|
||||||
|
- Add tooltip to relevance sort button in user settings UI (#4288) @kazuhitoyokoi
|
||||||
|
- Capture workspace dirty state when quick-adding junction (#4283) @knolleary
|
||||||
|
- Add docs for $clone function (#4284) @knolleary
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- Dependency updates (#4317) @knolleary
|
||||||
|
- Ensure storage/util.writeFile handles concurrent write attempts (#4316) @knolleary
|
||||||
|
- Migrate http -> https for nodered.org (#4313) @Rotzbua
|
||||||
|
- Add Node 20 to GH Action test matrix (#4305) @Rotzbua
|
||||||
|
- Handle group-scoped nodes inside subflow (#4301) @knolleary
|
||||||
|
- Handle non-url-safe chars in context api (#4298) @knolleary
|
||||||
|
- Fix git pull operation in project feature (#4290) @kazuhitoyokoi
|
||||||
|
- Change linefeed codes in Korean message catalogs (#4286) @kazuhitoyokoi
|
||||||
|
- Fix file permissions of message catalogs (#4285) @kazuhitoyokoi
|
||||||
|
- Update tour (#4278) @knolleary
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- File: Fix handling in file nodes when number is specified as file name (#4267) @kazuhitoyokoi
|
||||||
|
- Function: Adding function timeout to settings file (#4265) (#4309) @knolleary
|
||||||
|
- Function: Fix function setup tab layout (#4299) @knolleary
|
||||||
|
- HTTP Request: Handle 204 in httprequest JSON (#4262) @sammachin
|
||||||
|
- JSON: Fix test cases of JSON node (#4275) @kazuhitoyokoi
|
||||||
|
- MQTT: Remove unnecessary check for clientid if autoUnsub set (#4302) @knolleary
|
||||||
|
|
||||||
|
##### 3.1.0-beta.4: Beta Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Add Japanese translation for 3.1.0 (#4252) @kazuhitoyokoi
|
||||||
|
- Improve Catalogue visibility (#4248) @Steve-Mcl
|
||||||
|
- Add support for wiring and moving junctions on touch device (#4244) @Steve-Mcl
|
||||||
|
- Show errors and statuses of config nodes in the sidebar when no catch node is available (#4231) @bvmensvoort
|
||||||
|
- Improve wiring for horizontally aligned nodes (#4232) @knolleary
|
||||||
|
- French translation of Welcome Tours (#4200) @GogoVega
|
||||||
|
- French translation of v3.1.0-beta.3 changes (#4199) @GogoVega
|
||||||
|
- add Japanese message for 3.1.0 beta 3 (#4209) @HiroyasuNishiyama
|
||||||
|
- Dont clone the group nodes `node` array when saving edits (#4208) @Steve-Mcl
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- Add NR_SUBFLOW_NAME/ID/PATH env vars (#4250) @knolleary
|
||||||
|
- Evaluate all env vars as part of async flow start (#4230) @knolleary
|
||||||
|
- Add support for httpStatic middleware (#4229) @knolleary
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- Fix JSONata in file nodes (#4246) @kazuhitoyokoi
|
||||||
|
- Fix timeout icon in function and link call nodes (#4253) @kazuhitoyokoi
|
||||||
|
- Fix connection keep-alive in http request node (#4228) @knolleary
|
||||||
|
- adding timeout attribute to function node (#4177) @k1ln
|
||||||
|
- Fix manual mode join when multiple sequences being handled (#4143) @BitCaesar
|
||||||
|
- Fix delay node flush issue (#4203) @dceejay
|
||||||
|
- Update status and catch node labels in group mode (#4207) @Steve-Mcl
|
||||||
|
|
||||||
|
##### 3.1.0-beta.3: Beta Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- Select the item that is specified in a deep link URL (#4113) @Steve-Mcl
|
||||||
|
- Update to Monaco 0.38.0 (#4189) @Steve-Mcl
|
||||||
|
- Place subflow outputs/inputs relative to current view (#4183) @knolleary
|
||||||
|
- Enable RED.view.select to select group by id (#4184) @knolleary
|
||||||
|
- Combine existing env vars when merging groups (#4182) @knolleary
|
||||||
|
- Avoid creating empty global-config node if not needed (#4153) @knolleary
|
||||||
|
- Fix group selection when using lasso (#4108) @knolleary
|
||||||
|
- Use editor path in generating localStorage keys (#4151) @mw75
|
||||||
|
- Ensure no node credentials are included when exporting to clipboard (#4112) @knolleary
|
||||||
|
- Fix jsonata expression test ui (#4097) @knolleary
|
||||||
|
- Fix search button in palette popover (#4096) @knolleary
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- Allow options object on each httpStatic configuration (#4109) @kevinGodell
|
||||||
|
- Ensure non-zero exit codes for errors (#4181) @knolleary
|
||||||
|
- Ensure external modules are installed synchronously (#4180) @knolleary
|
||||||
|
- Update dependecies include got (#4155) @knolleary
|
||||||
|
- Add Japanese translations for v3.1 beta.2 (#4158) @kazuhitoyokoi
|
||||||
|
- Ensure express server options are applied consistently (#4178) @knolleary
|
||||||
|
- Remove version info from theme endpoint (#4179) @knolleary
|
||||||
|
- Add Japanese translations for welcome tour of 3.1.0 beta.2 (#4145) @kazuhitoyokoi
|
||||||
|
- Added SHA-256 and SHA-512-256 digest authentication (#4100) @sroebert
|
||||||
|
- Add "timers" types to known types (#4103) @Steve-Mcl
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- Allow Catch/Status nodes to be scoped to their group (#4185) @NetHans
|
||||||
|
- MQTT: Option to disable MQTT topic unsubscribe on disconnect (#4078) @flying7eleven
|
||||||
|
|
||||||
|
|
||||||
|
##### 3.1.0-beta.2: Beta Release
|
||||||
|
|
||||||
|
Editor
|
||||||
|
|
||||||
|
- NEW: Add change icon to tabs (#4068) @knolleary
|
||||||
|
- NEW: Complete overhaul of Group UX (#4079) @knolleary
|
||||||
|
- NEW: Add link to node help in node edit dialog footer (#4065) @knolleary
|
||||||
|
- NEW: Added editor feature for connecting multiple nodes to single node (#4051) @sonntam
|
||||||
|
- NEW: Increase workspace size to 8000x8000 (#4094) @knolleary
|
||||||
|
- Ensure node buttons are redrawn when flow lock state is changed (#4091) @knolleary
|
||||||
|
- Prevent loops being created with junction nodes (#4087) @knolleary
|
||||||
|
- Prevent opening locked node's edit dialog (#4069) @knolleary
|
||||||
|
- Reverse direction of tab scroll to expected direction (#4064) @knolleary
|
||||||
|
- Add cancel operation to editableList (#4077) @HiroyasuNishiyama
|
||||||
|
- Apply Mermaid diagram for project settings UI (#4054) @kazuhitoyokoi
|
||||||
|
- Add tooltip for show/hide button on info sidebar (#4050) @kazuhitoyokoi
|
||||||
|
- Fix align nodes on locked tab (#4072) @HiroyasuNishiyama
|
||||||
|
- Fix importing connected link nodes into a subflow (#4082) @knolleary
|
||||||
|
- Fix to add empty marker to empty group (#4060) @HiroyasuNishiyama
|
||||||
|
- Fix image URLs for v3.0 tour (#4053) @kazuhitoyokoi
|
||||||
|
- Show scrollbar in notification dialog only when needed (#4048) @kazuhitoyokoi
|
||||||
|
- Update-monaco-and-typings (#4089) @Steve-Mcl
|
||||||
|
- Update jquery UI (#4088) @knolleary
|
||||||
|
- Support i18n of lock/unlock buttons in flow property UI (#4049) @kazuhitoyokoi
|
||||||
|
- Translation kr (#3895) @hae-iotplatform
|
||||||
|
- Translation zhcn (!!请懂中文的帮忙review) (#3952) @cliyr
|
||||||
|
- Add French translation of nodes (#3964) @GogoVega
|
||||||
|
- Add French translation (#3962) @GogoVega
|
||||||
|
- Portuguese Brazilian (pt-BR) translation (#3804) @FabsMuller
|
||||||
|
|
||||||
|
|
||||||
|
Runtime
|
||||||
|
|
||||||
|
- NEW: Generate stable ids for subflow instance internal nodes (#4093) @knolleary
|
||||||
|
- NEW: Change default file name to flows.json in project feature (#4073) @kazuhitoyokoi
|
||||||
|
- NEW: Deprecate synchronous access to jsonata (#4090) @knolleary
|
||||||
|
- Add Node 18 to test matrix (#4084) @knolleary
|
||||||
|
- Bump minimum nodejs version supported to match documented value (#4086) @knolleary
|
||||||
|
- Update monaco docs link in settings.js (#4075) @Steve-Mcl
|
||||||
|
- Remove duplicated messages in the message catalog (#4066) @kazuhitoyokoi
|
||||||
|
- Ensure errors in preDeliver callback are handled (#3911) @knolleary
|
||||||
|
- Fix "EADDRINUSE" error (#4046) @bggbr
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
|
||||||
|
- Link Call: Clear link-call timeouts when node is closed (#4085) @knolleary
|
||||||
|
- Join: ensure inflight status is cleared when in auto mode (#4083) @knolleary
|
||||||
|
- File Out: Fix extra newline append for multipart file write (#3915) @dceejay
|
||||||
|
- Add validators for complete and link call nodes (#4056) @kazuhitoyokoi
|
||||||
|
|
||||||
|
##### 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
|
#### 3.0.2: Maintenance Release
|
||||||
|
|
||||||
Editor
|
Editor
|
||||||
|
@ -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/font-awesome.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/history.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/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/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/editableList.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/common/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/diagnostics.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.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/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/workspaces.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.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",
|
"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",
|
"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/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/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": [
|
// "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
|
||||||
// // TODO: resolve relative resource paths in
|
// // 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": [
|
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
|
||||||
"node_modules/jsonata/jsonata-es5.min.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/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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,7 +408,7 @@ module.exports = function(grunt) {
|
|||||||
{
|
{
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src',
|
cwd: 'packages/node_modules/@node-red/editor-client/src',
|
||||||
src: [
|
src: [
|
||||||
'types/node/*.ts',
|
'types/node/**/*.ts',
|
||||||
'types/node-red/*.ts',
|
'types/node-red/*.ts',
|
||||||
],
|
],
|
||||||
expand: true,
|
expand: true,
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
# Node-RED
|
# Node-RED
|
||||||
|
|
||||||
http://nodered.org
|
https://nodered.org
|
||||||
|
|
||||||
[![Build Status](https://github.com/node-red/node-red/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
|
[![Build Status](https://github.com/node-red/node-red/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
|
||||||
|
|
||||||
Low-code programming for event-driven applications.
|
Low-code programming for event-driven applications.
|
||||||
|
|
||||||
![Node-RED: Low-code programming for event-driven applications](http://nodered.org/images/node-red-screenshot.png)
|
![Node-RED: Low-code programming for event-driven applications](https://nodered.org/images/node-red-screenshot.png)
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
|
||||||
started.
|
started.
|
||||||
|
|
||||||
1. `sudo npm install -g --unsafe-perm node-red`
|
1. `sudo npm install -g --unsafe-perm node-red`
|
||||||
@ -19,7 +19,7 @@ started.
|
|||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
More documentation can be found [here](http://nodered.org/docs).
|
More documentation can be found [here](https://nodered.org/docs).
|
||||||
|
|
||||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||||
|
|
||||||
|
61
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red",
|
"name": "node-red",
|
||||||
"version": "3.0.2",
|
"version": "3.1.0",
|
||||||
"description": "Low-code programming for event-driven applications",
|
"description": "Low-code programming for event-driven applications",
|
||||||
"homepage": "http://nodered.org",
|
"homepage": "https://nodered.org",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -26,30 +26,30 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "8.7.1",
|
"acorn": "8.8.2",
|
||||||
"acorn-walk": "8.2.0",
|
"acorn-walk": "8.2.0",
|
||||||
"ajv": "8.11.0",
|
"ajv": "8.12.0",
|
||||||
"async-mutex": "0.3.2",
|
"async-mutex": "0.4.0",
|
||||||
"basic-auth": "2.0.1",
|
"basic-auth": "2.0.1",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"body-parser": "1.20.0",
|
"body-parser": "1.20.2",
|
||||||
"cheerio": "1.0.0-rc.10",
|
"cheerio": "1.0.0-rc.10",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"content-type": "1.0.4",
|
"content-type": "1.0.5",
|
||||||
"cookie": "0.5.0",
|
"cookie": "0.5.0",
|
||||||
"cookie-parser": "1.4.6",
|
"cookie-parser": "1.4.6",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"cronosjs": "1.7.1",
|
"cronosjs": "1.7.1",
|
||||||
"denque": "2.1.0",
|
"denque": "2.1.0",
|
||||||
"express": "4.18.1",
|
"express": "4.18.2",
|
||||||
"express-session": "1.17.3",
|
"express-session": "1.17.3",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"fs-extra": "10.1.0",
|
"fs-extra": "11.1.1",
|
||||||
"got": "11.8.5",
|
"got": "12.6.0",
|
||||||
"hash-sum": "2.0.0",
|
"hash-sum": "2.0.0",
|
||||||
"hpagent": "1.0.0",
|
"hpagent": "1.2.0",
|
||||||
"https-proxy-agent": "5.0.1",
|
"https-proxy-agent": "5.0.1",
|
||||||
"i18next": "21.8.16",
|
"i18next": "21.10.0",
|
||||||
"iconv-lite": "0.6.3",
|
"iconv-lite": "0.6.3",
|
||||||
"is-utf8": "0.2.1",
|
"is-utf8": "0.2.1",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
@ -60,33 +60,33 @@
|
|||||||
"memorystore": "1.6.7",
|
"memorystore": "1.6.7",
|
||||||
"mime": "3.0.0",
|
"mime": "3.0.0",
|
||||||
"moment": "2.29.4",
|
"moment": "2.29.4",
|
||||||
"moment-timezone": "0.5.34",
|
"moment-timezone": "0.5.43",
|
||||||
"mqtt": "4.3.7",
|
"mqtt": "4.3.7",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
"mustache": "4.2.0",
|
"mustache": "4.2.0",
|
||||||
"node-red-admin": "^3.0.0",
|
"node-red-admin": "^3.1.0",
|
||||||
"node-watch": "0.7.3",
|
"node-watch": "0.7.4",
|
||||||
"nopt": "5.0.0",
|
"nopt": "5.0.0",
|
||||||
"oauth2orize": "1.11.1",
|
"oauth2orize": "1.11.1",
|
||||||
"on-headers": "1.0.2",
|
"on-headers": "1.0.2",
|
||||||
"passport": "0.6.0",
|
"passport": "0.6.0",
|
||||||
"passport-http-bearer": "1.0.1",
|
"passport-http-bearer": "1.0.1",
|
||||||
"passport-oauth2-client-password": "0.1.2",
|
"passport-oauth2-client-password": "0.1.2",
|
||||||
"raw-body": "2.5.1",
|
"raw-body": "2.5.2",
|
||||||
"semver": "7.3.7",
|
"semver": "7.5.4",
|
||||||
"tar": "6.1.11",
|
"tar": "6.1.13",
|
||||||
"tough-cookie": "4.0.0",
|
"tough-cookie": "4.1.3",
|
||||||
"uglify-js": "3.16.3",
|
"uglify-js": "3.17.4",
|
||||||
"uuid": "8.3.2",
|
"uuid": "9.0.0",
|
||||||
"ws": "7.5.6",
|
"ws": "7.5.6",
|
||||||
"xml2js": "0.4.23"
|
"xml2js": "0.6.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"bcrypt": "5.0.1"
|
"bcrypt": "5.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"dompurify": "2.3.10",
|
"dompurify": "2.4.1",
|
||||||
"grunt": "1.5.3",
|
"grunt": "1.6.1",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-cli": "~1.4.3",
|
"grunt-cli": "~1.4.3",
|
||||||
"grunt-concurrent": "3.0.0",
|
"grunt-concurrent": "3.0.0",
|
||||||
@ -108,17 +108,18 @@
|
|||||||
"i18next-http-backend": "1.4.1",
|
"i18next-http-backend": "1.4.1",
|
||||||
"jquery-i18next": "1.2.1",
|
"jquery-i18next": "1.2.1",
|
||||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||||
"marked": "4.0.18",
|
"marked": "4.3.0",
|
||||||
|
"mermaid": "^9.4.3",
|
||||||
"minami": "1.2.3",
|
"minami": "1.2.3",
|
||||||
"mocha": "9.2.2",
|
"mocha": "9.2.2",
|
||||||
"node-red-node-test-helper": "^0.3.0",
|
"node-red-node-test-helper": "^0.3.2",
|
||||||
"nodemon": "2.0.19",
|
"nodemon": "2.0.20",
|
||||||
"proxy": "^1.0.2",
|
"proxy": "^1.0.2",
|
||||||
"sass": "1.54.2",
|
"sass": "1.62.1",
|
||||||
"should": "13.2.3",
|
"should": "13.2.3",
|
||||||
"sinon": "11.1.2",
|
"sinon": "11.1.2",
|
||||||
"stoppable": "^1.1.0",
|
"stoppable": "^1.1.0",
|
||||||
"supertest": "6.2.4"
|
"supertest": "6.3.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var express = require("express");
|
|
||||||
|
|
||||||
var nodes = require("./nodes");
|
var nodes = require("./nodes");
|
||||||
var flows = require("./flows");
|
var flows = require("./flows");
|
||||||
var flow = require("./flow");
|
var flow = require("./flow");
|
||||||
@ -37,18 +35,9 @@ module.exports = {
|
|||||||
plugins.init(runtimeAPI);
|
plugins.init(runtimeAPI);
|
||||||
diagnostics.init(settings, runtimeAPI);
|
diagnostics.init(settings, runtimeAPI);
|
||||||
|
|
||||||
var needsPermission = auth.needsPermission;
|
const needsPermission = auth.needsPermission;
|
||||||
|
|
||||||
var adminApp = express();
|
|
||||||
|
|
||||||
var defaultServerSettings = {
|
|
||||||
"x-powered-by": false
|
|
||||||
}
|
|
||||||
var serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
|
|
||||||
for (var eOption in serverSettings) {
|
|
||||||
adminApp.set(eOption, serverSettings[eOption]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const adminApp = apiUtil.createExpressApp(settings)
|
||||||
|
|
||||||
// Flows
|
// Flows
|
||||||
adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler);
|
adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler);
|
||||||
|
@ -46,14 +46,15 @@ module.exports = {
|
|||||||
runtimeAPI = _runtimeAPI;
|
runtimeAPI = _runtimeAPI;
|
||||||
needsPermission = auth.needsPermission;
|
needsPermission = auth.needsPermission;
|
||||||
if (!settings.disableEditor) {
|
if (!settings.disableEditor) {
|
||||||
info.init(runtimeAPI);
|
info.init(settings, runtimeAPI);
|
||||||
comms.init(server,settings,runtimeAPI);
|
comms.init(server,settings,runtimeAPI);
|
||||||
|
|
||||||
var ui = require("./ui");
|
var ui = require("./ui");
|
||||||
|
|
||||||
ui.init(runtimeAPI);
|
ui.init(runtimeAPI);
|
||||||
|
|
||||||
var editorApp = express();
|
const editorApp = apiUtil.createExpressApp(settings)
|
||||||
|
|
||||||
if (settings.requireHttps === true) {
|
if (settings.requireHttps === true) {
|
||||||
editorApp.enable('trust proxy');
|
editorApp.enable('trust proxy');
|
||||||
editorApp.use(function (req, res, next) {
|
editorApp.use(function (req, res, next) {
|
||||||
@ -86,7 +87,7 @@ module.exports = {
|
|||||||
|
|
||||||
//Projects
|
//Projects
|
||||||
var projects = require("./projects");
|
var projects = require("./projects");
|
||||||
projects.init(runtimeAPI);
|
projects.init(settings, runtimeAPI);
|
||||||
editorApp.use("/projects",projects.app());
|
editorApp.use("/projects",projects.app());
|
||||||
|
|
||||||
// Locales
|
// Locales
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var express = require("express");
|
|
||||||
var apiUtils = require("../util");
|
var apiUtils = require("../util");
|
||||||
|
|
||||||
|
var settings;
|
||||||
var runtimeAPI;
|
var runtimeAPI;
|
||||||
var needsPermission = require("../auth").needsPermission;
|
var needsPermission = require("../auth").needsPermission;
|
||||||
|
|
||||||
@ -77,11 +77,12 @@ function getProjectRemotes(req,res) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: function(_runtimeAPI) {
|
init: function(_settings, _runtimeAPI) {
|
||||||
|
settings = _settings;
|
||||||
runtimeAPI = _runtimeAPI;
|
runtimeAPI = _runtimeAPI;
|
||||||
},
|
},
|
||||||
app: function() {
|
app: function() {
|
||||||
var app = express();
|
var app = apiUtils.createExpressApp(settings)
|
||||||
|
|
||||||
app.use(function(req,res,next) {
|
app.use(function(req,res,next) {
|
||||||
runtimeAPI.projects.available().then(function(available) {
|
runtimeAPI.projects.available().then(function(available) {
|
||||||
|
@ -18,9 +18,9 @@ var runtimeAPI;
|
|||||||
var sshkeys = require("./sshkeys");
|
var sshkeys = require("./sshkeys");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: function(_runtimeAPI) {
|
init: function(settings, _runtimeAPI) {
|
||||||
runtimeAPI = _runtimeAPI;
|
runtimeAPI = _runtimeAPI;
|
||||||
sshkeys.init(runtimeAPI);
|
sshkeys.init(settings, runtimeAPI);
|
||||||
},
|
},
|
||||||
userSettings: function(req, res) {
|
userSettings: function(req, res) {
|
||||||
var opts = {
|
var opts = {
|
||||||
|
@ -17,13 +17,15 @@
|
|||||||
var apiUtils = require("../util");
|
var apiUtils = require("../util");
|
||||||
var express = require("express");
|
var express = require("express");
|
||||||
var runtimeAPI;
|
var runtimeAPI;
|
||||||
|
var settings;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: function(_runtimeAPI) {
|
init: function(_settings, _runtimeAPI) {
|
||||||
runtimeAPI = _runtimeAPI;
|
runtimeAPI = _runtimeAPI;
|
||||||
|
settings = _settings;
|
||||||
},
|
},
|
||||||
app: function() {
|
app: function() {
|
||||||
var app = express();
|
const app = apiUtils.createExpressApp(settings);
|
||||||
|
|
||||||
// List all SSH keys
|
// List all SSH keys
|
||||||
app.get("/", function(req,res) {
|
app.get("/", function(req,res) {
|
||||||
|
@ -19,6 +19,7 @@ var util = require("util");
|
|||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var clone = require("clone");
|
var clone = require("clone");
|
||||||
|
const apiUtil = require("../util")
|
||||||
|
|
||||||
var defaultContext = {
|
var defaultContext = {
|
||||||
page: {
|
page: {
|
||||||
@ -27,8 +28,7 @@ var defaultContext = {
|
|||||||
tabicon: {
|
tabicon: {
|
||||||
icon: "red/images/node-red-icon-black.svg",
|
icon: "red/images/node-red-icon-black.svg",
|
||||||
colour: "#8f0000"
|
colour: "#8f0000"
|
||||||
},
|
}
|
||||||
version: require(path.join(__dirname,"../../package.json")).version
|
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
title: "Node-RED",
|
title: "Node-RED",
|
||||||
@ -40,6 +40,7 @@ var defaultContext = {
|
|||||||
vendorMonaco: ""
|
vendorMonaco: ""
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var settings;
|
||||||
|
|
||||||
var theme = null;
|
var theme = null;
|
||||||
var themeContext = clone(defaultContext);
|
var themeContext = clone(defaultContext);
|
||||||
@ -92,7 +93,8 @@ function serveFilesFromTheme(themeValue, themeApp, directory, baseDirectory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: function(settings, _runtimeAPI) {
|
init: function(_settings, _runtimeAPI) {
|
||||||
|
settings = _settings;
|
||||||
runtimeAPI = _runtimeAPI;
|
runtimeAPI = _runtimeAPI;
|
||||||
themeContext = clone(defaultContext);
|
themeContext = clone(defaultContext);
|
||||||
if (process.env.NODE_ENV == "development") {
|
if (process.env.NODE_ENV == "development") {
|
||||||
@ -113,7 +115,15 @@ module.exports = {
|
|||||||
var url;
|
var url;
|
||||||
themeSettings = {};
|
themeSettings = {};
|
||||||
|
|
||||||
themeApp = express();
|
themeApp = apiUtil.createExpressApp(settings);
|
||||||
|
|
||||||
|
const defaultServerSettings = {
|
||||||
|
"x-powered-by": false
|
||||||
|
}
|
||||||
|
const serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
|
||||||
|
for (const eOption in serverSettings) {
|
||||||
|
themeApp.set(eOption, serverSettings[eOption]);
|
||||||
|
}
|
||||||
|
|
||||||
if (theme.page) {
|
if (theme.page) {
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ var adminApp;
|
|||||||
var server;
|
var server;
|
||||||
var editor;
|
var editor;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the module.
|
* Initialise the module.
|
||||||
* @param {Object} settings The runtime settings
|
* @param {Object} settings The runtime settings
|
||||||
@ -49,7 +48,7 @@ var editor;
|
|||||||
function init(settings,_server,storage,runtimeAPI) {
|
function init(settings,_server,storage,runtimeAPI) {
|
||||||
server = _server;
|
server = _server;
|
||||||
if (settings.httpAdminRoot !== false) {
|
if (settings.httpAdminRoot !== false) {
|
||||||
adminApp = express();
|
adminApp = apiUtil.createExpressApp(settings);
|
||||||
|
|
||||||
var cors = require('cors');
|
var cors = require('cors');
|
||||||
var corsHandler = cors({
|
var corsHandler = cors({
|
||||||
@ -64,14 +63,6 @@ function init(settings,_server,storage,runtimeAPI) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultServerSettings = {
|
|
||||||
"x-powered-by": false
|
|
||||||
}
|
|
||||||
var serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
|
|
||||||
for (var eOption in serverSettings) {
|
|
||||||
adminApp.set(eOption, serverSettings[eOption]);
|
|
||||||
}
|
|
||||||
|
|
||||||
auth.init(settings,storage);
|
auth.init(settings,storage);
|
||||||
|
|
||||||
var maxApiRequestSize = settings.apiMaxLength || '5mb';
|
var maxApiRequestSize = settings.apiMaxLength || '5mb';
|
||||||
@ -136,10 +127,11 @@ async function stop() {
|
|||||||
editor.stop();
|
editor.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: init,
|
init,
|
||||||
start: start,
|
start,
|
||||||
stop: stop,
|
stop,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @memberof @node-red/editor-api
|
* @memberof @node-red/editor-api
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
const express = require("express");
|
||||||
|
|
||||||
var log = require("@node-red/util").log; // TODO: separate module
|
const { log, i18n } = require("@node-red/util");
|
||||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
errorHandler: function(err,req,res,next) {
|
errorHandler: function(err,req,res,next) {
|
||||||
@ -64,5 +63,17 @@ module.exports = {
|
|||||||
path: req.path,
|
path: req.path,
|
||||||
ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined
|
ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
createExpressApp: function(settings) {
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const defaultServerSettings = {
|
||||||
|
"x-powered-by": false
|
||||||
|
}
|
||||||
|
const serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{});
|
||||||
|
for (let eOption in serverSettings) {
|
||||||
|
app.set(eOption, serverSettings[eOption]);
|
||||||
|
}
|
||||||
|
return app
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/editor-api",
|
"name": "@node-red/editor-api",
|
||||||
"version": "3.0.2",
|
"version": "3.1.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -16,14 +16,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/util": "3.0.2",
|
"@node-red/util": "3.1.0",
|
||||||
"@node-red/editor-client": "3.0.2",
|
"@node-red/editor-client": "3.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"body-parser": "1.20.0",
|
"body-parser": "1.20.2",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"express-session": "1.17.3",
|
"express-session": "1.17.3",
|
||||||
"express": "4.18.1",
|
"express": "4.18.2",
|
||||||
"memorystore": "1.6.7",
|
"memorystore": "1.6.7",
|
||||||
"mime": "3.0.0",
|
"mime": "3.0.0",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
@ -35,6 +35,6 @@
|
|||||||
"ws": "7.5.6"
|
"ws": "7.5.6"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"bcrypt": "5.0.1"
|
"bcrypt": "5.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1175,8 +1175,10 @@
|
|||||||
"languages": {
|
"languages": {
|
||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
"en-US": "Englisch",
|
"en-US": "Englisch",
|
||||||
|
"fr": "Französisch",
|
||||||
"ja": "Japanisch",
|
"ja": "Japanisch",
|
||||||
"ko": "Koreanisch",
|
"ko": "Koreanisch",
|
||||||
|
"pt-BR":"Portugiesisch",
|
||||||
"ru": "Russisch",
|
"ru": "Russisch",
|
||||||
"zh-CN": "Chinesisch (Vereinfacht)",
|
"zh-CN": "Chinesisch (Vereinfacht)",
|
||||||
"zh-TW": "Chinesisch (Traditionell)"
|
"zh-TW": "Chinesisch (Traditionell)"
|
||||||
|
@ -205,7 +205,7 @@
|
|||||||
},
|
},
|
||||||
"$formatNumber": {
|
"$formatNumber": {
|
||||||
"args": "number, picture [, options]",
|
"args": "number, picture [, options]",
|
||||||
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in eine dezimale Darstellung, wie im `picture`-String-Parameter vorgegeben.\n\nDas Verhalten dieser Funktion ist mit der XPath/XQuery-Funktion fn:formatnummer konsistent, wie sie in der XPath F&O 3.1-Spezifikation definiert ist. Der `picture`-String-Parameter definiert, wie die Zahl formatiert ist und hat die gleiche Syntax wie fn:format-number.\n\nDer optionale dritte Parameter `options` wird verwendet, um die standardmäßigen länderspezifischen Formatierungszeichen, wie z.B. das Dezimaltrennzeichen, zu überschreiben. Wenn dieser Parameter vorgegeben wird, muss es sich um ein Objekt handeln, das Name/Wert-Paare enthält, die im Abschnitt mit dem Dezimalformat der XPath F&O 3.1-Spezifikation vorgegeben sind."
|
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in eine dezimale Darstellung, wie im `picture`-String-Parameter vorgegeben.\n\nDas Verhalten dieser Funktion ist mit der XPath/XQuery-Funktion `fn:formatnummer` konsistent, wie sie in der XPath F&O 3.1-Spezifikation definiert ist. Der `picture`-String-Parameter definiert, wie die Zahl formatiert ist und hat die gleiche Syntax wie `fn:format-number`.\n\nDer optionale dritte Parameter `options` wird verwendet, um die standardmäßigen länderspezifischen Formatierungszeichen, wie z.B. das Dezimaltrennzeichen, zu überschreiben. Wenn dieser Parameter vorgegeben wird, muss es sich um ein Objekt handeln, das Name/Wert-Paare enthält, die im Abschnitt mit dem Dezimalformat der XPath F&O 3.1-Spezifikation vorgegeben sind."
|
||||||
},
|
},
|
||||||
"$formatBase": {
|
"$formatBase": {
|
||||||
"args": "number [, radix]",
|
"args": "number [, radix]",
|
||||||
|
@ -23,7 +23,11 @@
|
|||||||
"position": "Position",
|
"position": "Position",
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
"upload": "Upload"
|
"upload": "Upload",
|
||||||
|
"lock": "Lock",
|
||||||
|
"unlock": "Unlock",
|
||||||
|
"locked": "Locked",
|
||||||
|
"unlocked": "Unlocked"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"string": "string",
|
"string": "string",
|
||||||
@ -53,22 +57,30 @@
|
|||||||
"confirmDelete": "Confirm delete",
|
"confirmDelete": "Confirm delete",
|
||||||
"delete": "Are you sure you want to delete '__label__'?",
|
"delete": "Are you sure you want to delete '__label__'?",
|
||||||
"dropFlowHere": "Drop the flow here",
|
"dropFlowHere": "Drop the flow here",
|
||||||
|
"dropImageHere": "Drop the image here",
|
||||||
"addFlow": "Add flow",
|
"addFlow": "Add flow",
|
||||||
"addFlowToRight": "Add flow to the right",
|
"addFlowToRight": "Add flow to the right",
|
||||||
|
"closeFlow": "Close flow",
|
||||||
"hideFlow": "Hide flow",
|
"hideFlow": "Hide flow",
|
||||||
"hideOtherFlows": "Hide other flows",
|
"hideOtherFlows": "Hide other flows",
|
||||||
"showAllFlows": "Show all flows",
|
"showAllFlows": "Show all flows (__count__ hidden)",
|
||||||
"hideAllFlows": "Hide all flows",
|
"hideAllFlows": "Hide all flows",
|
||||||
"hiddenFlows": "List __count__ hidden flow",
|
"hiddenFlows": "List __count__ hidden flow",
|
||||||
"hiddenFlows_plural": "List __count__ hidden flows",
|
"hiddenFlows_plural": "List __count__ hidden flows",
|
||||||
"showLastHiddenFlow": "Show last hidden flow",
|
"showLastHiddenFlow": "Reopen hidden flow",
|
||||||
"listFlows": "List flows",
|
"listFlows": "List flows",
|
||||||
"listSubflows": "List subflows",
|
"listSubflows": "List subflows",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"info": "Description",
|
"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": {
|
"menu": {
|
||||||
"label": {
|
"label": {
|
||||||
@ -101,6 +113,7 @@
|
|||||||
"displayStatus": "Show node status",
|
"displayStatus": "Show node status",
|
||||||
"displayConfig": "Configuration nodes",
|
"displayConfig": "Configuration nodes",
|
||||||
"import": "Import",
|
"import": "Import",
|
||||||
|
"importExample": "Import Example Flow",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
"search": "Search flows",
|
"search": "Search flows",
|
||||||
"searchInput": "search your flows",
|
"searchInput": "search your flows",
|
||||||
@ -499,6 +512,7 @@
|
|||||||
"addRemoveNode": "Add/remove node from selection",
|
"addRemoveNode": "Add/remove node from selection",
|
||||||
"editSelected": "Edit selected node",
|
"editSelected": "Edit selected node",
|
||||||
"deleteSelected": "Delete selected nodes or link",
|
"deleteSelected": "Delete selected nodes or link",
|
||||||
|
"deleteReconnect": "Delete and Reconnect",
|
||||||
"importNode": "Import nodes",
|
"importNode": "Import nodes",
|
||||||
"exportNode": "Export nodes",
|
"exportNode": "Export nodes",
|
||||||
"nudgeNode": "Move selected nodes (1px)",
|
"nudgeNode": "Move selected nodes (1px)",
|
||||||
@ -573,6 +587,7 @@
|
|||||||
"editor": {
|
"editor": {
|
||||||
"title": "Manage palette",
|
"title": "Manage palette",
|
||||||
"palette": "Palette",
|
"palette": "Palette",
|
||||||
|
"allCatalogs": "All Catalogs",
|
||||||
"times": {
|
"times": {
|
||||||
"seconds": "seconds ago",
|
"seconds": "seconds ago",
|
||||||
"minutes": "minutes ago",
|
"minutes": "minutes ago",
|
||||||
@ -612,6 +627,7 @@
|
|||||||
"tab-nodes": "Nodes",
|
"tab-nodes": "Nodes",
|
||||||
"tab-install": "Install",
|
"tab-install": "Install",
|
||||||
"sort": "sort:",
|
"sort": "sort:",
|
||||||
|
"sortRelevance": "relevance",
|
||||||
"sortAZ": "a-z",
|
"sortAZ": "a-z",
|
||||||
"sortRecent": "recent",
|
"sortRecent": "recent",
|
||||||
"more": "+ __count__ more",
|
"more": "+ __count__ more",
|
||||||
@ -685,9 +701,11 @@
|
|||||||
"empty": "empty",
|
"empty": "empty",
|
||||||
"globalConfig": "Global Configuration Nodes",
|
"globalConfig": "Global Configuration Nodes",
|
||||||
"triggerAction": "Trigger action",
|
"triggerAction": "Trigger action",
|
||||||
|
"find": "Find in workspace",
|
||||||
|
"copyItemUrl": "Copy item url",
|
||||||
|
"copyURL2Clipboard": "Copied url to clipboard",
|
||||||
"showFlow": "Show",
|
"showFlow": "Show",
|
||||||
"hideFlow": "Hide",
|
"hideFlow": "Hide"
|
||||||
"find": "Find in workspace"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"name": "Help",
|
"name": "Help",
|
||||||
@ -988,7 +1006,10 @@
|
|||||||
"quote": "Quote",
|
"quote": "Quote",
|
||||||
"link": "Link",
|
"link": "Link",
|
||||||
"horizontal-rule": "Horizontal rule",
|
"horizontal-rule": "Horizontal rule",
|
||||||
"toggle-preview": "Toggle preview"
|
"toggle-preview": "Toggle preview",
|
||||||
|
"mermaid": {
|
||||||
|
"summary": "Mermaid Diagram"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"bufferEditor": {
|
"bufferEditor": {
|
||||||
"title": "Buffer editor",
|
"title": "Buffer editor",
|
||||||
@ -1183,8 +1204,10 @@
|
|||||||
"languages": {
|
"languages": {
|
||||||
"de": "German",
|
"de": "German",
|
||||||
"en-US": "English",
|
"en-US": "English",
|
||||||
|
"fr": "French",
|
||||||
"ja": "Japanese",
|
"ja": "Japanese",
|
||||||
"ko": "Korean",
|
"ko": "Korean",
|
||||||
|
"pt-BR":"Portuguese",
|
||||||
"ru": "Russian",
|
"ru": "Russian",
|
||||||
"zh-CN": "Chinese(Simplified)",
|
"zh-CN": "Chinese(Simplified)",
|
||||||
"zh-TW": "Chinese(Traditional)"
|
"zh-TW": "Chinese(Traditional)"
|
||||||
@ -1210,5 +1233,10 @@
|
|||||||
"node": "Node",
|
"node": "Node",
|
||||||
"junction": "Junction",
|
"junction": "Junction",
|
||||||
"linkNodes": "Link Nodes"
|
"linkNodes": "Link Nodes"
|
||||||
|
},
|
||||||
|
"env-var": {
|
||||||
|
"environment": "Environment",
|
||||||
|
"header": "Global Environment Variables",
|
||||||
|
"revert": "Revert"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
},
|
},
|
||||||
"$now": {
|
"$now": {
|
||||||
"args": "$[picture [, timezone]]",
|
"args": "$[picture [, timezone]]",
|
||||||
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional picture and timezone parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional `picture` and `timezone` parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
||||||
},
|
},
|
||||||
"$base64encode": {
|
"$base64encode": {
|
||||||
"args": "string",
|
"args": "string",
|
||||||
@ -137,7 +137,7 @@
|
|||||||
},
|
},
|
||||||
"$sort": {
|
"$sort": {
|
||||||
"args": "array [, function]",
|
"args": "array [, function]",
|
||||||
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values `left` and `right`. If the value of `left` should be placed after the value of `right` in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
||||||
},
|
},
|
||||||
"$reverse": {
|
"$reverse": {
|
||||||
"args": "array",
|
"args": "array",
|
||||||
@ -201,11 +201,11 @@
|
|||||||
},
|
},
|
||||||
"$fromMillis": {
|
"$fromMillis": {
|
||||||
"args": "number, [, picture [, timezone]]",
|
"args": "number, [, picture [, timezone]]",
|
||||||
"desc": "Convert the `number` representing milliseconds since the Unix Epoch (1 January, 1970 UTC) to a formatted string representation of the timestamp as specified by the picture string.\n\nIf the optional `picture` parameter is omitted, then the timestamp is formatted in the ISO 8601 format.\n\nIf the optional `picture` string is supplied, then the timestamp is formatted occording to the representation specified in that string. The behaviour of this function is consistent with the two-argument version of the XPath/XQuery function `format-dateTime` as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the timestamp is formatted and has the same syntax as `format-dateTime`.\n\nIf the optional `timezone` string is supplied, then the formatted timestamp will be in that timezone. The `timezone` string should be in the format '±HHMM', where ± is either the plus or minus sign and HHMM is the offset in hours and minutes from UTC. Positive offset for timezones east of UTC, negative offset for timezones west of UTC."
|
"desc": "Convert the `number` representing milliseconds since the Unix Epoch (1 January, 1970 UTC) to a formatted string representation of the timestamp as specified by the picture string.\n\nIf the optional `picture` parameter is omitted, then the timestamp is formatted in the ISO 8601 format.\n\nIf the optional `picture` string is supplied, then the timestamp is formatted according to the representation specified in that string. The behaviour of this function is consistent with the two-argument version of the XPath/XQuery function `format-dateTime` as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the timestamp is formatted and has the same syntax as `format-dateTime`.\n\nIf the optional `timezone` string is supplied, then the formatted timestamp will be in that timezone. The `timezone` string should be in the format '±HHMM', where ± is either the plus or minus sign and HHMM is the offset in hours and minutes from UTC. Positive offset for timezones east of UTC, negative offset for timezones west of UTC."
|
||||||
},
|
},
|
||||||
"$formatNumber": {
|
"$formatNumber": {
|
||||||
"args": "number, picture [, options]",
|
"args": "number, picture [, options]",
|
||||||
"desc": "Casts the `number` to a string and formats it to a decimal representation as specified by the `picture` string.\n\n The behaviour of this function is consistent with the XPath/XQuery function fn:format-number as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the number is formatted and has the same syntax as fn:format-number.\n\nThe optional third argument `options` is used to override the default locale specific formatting characters such as the decimal separator. If supplied, this argument must be an object containing name/value pairs specified in the decimal format section of the XPath F&O 3.1 specification."
|
"desc": "Casts the `number` to a string and formats it to a decimal representation as specified by the `picture` string.\n\n The behaviour of this function is consistent with the XPath/XQuery function `fn:format-number` as defined in the XPath F&O 3.1 specification. The `picture` string parameter defines how the number is formatted and has the same syntax as `fn:format-number`.\n\nThe optional third argument `options` is used to override the default locale specific formatting characters such as the decimal separator. If supplied, this argument must be an object containing name/value pairs specified in the decimal format section of the XPath F&O 3.1 specification."
|
||||||
},
|
},
|
||||||
"$formatBase": {
|
"$formatBase": {
|
||||||
"args": "number [, radix]",
|
"args": "number [, radix]",
|
||||||
@ -237,7 +237,7 @@
|
|||||||
},
|
},
|
||||||
"$assert": {
|
"$assert": {
|
||||||
"args": "arg, str",
|
"args": "arg, str",
|
||||||
"desc": "If `arg` is true the function returns undefined. If `arg` is false an exception is thrown with `str` as the message of the exception."
|
"desc": "If `arg` is `true` the function returns `undefined`. If `arg` is `false` an exception is thrown with `str` as the message of the exception."
|
||||||
},
|
},
|
||||||
"$single": {
|
"$single": {
|
||||||
"args": "array, function",
|
"args": "array, function",
|
||||||
@ -270,5 +270,9 @@
|
|||||||
"$moment": {
|
"$moment": {
|
||||||
"args": "[str]",
|
"args": "[str]",
|
||||||
"desc": "Gets a date object using the Moment library."
|
"desc": "Gets a date object using the Moment library."
|
||||||
|
},
|
||||||
|
"$clone": {
|
||||||
|
"args": "value",
|
||||||
|
"desc": "Safely clone an object."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1239
packages/node_modules/@node-red/editor-client/locales/fr/editor.json
vendored
Normal file
23
packages/node_modules/@node-red/editor-client/locales/fr/infotips.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"tip0": "Vous pouvez supprimer les noeuds ou les liens sélectionnés avec {{core:delete-selection}}",
|
||||||
|
"tip1": "Rechercher des noeuds à l'aide de {{core:search}}",
|
||||||
|
"tip2": "{{core:toggle-sidebar}} basculera l'affichage de cette barre latérale",
|
||||||
|
"tip3": "Vous pouvez gérer votre palette de noeuds avec {{core:manage-palette}}",
|
||||||
|
"tip4": "Vos noeuds de configuration de flux sont répertoriés dans le panneau de la barre latérale. Ils sont accessibles depuis le menu ou avec {{core:show-config-tab}}",
|
||||||
|
"tip5": "Activer ou désactiver ces conseils à partir de l'option dans les paramètres",
|
||||||
|
"tip6": "Déplacer les noeuds sélectionnés à l'aide des touches [gauche] [haut] [bas] et [droite]. Maintenir la touche [shift] enfoncée pour les pousser plus loin",
|
||||||
|
"tip7": "Faire glisser un noeud sur un fil le raccordera au lien",
|
||||||
|
"tip8": "Exporter les noeuds sélectionnés, ou l'onglet actuel avec {{core:show-export-dialog}}",
|
||||||
|
"tip9": "Importer un flux en faisant glisser son JSON dans l'éditeur, ou avec {{core:show-import-dialog}}",
|
||||||
|
"tip10": "[majuscule] [clic] et faites glisser sur un port de noeud pour déplacer tous les fils attachés ou seulement celui sélectionné",
|
||||||
|
"tip11": "Afficher l'onglet Infos avec {{core:show-info-tab}} ou l'onglet Débogage avec {{core:show-debug-tab}}",
|
||||||
|
"tip12": "[ctrl] [clic] dans l'espace de travail pour ouvrir la boîte de dialogue d'ajout rapide",
|
||||||
|
"tip13": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un port de noeud pour activer le câblage rapide",
|
||||||
|
"tip14": "Maintenir la touche [shift] enfoncée lorsque vous [cliquez] sur un noeud pour sélectionner également tous ses noeuds connectés",
|
||||||
|
"tip15": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un noeud pour l'ajouter ou le supprimer de la sélection actuelle",
|
||||||
|
"tip16": "Changer d'onglet de flux avec {{core:show-previous-tab}} et {{core:show-next-tab}}",
|
||||||
|
"tip17": "Vous pouvez confirmer vos modifications dans le panneau d'édition du noeud avec {{core:confirm-edit-tray}} ou les annuler avec {{core:cancel-edit-tray}}",
|
||||||
|
"tip18": "Appuyer sur {{core:edit-selected-node}} modifiera le premier noeud de la sélection actuelle"
|
||||||
|
}
|
||||||
|
}
|
274
packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json
vendored
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
{
|
||||||
|
"$string": {
|
||||||
|
"args": "arg[, prettify]",
|
||||||
|
"desc": "Convertit le paramètre `arg` en une chaîne de caractères en utilisant les règles de typage suivantes :\n\n - Les chaînes de caractères sont inchangées\n - Les fonctions sont converties en une chaîne vide\n - L'infini numérique et NaN renvoient une erreur car ils ne peuvent pas être représentés comme un Numéro JSON\n - Toutes les autres valeurs sont converties en une chaîne JSON à l'aide de la fonction `JSON.stringify`. Si `prettify` est vrai, alors le JSON \"prettified\" est produit. c'est-à-dire une ligne par champ et les lignes seront en retrait en fonction de la profondeur du champ."
|
||||||
|
},
|
||||||
|
"$length": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Renvoie le nombre de caractères dans la chaîne `str`. Une erreur est renvoyée si `str` n'est pas une chaîne de caractères."
|
||||||
|
},
|
||||||
|
"$substring": {
|
||||||
|
"args": "str, start[, length]",
|
||||||
|
"desc": "Renvoie une chaîne contenant les caractères du premier paramètre `str` commençant à la position `start` (pas de décalage). Si `length` est spécifié, alors la sous-chaîne contiendra un maximum de caractères `length`. Si `start` est négatif alors il indique le nombre de caractères à partir de la fin de `str`."
|
||||||
|
},
|
||||||
|
"$substringBefore": {
|
||||||
|
"args": "str, chars",
|
||||||
|
"desc": "Renvoie la sous-chaîne avant la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`."
|
||||||
|
},
|
||||||
|
"$substringAfter": {
|
||||||
|
"args": "str, chars",
|
||||||
|
"desc": "Renvoie la sous-chaîne après la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`."
|
||||||
|
},
|
||||||
|
"$uppercase": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en majuscules."
|
||||||
|
},
|
||||||
|
"$lowercase": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en minuscules."
|
||||||
|
},
|
||||||
|
"$trim": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Normalise et supprime tous les caractères d'espacement dans `str` en appliquant les étapes suivantes :\n\n - Toutes les tabulations, retours à la ligne et sauts de ligne sont remplacés par des espaces.\n- Les séquences contiguës d'espaces sont réduites à un seul espace.\n- Les espaces de fin et de début sont supprimés.\n\n Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée sans argument), alors la valeur de contexte est utilisée comme valeur de `str`. Une erreur est renvoyée si `str` n'est pas une chaîne."
|
||||||
|
},
|
||||||
|
"$contains": {
|
||||||
|
"args": "str, pattern",
|
||||||
|
"desc": "Renvoie `true` si `str` correspond à `pattern`, sinon il renvoie `false`. Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée avec un argument), alors la valeur de contexte est utilisée comme valeur de `str`. Le paramètre `pattern` peut être une chaîne ou une expression régulière."
|
||||||
|
},
|
||||||
|
"$split": {
|
||||||
|
"args": "str[, separator][, limit]",
|
||||||
|
"desc": "Divise le paramètre `str` en un tableau de sous-chaînes. C'est une erreur si `str` n'est pas une chaîne. Le paramètre facultatif `separator` spécifie les caractères à l'intérieur de `str` à propos desquels il doit être divisé en chaîne ou en expression régulière. Si `separator` n'est pas spécifié, la chaîne vide est supposée et `str` sera divisé en un tableau de caractères uniques. C'est une erreur si `separator` n'est pas une chaîne. Le paramètre facultatif `limit` est un nombre qui spécifie le nombre maximum de sous-chaînes à inclure dans le tableau résultant. Toutes les sous-chaînes supplémentaires sont ignorées. Si `limit` n'est pas spécifié, alors `str` est entièrement divisé sans limite à la taille du tableau résultant. C'est une erreur si `limit` n'est pas un nombre non négatif."
|
||||||
|
},
|
||||||
|
"$join": {
|
||||||
|
"args": "array[, separator]",
|
||||||
|
"desc": "Joint un tableau de chaînes de composants en une seule chaîne concaténée, chaque chaîne de composants étant séparée par le paramètre facultatif `separator`. C'est une erreur si l'entrée `array` contient un élément qui n'est pas une chaîne. Si `séparateur` n'est pas spécifié, il est supposé être la chaîne vide, c'est-à-dire qu'il n'y a pas de `séparateur` entre les chaînes de composants. C'est une erreur si `separator` n'est pas une chaîne."
|
||||||
|
},
|
||||||
|
"$match": {
|
||||||
|
"args": "str, pattern [, limit]",
|
||||||
|
"desc": "Applique la chaîne `str` à l'expression régulière `pattern` et renvoie un tableau d'objets, chaque objet contenant des informations sur chaque occurrence d'une correspondance dans `str`."
|
||||||
|
},
|
||||||
|
"$replace": {
|
||||||
|
"args": "str, pattern, replacement [, limit]",
|
||||||
|
"desc": "Trouve les occurrences de `pattern` dans `str` et les remplace par `replacement`.\n\nLe paramètre facultatif `limit` est le nombre maximum de remplacements."
|
||||||
|
},
|
||||||
|
"$now": {
|
||||||
|
"args": "$[picture [, timezone]]",
|
||||||
|
"desc": "Génère un horodatage au format compatible ISO 8601 et le renvoie sous forme de chaîne. Si les paramètres optionnels d'image et de fuseau horaire sont fournis, alors l'horodatage actuel est formaté comme décrit par la fonction `$fromMillis()`"
|
||||||
|
},
|
||||||
|
"$base64encode": {
|
||||||
|
"args": "string",
|
||||||
|
"desc": "Convertit une chaîne ASCII en une représentation en base 64. Chaque caractère de la chaîne est traité comme un octet de données binaires. Cela nécessite que tous les caractères de la chaîne se trouvent dans la plage 0x00 à 0xFF, qui inclut tous les caractères des chaînes encodées en URI. Les caractères Unicode en dehors de cette plage ne sont pas pris en charge."
|
||||||
|
},
|
||||||
|
"$base64decode": {
|
||||||
|
"args": "string",
|
||||||
|
"desc": "Convertit les octets encodés en base 64 en une chaîne, à l'aide d'une page de codes Unicode UTF-8."
|
||||||
|
},
|
||||||
|
"$number": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Convertit le paramètre `arg` en un nombre en utilisant les règles de conversion suivantes :\n\n - Les nombres sont inchangés\n - Les chaînes qui contiennent une séquence de caractères représentant un nombre JSON légal sont converties en ce nombre\n - Toutes les autres valeurs provoquer l'envoi d'une erreur."
|
||||||
|
},
|
||||||
|
"$abs": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Renvoie la valeur absolue du paramètre `nombre`."
|
||||||
|
},
|
||||||
|
"$floor": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche inférieur ou égal à `number`."
|
||||||
|
},
|
||||||
|
"$ceil": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche supérieur ou égal à `number`."
|
||||||
|
},
|
||||||
|
"$round": {
|
||||||
|
"args": "number [, precision]",
|
||||||
|
"desc": "Renvoie la valeur du paramètre `number` arrondie au nombre de décimales spécifié par le paramètre facultatif `precision`."
|
||||||
|
},
|
||||||
|
"$power": {
|
||||||
|
"args": "base, exponent",
|
||||||
|
"desc": "Renvoie la valeur de `base` élevée à la puissance de `exponent`."
|
||||||
|
},
|
||||||
|
"$sqrt": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Renvoie la racine carrée de la valeur du paramètre `number`."
|
||||||
|
},
|
||||||
|
"$random": {
|
||||||
|
"args": "",
|
||||||
|
"desc": "Renvoie un nombre pseudo-aléatoire supérieur ou égal à zéro et inférieur à un."
|
||||||
|
},
|
||||||
|
"$millis": {
|
||||||
|
"args": "",
|
||||||
|
"desc": "Renvoie le nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Tous les appels de `$millis()` dans une évaluation d'une expression renverront toutes la même valeur."
|
||||||
|
},
|
||||||
|
"$sum": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie la somme arithmétique d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
|
||||||
|
},
|
||||||
|
"$max": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie le nombre maximal dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
|
||||||
|
},
|
||||||
|
"$min": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie le nombre minimum dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
|
||||||
|
},
|
||||||
|
"$average": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie la valeur moyenne d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre."
|
||||||
|
},
|
||||||
|
"$boolean": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Transforme l'argument en booléen en utilisant les règles suivantes :\n\n - `Boolean` : inchangé\n - `string` : vide : `false`\n - `string` : non vide : `true`\n - `number` : `0` : `false`\n - `number` : non nul : `true`\n - `null` : `false`\n - `array` : vide : `false`\n - `array` : contient un membre qui convertit en `true` : `true`\n - `array` : tous les membres sont transformés en `false` : `false`\n - `object` : vide : `false`\n - `object` : non vide : `true`\n - `function` : `false`"
|
||||||
|
},
|
||||||
|
"$not": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Renvoie un booléen résultat de la négation logique de l'argument"
|
||||||
|
},
|
||||||
|
"$exists": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Renvoie la valeur booléenne `true` si l'expression `arg` est évaluée à une valeur, ou `false` si l'expression ne correspond à rien (par exemple, un chemin vers une référence de champ inexistante)."
|
||||||
|
},
|
||||||
|
"$count": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie le nombre d'éléments du tableau"
|
||||||
|
},
|
||||||
|
"$append": {
|
||||||
|
"args": "array, array",
|
||||||
|
"desc": "Combine deux tableaux"
|
||||||
|
},
|
||||||
|
"$sort": {
|
||||||
|
"args": "array [, function]",
|
||||||
|
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais triées dans l'ordre.\n\nSi un comparateur `function` est fourni, alors il doit s'agir d'une fonction qui prend deux paramètres :\n\n`function(left , droite)`\n\nCette fonction est invoquée par l'algorithme de tri pour comparer deux valeurs à gauche et à droite. Si la valeur de `left` doit être placée après la valeur de `right` dans l'ordre de tri souhaité, la fonction doit renvoyer un booléen `true` pour indiquer un échange. Sinon, il doit renvoyer `false`."
|
||||||
|
},
|
||||||
|
"$reverse": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais dans l'ordre inverse."
|
||||||
|
},
|
||||||
|
"$shuffle": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais mélangées dans un ordre aléatoire."
|
||||||
|
},
|
||||||
|
"$zip": {
|
||||||
|
"args": "array, ...",
|
||||||
|
"desc": "Renvoie un tableau convolué (zippé) contenant des tableaux groupés de valeurs des arguments `array1`...`arrayN` d'index 0, 1, 2...."
|
||||||
|
},
|
||||||
|
"$keys": {
|
||||||
|
"args": "object",
|
||||||
|
"desc": "Renvoie un tableau contenant les clés de l'objet. Si l'argument est un tableau d'objets, le tableau renvoyé contient une liste dédupliquée de toutes les clés de tous les objets."
|
||||||
|
},
|
||||||
|
"$lookup": {
|
||||||
|
"args": "object, key",
|
||||||
|
"desc": "Renvoie la valeur associée à la clé dans l'objet. Si le premier argument est un tableau d'objets, tous les objets du tableau sont recherchés et les valeurs associées à toutes les occurrences de key sont renvoyées."
|
||||||
|
},
|
||||||
|
"$spread": {
|
||||||
|
"args": "object",
|
||||||
|
"desc": "Divise un objet contenant des paires clé/valeur en un tableau d'objets, chacun ayant une seule paire clé/valeur de l'objet d'entrée. Si le paramètre est un tableau d'objets, alors le tableau résultant contient un objet pour chaque paire clé/valeur dans chaque objet du tableau fourni."
|
||||||
|
},
|
||||||
|
"$merge": {
|
||||||
|
"args": "array<object>",
|
||||||
|
"desc": "Fusionne un tableau d'`objets` en un seul `objet` contenant toutes les paires clé/valeur de chacun des objets du tableau d'entrée. Si l'un des objets d'entrée contient la même clé, alors l'`objet` renvoyé contiendra la valeur du dernier dans le tableau. C'est une erreur si le tableau d'entrée contient un élément qui n'est pas un objet."
|
||||||
|
},
|
||||||
|
"$sift": {
|
||||||
|
"args": "object, function",
|
||||||
|
"desc": "Renvoie un objet qui contient uniquement les paires clé/valeur du paramètre `object` qui satisfont le prédicat `function` transmis comme second paramètre.\n\nLa `function` qui est fournie comme second paramètre doit avoir la signature suivante :\n\n`fonction(valeur [, clé [, objet]])`"
|
||||||
|
},
|
||||||
|
"$each": {
|
||||||
|
"args": "object, function",
|
||||||
|
"desc": "Renvoie un tableau contenant les valeurs renvoyées par la `fonction` lorsqu'elle est appliquée à chaque paire clé/valeur dans l'`objet`."
|
||||||
|
},
|
||||||
|
"$map": {
|
||||||
|
"args": "array, function",
|
||||||
|
"desc": "Renvoie un tableau contenant les résultats de l'application du paramètre `function` à chaque valeur du paramètre `array`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function( valeur [, indice [, tableau]])`"
|
||||||
|
},
|
||||||
|
"$filter": {
|
||||||
|
"args": "array, function",
|
||||||
|
"desc": "Renvoie un tableau contenant uniquement les valeurs du paramètre `array` qui satisfont le prédicat `function`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function(value [ , indice [, tableau]])`"
|
||||||
|
},
|
||||||
|
"$reduce": {
|
||||||
|
"args": "array, function [, init]",
|
||||||
|
"desc": "Renvoie une valeur agrégée dérivée de l'application successive du paramètre `function` à chaque valeur de `array` en combinaison avec le résultat de l'application précédente de la fonction.\n\nLa fonction doit accepter deux arguments et se comporte comme un opérateur infixe entre chaque valeur dans le `tableau`. La signature de `function` doit être de la forme : `myfunc($accumulator, $value[, $index[, $array]])`\n\nLe paramètre facultatif `init` est utilisé comme valeur initiale dans l'agrégation ."
|
||||||
|
},
|
||||||
|
"$flowContext": {
|
||||||
|
"args": "string[, string]",
|
||||||
|
"desc": "Récupère une propriété de contexte de flux.\n\nCeci est une fonction définie par Node-RED."
|
||||||
|
},
|
||||||
|
"$globalContext": {
|
||||||
|
"args": "string[, string]",
|
||||||
|
"desc": "Récupère une propriété de contexte globale.\n\nCeci est une fonction définie par Node-RED."
|
||||||
|
},
|
||||||
|
"$pad": {
|
||||||
|
"args": "string, width [, char]",
|
||||||
|
"desc": "Renvoie une copie de la `chaîne` avec un rembourrage supplémentaire, si nécessaire, de sorte que son nombre total de caractères corresponde au moins à la valeur absolue du paramètre `width`.\n\nSi `width` est un nombre positif, alors la chaîne est rembourré à droite; s'il est négatif, il est rempli vers la gauche.\n\nL'argument optionnel `char` spécifie le(s) caractère(s) de remplissage à utiliser. S'il n'est pas spécifié, la valeur par défaut est le caractère espace."
|
||||||
|
},
|
||||||
|
"$fromMillis": {
|
||||||
|
"args": "number, [, picture [, timezone]]",
|
||||||
|
"desc": "Convertisser le « nombre » représentant les millisecondes depuis l'époque Unix (1er janvier 1970 UTC) en une représentation sous forme de chaîne formatée de l'horodatage tel que spécifié par la chaîne d'image.\n\nSi le paramètre facultatif « image » est omis, l'horodatage est formaté au format ISO 8601.\n\nSi la chaîne facultative `image` est fournie, l'horodatage est formaté selon la représentation spécifiée dans cette chaîne. Le comportement de cette fonction est cohérent avec la version à deux arguments de la fonction XPath/XQuery `format-dateTime` telle que définie dans la spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont l'horodatage est formaté et a la même syntaxe que `format-dateTime`.\n\nSi la chaîne facultative `timezone` est fournie, alors l'horodatage formaté sera dans ce fuseau horaire. La chaîne `timezone` doit être au format '±HHMM', où ± est le signe plus ou moins et HHMM est le décalage en heures et minutes par rapport à UTC. Décalage positif pour les fuseaux horaires à l'est de UTC, décalage négatif pour les fuseaux horaires à l'ouest de UTC."
|
||||||
|
},
|
||||||
|
"$formatNumber": {
|
||||||
|
"args": "number, picture [, options]",
|
||||||
|
"desc": "Convertit le `number` en une chaîne et le formate en une représentation décimale comme spécifié par la chaîne `picture`.\n\n Le comportement de cette fonction est cohérent avec la fonction XPath/XQuery `fn:format-number` telle que définie dans le Spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-number`.\n\nLe troisième argument facultatif `options` est utilisé pour remplacer les caractères de formatage spécifiques aux paramètres régionaux par défaut, tels que le séparateur décimal. S'il est fourni, cet argument doit être un objet contenant des paires nom/valeur spécifiées dans la section de format décimal de la spécification XPath F&O 3.1."
|
||||||
|
},
|
||||||
|
"$formatBase": {
|
||||||
|
"args": "number [, radix]",
|
||||||
|
"desc": "Convertit le `number` en une chaîne et le formate en un entier représenté dans la base numérique spécifiée par l'argument `radix`. Si `radix` n'est pas spécifié, la valeur par défaut est la base 10. `radix` peut être compris entre 2 et 36, sinon une erreur est renvoyée."
|
||||||
|
},
|
||||||
|
"$toMillis": {
|
||||||
|
"args": "timestamp",
|
||||||
|
"desc": "Convertit une chaîne `timestamp` au format ISO 8601 en nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Une erreur est renvoyée si la chaîne n'est pas au format correct."
|
||||||
|
},
|
||||||
|
"$env": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Renvoie la valeur d'une variable d'environnement.\n\nCeci est une fonction définie par Node-RED."
|
||||||
|
},
|
||||||
|
"$eval": {
|
||||||
|
"args": "expr [, context]",
|
||||||
|
"desc": "Analyse et évalue la chaîne `expr` qui contient un JSON littéral ou une expression JSONata en utilisant le contexte actuel comme contexte d'évaluation."
|
||||||
|
},
|
||||||
|
"$formatInteger": {
|
||||||
|
"args": "number, picture",
|
||||||
|
"desc": "Transforme le `nombre` en une chaîne et le formate en une représentation entière comme spécifié par la chaîne `image`. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-integer` de la spécification XPath F&O 3.1."
|
||||||
|
},
|
||||||
|
"$parseInteger": {
|
||||||
|
"args": "string, picture",
|
||||||
|
"desc": "Analyse le contenu du paramètre `string` en un entier (comme un nombre JSON) en utilisant le format spécifié par la chaîne `picture`. Le paramètre de chaîne `picture` a le même format que `$formatInteger`."
|
||||||
|
},
|
||||||
|
"$error": {
|
||||||
|
"args": "[str]",
|
||||||
|
"desc": "Génère une erreur avec un message. Le `str` facultatif remplacera le message par défaut de la fonction `$error() évaluée`"
|
||||||
|
},
|
||||||
|
"$assert": {
|
||||||
|
"args": "arg, str",
|
||||||
|
"desc": "Si `arg` est vrai, la fonction renvoie undefined. Si `arg` est faux, une exception est lancée avec `str` comme message de l'exception."
|
||||||
|
},
|
||||||
|
"$single": {
|
||||||
|
"args": "array, function",
|
||||||
|
"desc": "Renvoie la seule et unique valeur du paramètre `array` qui satisfait le prédicat `function` (c'est-à-dire que la `function` renvoie la valeur booléenne `true` lorsqu'elle est transmise à la valeur). Lève une exception si le nombre de valeurs correspondantes n'est pas exactement un.\n\nLa fonction doit être fournie dans la signature suivante : `function(value [, index [, array]])` où value est chaque entrée du tableau, index est la position de cette valeur et le tableau entier est passé comme troisième argument"
|
||||||
|
},
|
||||||
|
"$encodeUrlComponent": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Encode un composant URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère.\n\nExemple : `$encodeUrlComponent(\"?x =test\")` => `\"%3Fx%3Dtest\"`"
|
||||||
|
},
|
||||||
|
"$encodeUrl": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Encode une URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère.\n\nExemple : `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0% B5%D0%BB%D0%BB%D1%8B\"`"
|
||||||
|
},
|
||||||
|
"$decodeUrlComponent": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Décode un composant URL (Uniform Resource Locator) précédemment créé par encodeUrlComponent.\n\nExemple : `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
|
||||||
|
},
|
||||||
|
"$decodeUrl": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Décode une URL (Uniform Resource Locator) précédemment créée par encodeUrl.\n\nExemple : `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
|
||||||
|
},
|
||||||
|
"$distinct": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Renvoie un tableau avec les valeurs en double supprimées de `array`"
|
||||||
|
},
|
||||||
|
"$type": {
|
||||||
|
"args": "value",
|
||||||
|
"desc": "Renvoie le type de `value` sous forme de chaîne. Si `value` n'est pas défini, cela renverra `undefined`"
|
||||||
|
},
|
||||||
|
"$moment": {
|
||||||
|
"args": "[str]",
|
||||||
|
"desc": "Obtient un objet de date à l'aide de la bibliothèque Moment."
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,11 @@
|
|||||||
"position": "配置",
|
"position": "配置",
|
||||||
"enable": "有効",
|
"enable": "有効",
|
||||||
"disable": "無効",
|
"disable": "無効",
|
||||||
"upload": "アップロード"
|
"upload": "アップロード",
|
||||||
|
"lock": "固定",
|
||||||
|
"unlock": "固定を解除",
|
||||||
|
"locked": "固定済み",
|
||||||
|
"unlocked": "固定なし"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"string": "文字列",
|
"string": "文字列",
|
||||||
@ -53,8 +57,10 @@
|
|||||||
"confirmDelete": "削除の確認",
|
"confirmDelete": "削除の確認",
|
||||||
"delete": "本当に '__label__' を削除しますか?",
|
"delete": "本当に '__label__' を削除しますか?",
|
||||||
"dropFlowHere": "ここにフローをドロップしてください",
|
"dropFlowHere": "ここにフローをドロップしてください",
|
||||||
|
"dropImageHere": "ここに画像ファイルをドロップしてください",
|
||||||
"addFlow": "フローの追加",
|
"addFlow": "フローの追加",
|
||||||
"addFlowToRight": "右側にフローを追加",
|
"addFlowToRight": "右側にフローを追加",
|
||||||
|
"closeFlow": "フローを閉じる",
|
||||||
"hideFlow": "フローを非表示",
|
"hideFlow": "フローを非表示",
|
||||||
"hideOtherFlows": "他のフローを非表示",
|
"hideOtherFlows": "他のフローを非表示",
|
||||||
"showAllFlows": "全てのフローを表示",
|
"showAllFlows": "全てのフローを表示",
|
||||||
@ -68,7 +74,13 @@
|
|||||||
"enabled": "有効",
|
"enabled": "有効",
|
||||||
"disabled": "無効",
|
"disabled": "無効",
|
||||||
"info": "詳細",
|
"info": "詳細",
|
||||||
"selectNodes": "ノードをクリックして選択"
|
"selectNodes": "ノードをクリックして選択",
|
||||||
|
"enableFlow": "フローを有効化",
|
||||||
|
"disableFlow": "フローを無効化",
|
||||||
|
"lockFlow": "フローを固定",
|
||||||
|
"unlockFlow": "フローの固定を解除",
|
||||||
|
"moveToStart": "フローを先頭へ移動",
|
||||||
|
"moveToEnd": "フローを最後へ移動"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"label": {
|
"label": {
|
||||||
@ -101,6 +113,7 @@
|
|||||||
"displayStatus": "ノードのステータスを表示",
|
"displayStatus": "ノードのステータスを表示",
|
||||||
"displayConfig": "設定ノード",
|
"displayConfig": "設定ノード",
|
||||||
"import": "読み込み",
|
"import": "読み込み",
|
||||||
|
"importExample": "フロー例を読み込み",
|
||||||
"export": "書き出し",
|
"export": "書き出し",
|
||||||
"search": "ノードを検索",
|
"search": "ノードを検索",
|
||||||
"searchInput": "ノードを検索",
|
"searchInput": "ノードを検索",
|
||||||
@ -499,6 +512,7 @@
|
|||||||
"addRemoveNode": "ノードの選択、選択解除",
|
"addRemoveNode": "ノードの選択、選択解除",
|
||||||
"editSelected": "選択したノードを編集",
|
"editSelected": "選択したノードを編集",
|
||||||
"deleteSelected": "選択したノードや接続を削除",
|
"deleteSelected": "選択したノードや接続を削除",
|
||||||
|
"deleteReconnect": "削除と再接続",
|
||||||
"importNode": "フローの読み込み",
|
"importNode": "フローの読み込み",
|
||||||
"exportNode": "フローの書き出し",
|
"exportNode": "フローの書き出し",
|
||||||
"nudgeNode": "選択したノードを移動(移動量小)",
|
"nudgeNode": "選択したノードを移動(移動量小)",
|
||||||
@ -573,6 +587,7 @@
|
|||||||
"editor": {
|
"editor": {
|
||||||
"title": "パレットの管理",
|
"title": "パレットの管理",
|
||||||
"palette": "パレット",
|
"palette": "パレット",
|
||||||
|
"allCatalogs": "全カタログ",
|
||||||
"times": {
|
"times": {
|
||||||
"seconds": "数秒前",
|
"seconds": "数秒前",
|
||||||
"minutes": "数分前",
|
"minutes": "数分前",
|
||||||
@ -612,6 +627,7 @@
|
|||||||
"tab-nodes": "現在のノード",
|
"tab-nodes": "現在のノード",
|
||||||
"tab-install": "ノードを追加",
|
"tab-install": "ノードを追加",
|
||||||
"sort": "並べ替え:",
|
"sort": "並べ替え:",
|
||||||
|
"sortRelevance": "関連順",
|
||||||
"sortAZ": "辞書順",
|
"sortAZ": "辞書順",
|
||||||
"sortRecent": "日付順",
|
"sortRecent": "日付順",
|
||||||
"more": "+ さらに __count__ 個",
|
"more": "+ さらに __count__ 個",
|
||||||
@ -685,9 +701,11 @@
|
|||||||
"empty": "空",
|
"empty": "空",
|
||||||
"globalConfig": "グローバル設定ノード",
|
"globalConfig": "グローバル設定ノード",
|
||||||
"triggerAction": "アクションを実行",
|
"triggerAction": "アクションを実行",
|
||||||
|
"find": "ワークスペース内を検索",
|
||||||
|
"copyItemUrl": "要素のURLをコピー",
|
||||||
|
"copyURL2Clipboard": "URLをクリップボードにコピーしました",
|
||||||
"showFlow": "表示",
|
"showFlow": "表示",
|
||||||
"hideFlow": "非表示",
|
"hideFlow": "非表示"
|
||||||
"find": "ワークスペース内を検索"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"name": "ヘルプ",
|
"name": "ヘルプ",
|
||||||
@ -988,7 +1006,10 @@
|
|||||||
"quote": "引用",
|
"quote": "引用",
|
||||||
"link": "リンク",
|
"link": "リンク",
|
||||||
"horizontal-rule": "区切り線",
|
"horizontal-rule": "区切り線",
|
||||||
"toggle-preview": "プレビュー表示切替え"
|
"toggle-preview": "プレビュー表示切替え",
|
||||||
|
"mermaid": {
|
||||||
|
"summary": "Mermaid図"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"bufferEditor": {
|
"bufferEditor": {
|
||||||
"title": "バッファエディタ",
|
"title": "バッファエディタ",
|
||||||
@ -1183,8 +1204,10 @@
|
|||||||
"languages": {
|
"languages": {
|
||||||
"de": "ドイツ語",
|
"de": "ドイツ語",
|
||||||
"en-US": "英語",
|
"en-US": "英語",
|
||||||
|
"fr": "フランス語",
|
||||||
"ja": "日本語",
|
"ja": "日本語",
|
||||||
"ko": "韓国語",
|
"ko": "韓国語",
|
||||||
|
"pt-BR": "ポルトガル語",
|
||||||
"ru": "ロシア語",
|
"ru": "ロシア語",
|
||||||
"zh-CN": "中国語(簡体)",
|
"zh-CN": "中国語(簡体)",
|
||||||
"zh-TW": "中国語(繁体)"
|
"zh-TW": "中国語(繁体)"
|
||||||
@ -1211,6 +1234,11 @@
|
|||||||
"junction": "分岐点",
|
"junction": "分岐点",
|
||||||
"linkNodes": "Linkノード"
|
"linkNodes": "Linkノード"
|
||||||
},
|
},
|
||||||
|
"env-var": {
|
||||||
|
"environment": "環境変数",
|
||||||
|
"header": "大域環境変数",
|
||||||
|
"revert": "破棄"
|
||||||
|
},
|
||||||
"action-list": {
|
"action-list": {
|
||||||
"toggle-show-tips": "ヒント表示切替",
|
"toggle-show-tips": "ヒント表示切替",
|
||||||
"show-about": "Node-REDの説明を表示",
|
"show-about": "Node-REDの説明を表示",
|
||||||
@ -1295,6 +1323,7 @@
|
|||||||
"distribute-selection-vertically": "選択を上下に整列",
|
"distribute-selection-vertically": "選択を上下に整列",
|
||||||
"wire-series-of-nodes": "ノードを一続きに接続",
|
"wire-series-of-nodes": "ノードを一続きに接続",
|
||||||
"wire-node-to-multiple": "ノードを複数に接続",
|
"wire-node-to-multiple": "ノードを複数に接続",
|
||||||
|
"wire-multiple-to-node": "複数からノードへ接続",
|
||||||
"split-wire-with-link-nodes": "ワイヤーをlinkノードで分割",
|
"split-wire-with-link-nodes": "ワイヤーをlinkノードで分割",
|
||||||
"generate-node-names": "ノード名を生成",
|
"generate-node-names": "ノード名を生成",
|
||||||
"show-user-settings": "ユーザ設定を表示",
|
"show-user-settings": "ユーザ設定を表示",
|
||||||
@ -1354,6 +1383,14 @@
|
|||||||
"show-project-settings": "プロジェクト設定を表示",
|
"show-project-settings": "プロジェクト設定を表示",
|
||||||
"show-version-control-tab": "バージョンコントロールタブを表示",
|
"show-version-control-tab": "バージョンコントロールタブを表示",
|
||||||
"start-flows": "フローを開始",
|
"start-flows": "フローを開始",
|
||||||
"stop-flows": "フローを停止"
|
"stop-flows": "フローを停止",
|
||||||
|
"copy-item-url": "要素のURLをコピー",
|
||||||
|
"copy-item-edit-url": "要素の編集URLをコピー",
|
||||||
|
"move-flow-to-start": "フローを先頭に移動",
|
||||||
|
"move-flow-to-end": "フローを末尾に移動",
|
||||||
|
"show-global-env": "大域環境変数を表示",
|
||||||
|
"lock-flow": "フローを固定",
|
||||||
|
"unlock-flow": "フローの固定を解除",
|
||||||
|
"show-node-help": "ノードのヘルプを表示"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
},
|
},
|
||||||
"$now": {
|
"$now": {
|
||||||
"args": "$[picture [, timezone]]",
|
"args": "$[picture [, timezone]]",
|
||||||
"desc": "ISO 8601互換形式の時刻を生成し、文字列として返します。pictureおよびtimezoneパラメータが指定されている場合、現在時刻を`$fromMillis()`関数の説明に従ってフォーマットします。"
|
"desc": "ISO 8601互換形式の時刻を生成し、文字列として返します。`picture` および `timezone` パラメータが指定されている場合、現在時刻を `$fromMillis()` 関数の説明に従ってフォーマットします。"
|
||||||
},
|
},
|
||||||
"$base64encode": {
|
"$base64encode": {
|
||||||
"args": "string",
|
"args": "string",
|
||||||
@ -117,11 +117,11 @@
|
|||||||
},
|
},
|
||||||
"$boolean": {
|
"$boolean": {
|
||||||
"args": "arg",
|
"args": "arg",
|
||||||
"desc": "以下のルールを用いて、ブーリアン型へ型変換します。:\n\n - `Boolean` : 変換しない\n - `string`: 空 : `false`\n - `string`: 空でない : `true`\n - `number`: `0` : `false`\n - `number`: 0でない : `true`\n - `null` : `false`\n - `array`: 空 : `false`\n - `array`: `true` に型変換された要素を持つ: `true`\n - `array`: 全ての要素が `false` に型変換: `false`\n - `object`: 空 : `false`\n - `object`: 空でない : `true`\n - `function` : `false`"
|
"desc": "以下のルールを用いて、真偽型へ型変換します。:\n\n - `Boolean` : 変換しない\n - `string`: 空 : `false`\n - `string`: 空でない : `true`\n - `number`: `0` : `false`\n - `number`: 0でない : `true`\n - `null` : `false`\n - `array`: 空 : `false`\n - `array`: `true` に型変換された要素を持つ: `true`\n - `array`: 全ての要素が `false` に型変換: `false`\n - `object`: 空 : `false`\n - `object`: 空でない : `true`\n - `function` : `false`"
|
||||||
},
|
},
|
||||||
"$not": {
|
"$not": {
|
||||||
"args": "arg",
|
"args": "arg",
|
||||||
"desc": "引数の否定をブーリアン型で返します。 `arg` は最初にブーリアン型に型変換されます。"
|
"desc": "引数の否定を真偽型で返します。 `arg` は最初に真偽型に型変換されます。"
|
||||||
},
|
},
|
||||||
"$exists": {
|
"$exists": {
|
||||||
"args": "arg",
|
"args": "arg",
|
||||||
@ -137,7 +137,7 @@
|
|||||||
},
|
},
|
||||||
"$sort": {
|
"$sort": {
|
||||||
"args": "array [, function]",
|
"args": "array [, function]",
|
||||||
"desc": "配列 `array` 内の値を並び変えた配列を返します。\n\n比較関数 `function` を用いる場合、比較関数は以下のとおり2つの引数を持つ必要があります。\n\n`function(left, right)`\n\n比較関数は、leftとrightの2つの値を比較するために、値を並び替える処理で呼び出されます。もし、求められる並び順にてleftの値をrightの値より後ろに置きたい場合は、比較関数は置き換えを表すブーリアン型の `true` を返す必要があります。一方、置き換えが不要の場合は `false` を返す必要があります。"
|
"desc": "配列 `array` 内の値を並び変えた配列を返します。\n\n比較関数 `function` を用いる場合、比較関数は以下のとおり2つの引数を持つ必要があります。\n\n`function(left, right)`\n\n比較関数は、`left` と `right` の2つの値を比較するために、値を並び替える処理で呼び出されます。もし、求められる並び順にて `left` の値を `right` の値より後ろに置きたい場合は、比較関数は置き換えを表す真偽型の `true` を返す必要があります。一方、置き換えが不要の場合は `false` を返す必要があります。"
|
||||||
},
|
},
|
||||||
"$reverse": {
|
"$reverse": {
|
||||||
"args": "array",
|
"args": "array",
|
||||||
@ -205,7 +205,7 @@
|
|||||||
},
|
},
|
||||||
"$formatNumber": {
|
"$formatNumber": {
|
||||||
"args": "number, picture [, options]",
|
"args": "number, picture [, options]",
|
||||||
"desc": "`number` を文字列へ変換し、文字列 `picture` に指定した数値表現になるよう書式を変更します。\n\nこの関数の動作は、XPath F&O 3.1の仕様に定義されているXPath/XQuery関数のfn:format-numberの動作と同じです。引数の文字列 picture は、fn:format-numberと同じ構文で数値の書式を定義します。\n\n任意の第三引数 `options` は、小数点記号の様な既定のロケール固有の書式設定文字を上書きするために使用します。この引数を指定する場合、XPath F&O 3.1の仕様の数値形式の項に記述されているname/valueペアを含むオブジェクトでなければなりません。"
|
"desc": "`number` を文字列へ変換し、文字列 `picture` に指定した数値表現になるよう書式を変更します。\n\nこの関数の動作は、XPath F&O 3.1の仕様に定義されているXPath/XQuery関数の `fn:format-number` の動作と同じです。引数の文字列 `picture` は、 `fn:format-number` と同じ構文で数値の書式を定義します。\n\n任意の第三引数 `options` は、小数点記号の様な既定のロケール固有の書式設定文字を上書きするために使用します。この引数を指定する場合、XPath F&O 3.1の仕様の数値形式の項に記述されているname/valueペアを含むオブジェクトでなければなりません。"
|
||||||
},
|
},
|
||||||
"$formatBase": {
|
"$formatBase": {
|
||||||
"args": "number [, radix]",
|
"args": "number [, radix]",
|
||||||
@ -237,7 +237,7 @@
|
|||||||
},
|
},
|
||||||
"$assert": {
|
"$assert": {
|
||||||
"args": "arg, str",
|
"args": "arg, str",
|
||||||
"desc": "`arg`が真の場合、undefinedを返します。偽の場合、`str`をメッセージとする例外を送出します。"
|
"desc": "`arg`が真の場合、`undefined`を返します。偽の場合、`str`をメッセージとする例外を送出します。"
|
||||||
},
|
},
|
||||||
"$single": {
|
"$single": {
|
||||||
"args": "array, function",
|
"args": "array, function",
|
||||||
@ -270,5 +270,9 @@
|
|||||||
"$moment": {
|
"$moment": {
|
||||||
"args": "[str]",
|
"args": "[str]",
|
||||||
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
|
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
|
||||||
|
},
|
||||||
|
"$clone": {
|
||||||
|
"args": "value",
|
||||||
|
"desc": "オブジェクトを安全に複製します。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,16 +24,29 @@
|
|||||||
"delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?",
|
"delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?",
|
||||||
"dropFlowHere": "플로우를 이곳에 가져오세요",
|
"dropFlowHere": "플로우를 이곳에 가져오세요",
|
||||||
"addFlow": "플로우 추가",
|
"addFlow": "플로우 추가",
|
||||||
|
"addFlowToRight": "오른쪽에 플로우 추가",
|
||||||
|
"hideFlow": "플로우 숨기기",
|
||||||
|
"hideOtherFlows": "다른 플로우 숨기기",
|
||||||
|
"showAllFlows": "모든 플로우 보기",
|
||||||
|
"hideAllFlows": "모든 플로우 숨기기",
|
||||||
|
"hiddenFlows": "__count__개의 숨겨진 플로우 보기",
|
||||||
|
"hiddenFlows_plural": "__count__개의 숨겨진 플로우 보기",
|
||||||
|
"showLastHiddenFlow": "마지막으로 숨겨진 플로우 보기",
|
||||||
|
"listFlows": "플로우 리스트",
|
||||||
|
"listSubflows": "서브 플로우 리스트",
|
||||||
"status": "상태",
|
"status": "상태",
|
||||||
"enabled": "사용가능",
|
"enabled": "사용가능",
|
||||||
"disabled": "사용불가능",
|
"disabled": "사용불가능",
|
||||||
"info": "상세내역"
|
"info": "상세내역",
|
||||||
|
"selectNodes": "선택할 노드 클릭"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"label": {
|
"label": {
|
||||||
"view": {
|
"view": {
|
||||||
"view": "창",
|
"view": "창",
|
||||||
"grid": "눈금선",
|
"grid": "눈금선",
|
||||||
|
"storeZoom": "불러오기 시 확대/축소 복원",
|
||||||
|
"storePosition": "불러오기 시 스크롤 위치 복원",
|
||||||
"showGrid": "눈금선 보이기",
|
"showGrid": "눈금선 보이기",
|
||||||
"snapGrid": "노드 배치 보조 켜기",
|
"snapGrid": "노드 배치 보조 켜기",
|
||||||
"gridSize": "눈금선 크기",
|
"gridSize": "눈금선 크기",
|
||||||
@ -41,7 +54,9 @@
|
|||||||
"defaultDir": "기본",
|
"defaultDir": "기본",
|
||||||
"ltr": "왼쪽 -> 오른쪽",
|
"ltr": "왼쪽 -> 오른쪽",
|
||||||
"rtl": "오른쪽 -> 왼쪽",
|
"rtl": "오른쪽 -> 왼쪽",
|
||||||
"auto": "자동배분"
|
"auto": "자동배분",
|
||||||
|
"language": "언어",
|
||||||
|
"browserDefault": "브라우저 기본값"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"show": "우측사이드바 보이기"
|
"show": "우측사이드바 보이기"
|
||||||
@ -49,6 +64,7 @@
|
|||||||
"palette": {
|
"palette": {
|
||||||
"show": "팔렛트 보이기"
|
"show": "팔렛트 보이기"
|
||||||
},
|
},
|
||||||
|
"edit": "수정",
|
||||||
"settings": "설정",
|
"settings": "설정",
|
||||||
"userSettings": "사용자 설정",
|
"userSettings": "사용자 설정",
|
||||||
"nodes": "노드설정",
|
"nodes": "노드설정",
|
||||||
@ -58,9 +74,9 @@
|
|||||||
"export": "내보내기",
|
"export": "내보내기",
|
||||||
"search": "플로우 검색",
|
"search": "플로우 검색",
|
||||||
"searchInput": "플로우 검색",
|
"searchInput": "플로우 검색",
|
||||||
"subflows": "보조 플로우",
|
"subflows": "서브 플로우",
|
||||||
"createSubflow": "보조 플로우 생성",
|
"createSubflow": "서브 플로우 생성",
|
||||||
"selectionToSubflow": "보조 플로우 선택",
|
"selectionToSubflow": "서브 플로우 선택",
|
||||||
"flows": "플로우",
|
"flows": "플로우",
|
||||||
"add": "추가",
|
"add": "추가",
|
||||||
"rename": "이름변경",
|
"rename": "이름변경",
|
||||||
@ -71,19 +87,43 @@
|
|||||||
"editPalette": "팔렛트 관리",
|
"editPalette": "팔렛트 관리",
|
||||||
"other": "기타",
|
"other": "기타",
|
||||||
"showTips": "Tip 보기",
|
"showTips": "Tip 보기",
|
||||||
|
"showWelcomeTours": "새 버전에 대한 가이드 보기 표시",
|
||||||
"help": "Node-RED 웹사이트",
|
"help": "Node-RED 웹사이트",
|
||||||
"projects": "프로젝트",
|
"projects": "프로젝트",
|
||||||
"projects-new": "신규",
|
"projects-new": "신규",
|
||||||
"projects-open": "열기",
|
"projects-open": "열기",
|
||||||
"projects-settings": "프로젝트 설정",
|
"projects-settings": "프로젝트 설정",
|
||||||
"showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기"
|
"showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기",
|
||||||
|
"codeEditor": "Code Editor",
|
||||||
|
"groups": "그룹",
|
||||||
|
"groupSelection": "그룹 선택",
|
||||||
|
"ungroupSelection": "그룹 선택 해제",
|
||||||
|
"groupMergeSelection": "선택 항목 병합",
|
||||||
|
"groupRemoveSelection": "선택 그룹 제거",
|
||||||
|
"arrange": "배치",
|
||||||
|
"alignLeft": "왼쪽으로 정렬",
|
||||||
|
"alignCenter": "가운데 정렬",
|
||||||
|
"alignRight": "오른쪽으로 정렬",
|
||||||
|
"alignTop": "맨 위에 정렬",
|
||||||
|
"alignMiddle": "맨 위에 정렬",
|
||||||
|
"alignBottom": "맨 아래 정렬",
|
||||||
|
"distributeHorizontally": "수평으로 배치",
|
||||||
|
"distributeVertically": "수직으로 배치",
|
||||||
|
"moveToBack": "맨 뒤로 이동",
|
||||||
|
"moveToFront": "맨 앞으로 이동",
|
||||||
|
"moveBackwards": "뒤로 이동",
|
||||||
|
"moveForwards": "앞으로 이동"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"toggle-navigator": "네비게이터 표시/비표시",
|
"toggle-navigator": "네비게이터 표시/비표시",
|
||||||
"zoom-out": "축소하기",
|
"zoom-out": "축소하기",
|
||||||
"zoom-reset": "확대/축소 초기화",
|
"zoom-reset": "확대/축소 초기화",
|
||||||
"zoom-in": "확대하기"
|
"zoom-in": "확대하기",
|
||||||
|
"search-flows": "플로우 찾기",
|
||||||
|
"search-prev": "이전",
|
||||||
|
"search-next": "다음",
|
||||||
|
"search-counter": "\"__term__\" __result__ of __count__"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"loggedInAs": "__name__ 에 로그인됨",
|
"loggedInAs": "__name__ 에 로그인됨",
|
||||||
@ -99,12 +139,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification": {
|
"notification": {
|
||||||
|
"state": {
|
||||||
|
"flowsStopped": "플로우 중지됨",
|
||||||
|
"flowsStarted": "플로우 시작됨"
|
||||||
|
},
|
||||||
"warning": "<strong>경고</strong>: __message__",
|
"warning": "<strong>경고</strong>: __message__",
|
||||||
"warnings": {
|
"warnings": {
|
||||||
"undeployedChanges": "변경사항 배포가 취소되었습니다",
|
"undeployedChanges": "변경사항 배포가 취소되었습니다",
|
||||||
"nodeActionDisabled": "노드 실행이 비활성화 되었습니다",
|
"nodeActionDisabled": "노드 실행이 비활성화 되었습니다",
|
||||||
"nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다",
|
"nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다",
|
||||||
"missing-types": "<p>타입이 없는 노드로인해 플로우가 중지되었습니다</p>",
|
"missing-types": "<p>타입이 없는 노드로인해 플로우가 중지되었습니다</p>",
|
||||||
|
"missing-modules": "<p>누락된 모듈로 인해 플로우가 중지되었습니다.</p>",
|
||||||
"safe-mode": "<p>[안전모드] 플로우가 정지되었습니다.</p><p>플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.</p>",
|
"safe-mode": "<p>[안전모드] 플로우가 정지되었습니다.</p><p>플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.</p>",
|
||||||
"restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ",
|
"restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ",
|
||||||
"credentials_load_failed": "<p>인증정보 복호화에 실패하여 플로우가 멈췄습니다. </p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p>",
|
"credentials_load_failed": "<p>인증정보 복호화에 실패하여 플로우가 멈췄습니다. </p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p>",
|
||||||
@ -132,7 +177,12 @@
|
|||||||
"updated": "'__project__'가 변경 되었습니다",
|
"updated": "'__project__'가 변경 되었습니다",
|
||||||
"pull": "'__project__'를 다시 가져왔습니다",
|
"pull": "'__project__'를 다시 가져왔습니다",
|
||||||
"revert": "'__project__'를 취소했습니다",
|
"revert": "'__project__'를 취소했습니다",
|
||||||
"merge-complete": "Git 병합이 완료되었습니다"
|
"merge-complete": "Git 병합이 완료되었습니다",
|
||||||
|
"setupCredentials": "자격 증명 설정",
|
||||||
|
"setupProjectFiles": "프로젝트 파일 설정",
|
||||||
|
"no": "취소",
|
||||||
|
"createDefault": "기본 프로젝트 파일 만들기",
|
||||||
|
"mergeConflict": "병합 충돌 표시"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"manage-project-dep": "프로젝트 의존성 관리",
|
"manage-project-dep": "프로젝트 의존성 관리",
|
||||||
@ -152,10 +202,14 @@
|
|||||||
"node_plural": "__count__ 개의 노드",
|
"node_plural": "__count__ 개의 노드",
|
||||||
"configNode": "__count__ 개의 설정 노드",
|
"configNode": "__count__ 개의 설정 노드",
|
||||||
"configNode_plural": "__count__ 개의 설정 노드",
|
"configNode_plural": "__count__ 개의 설정 노드",
|
||||||
|
"group": "__count__ 개의 그룹",
|
||||||
|
"group_plural": "__count__ 개의 그룹",
|
||||||
"flow": "__count__ 개의 플로우",
|
"flow": "__count__ 개의 플로우",
|
||||||
"flow_plural": "__count__ 개의 플로우",
|
"flow_plural": "__count__ 개의 플로우",
|
||||||
"subflow": "__count__ 개의 서브 플로우",
|
"subflow": "__count__ 개의 서브 플로우",
|
||||||
"subflow_plural": "__count__ 개의 서브 플로우",
|
"subflow_plural": "__count__ 개의 서브 플로우",
|
||||||
|
"replacedNodes": "__count__ 개의 교체된 노드",
|
||||||
|
"replacedNodes_plural": "__count__ 개의 교체된 노드",
|
||||||
"pasteNodes": "여기에 노드를 붙여넣기 하세요",
|
"pasteNodes": "여기에 노드를 붙여넣기 하세요",
|
||||||
"selectFile": "불러올 파일을 선택하세요",
|
"selectFile": "불러올 파일을 선택하세요",
|
||||||
"importNodes": "노드 불러오기",
|
"importNodes": "노드 불러오기",
|
||||||
@ -163,28 +217,46 @@
|
|||||||
"download": "다운로드",
|
"download": "다운로드",
|
||||||
"importUnrecognised": "알 수 없는 형식 :",
|
"importUnrecognised": "알 수 없는 형식 :",
|
||||||
"importUnrecognised_plural": "알 수 없는 형식 :",
|
"importUnrecognised_plural": "알 수 없는 형식 :",
|
||||||
|
"importDuplicate": "가져온 중복 노드:",
|
||||||
|
"importDuplicate_plural": "가져온 중복 노드:",
|
||||||
"nodesExported": "클립보드에 노드 내보내기",
|
"nodesExported": "클립보드에 노드 내보내기",
|
||||||
"nodesImported": "불러오기 : ",
|
"nodesImported": "불러오기 : ",
|
||||||
"nodeCopied": "__count__개의 노드가 복사되었습니다",
|
"nodeCopied": "__count__개의 노드가 복사되었습니다",
|
||||||
"nodeCopied_plural": "__count__개의 노드가 복사되었습니다",
|
"nodeCopied_plural": "__count__개의 노드가 복사되었습니다",
|
||||||
|
"groupCopied": "__count__ 개의 그룹이 복사되었습니다",
|
||||||
|
"groupCopied_plural": "__count__ 개의 그룹이 복사되었습니다",
|
||||||
|
"groupStyleCopied": "그룹 스타일이 복사되었습니다",
|
||||||
"invalidFlow": "정상적지 않은 플로우 : __message__",
|
"invalidFlow": "정상적지 않은 플로우 : __message__",
|
||||||
|
"recoveredNodes": "복구된 노드",
|
||||||
|
"recoveredNodesInfo": "이 플로우의 노드를 가져올 때 유효한 플로우 ID가 누락되었습니다. 해당 플로우에 추가되었으므로 복원하거나 삭제할 수 있습니다.",
|
||||||
|
"recoveredNodesNotification": "<p>유효하지 않은 플로우 ID를 가진 노드입니다.</p><p>'__flowName__' 라는 플로우에 추가되었습니다.</p>",
|
||||||
"export": {
|
"export": {
|
||||||
"selected": "선택된 노드",
|
"selected": "선택된 노드",
|
||||||
"current": "현재 플로우",
|
"current": "현재 플로우",
|
||||||
"all": "모든 플로우",
|
"all": "모든 플로우",
|
||||||
"compact": "압축형식",
|
"compact": "압축형식",
|
||||||
"formatted": "서식유지",
|
"formatted": "서식유지",
|
||||||
"copy": "클립보드로 내보내기"
|
"copy": "클립보드로 내보내기",
|
||||||
|
"export": "라이브러리로 내보내기",
|
||||||
|
"exportAs": "내보내기",
|
||||||
|
"overwrite": "확인",
|
||||||
|
"exists": "<p><b>\"__file__\"</b> 이미 존재합니다.</p><p>교체하시겠습니까?</p>"
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"import": "가져올 위치 : ",
|
"import": "가져올 위치 : ",
|
||||||
|
"importSelected": "선택 항목 가져오기",
|
||||||
|
"importCopy": "사본 가져오기",
|
||||||
|
"viewNodes": "노드 보기...",
|
||||||
"newFlow": "새로운 플로우",
|
"newFlow": "새로운 플로우",
|
||||||
|
"replace": "교체",
|
||||||
"errors": {
|
"errors": {
|
||||||
"notArray": "입력이 JSON 배열이 아닙니다",
|
"notArray": "입력이 JSON 배열이 아닙니다",
|
||||||
"itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다",
|
"itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다",
|
||||||
"missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다",
|
"missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다",
|
||||||
"missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다"
|
"missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다"
|
||||||
}
|
},
|
||||||
|
"conflictNotification1": "가져오는 노드 중 일부가 이미 작업 공간에 있습니다..",
|
||||||
|
"conflictNotification2": "가져올 노드와 기존 노드를 바꿀지 아니면 복사본을 가져올지 선택합니다."
|
||||||
},
|
},
|
||||||
"copyMessagePath": "Path가 복사 되었습니다",
|
"copyMessagePath": "Path가 복사 되었습니다",
|
||||||
"copyMessageValue": "Value가 복사 되었습니다",
|
"copyMessageValue": "Value가 복사 되었습니다",
|
||||||
@ -198,6 +270,10 @@
|
|||||||
"modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다",
|
"modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다",
|
||||||
"modifiedNodes": "변경된 노드",
|
"modifiedNodes": "변경된 노드",
|
||||||
"modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다",
|
"modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다",
|
||||||
|
"startFlows": "시작",
|
||||||
|
"startFlowsDesc": "플로우를 시작합니다",
|
||||||
|
"stopFlows": "중지",
|
||||||
|
"stopFlowsDesc": "플로우를 중지합니다",
|
||||||
"restartFlows": "플로우 재시작",
|
"restartFlows": "플로우 재시작",
|
||||||
"restartFlowsDesc": "현재 배포된 플로우를 재시작합니다",
|
"restartFlowsDesc": "현재 배포된 플로우를 재시작합니다",
|
||||||
"successfulDeploy": "배포가 성공했습니다",
|
"successfulDeploy": "배포가 성공했습니다",
|
||||||
@ -266,6 +342,7 @@
|
|||||||
"newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :"
|
"newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :"
|
||||||
},
|
},
|
||||||
"subflow": {
|
"subflow": {
|
||||||
|
"editSubflowInstance": "서브 플로우 인스턴스 수정: __name__",
|
||||||
"editSubflow": "플로우 템플릿 수정 : __name__",
|
"editSubflow": "플로우 템플릿 수정 : __name__",
|
||||||
"edit": "플로우 템플릿 수정",
|
"edit": "플로우 템플릿 수정",
|
||||||
"subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다",
|
"subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다",
|
||||||
@ -273,14 +350,39 @@
|
|||||||
"editSubflowProperties": "속성 수정",
|
"editSubflowProperties": "속성 수정",
|
||||||
"input": "입력:",
|
"input": "입력:",
|
||||||
"output": "출력:",
|
"output": "출력:",
|
||||||
|
"status": "상태 노드",
|
||||||
"deleteSubflow": "서브 플로우 삭제",
|
"deleteSubflow": "서브 플로우 삭제",
|
||||||
|
"confirmDelete": "서브 플로우를 삭제하시겠습니까?",
|
||||||
"info": "상세내역",
|
"info": "상세내역",
|
||||||
"category": "카테고리",
|
"category": "카테고리",
|
||||||
|
"module": "모듈",
|
||||||
|
"license": "라이선스",
|
||||||
|
"licenseNone": "없음",
|
||||||
|
"licenseOther": "Other",
|
||||||
|
"type": "노드",
|
||||||
|
"version": "버전",
|
||||||
|
"versionPlaceholder": "x.y.z",
|
||||||
|
"keys": "키워드",
|
||||||
|
"keysPlaceholder": "키워드(쉼표로 구분)를 입력해주세요",
|
||||||
|
"author": "이름",
|
||||||
|
"authorPlaceholder": "이름 또는 이메일을 입력해주세요",
|
||||||
|
"desc": "설명",
|
||||||
|
"env": {
|
||||||
|
"restore": "서브 플로우 기본값으로 복원",
|
||||||
|
"remove": "환경 변수 제거"
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다",
|
"noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다",
|
||||||
"multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다"
|
"multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"group": {
|
||||||
|
"editGroup": "그룹 수정: __name__",
|
||||||
|
"errors": {
|
||||||
|
"cannotCreateDiffGroups": "다른 그룹의 노드를 사용하여 그룹을 생성할 수 없습니다",
|
||||||
|
"cannotAddSubflowPorts": "그룹에 서브 플로우 포트를 추가할 수 없습니다"
|
||||||
|
}
|
||||||
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"configEdit": "수정",
|
"configEdit": "수정",
|
||||||
"configAdd": "추가",
|
"configAdd": "추가",
|
||||||
@ -294,19 +396,20 @@
|
|||||||
"addNewType": "__type__의 노드타입 추가 ...",
|
"addNewType": "__type__의 노드타입 추가 ...",
|
||||||
"nodeProperties": "노드 속성",
|
"nodeProperties": "노드 속성",
|
||||||
"label": "명칭",
|
"label": "명칭",
|
||||||
|
"color": "Color",
|
||||||
"portLabels": "포트 설정",
|
"portLabels": "포트 설정",
|
||||||
"labelInputs": "입력",
|
"labelInputs": "입력",
|
||||||
"labelOutputs": "출력",
|
"labelOutputs": "출력",
|
||||||
"settingIcon": "아이콘",
|
"settingIcon": "아이콘",
|
||||||
|
"default": "default",
|
||||||
"noDefaultLabel": "없음",
|
"noDefaultLabel": "없음",
|
||||||
"defaultLabel": "기본 명칭",
|
"defaultLabel": "기본 명칭",
|
||||||
"searchIcons": "아이콘 조회",
|
"searchIcons": "아이콘 조회",
|
||||||
"useDefault": "기본설정 사용",
|
"useDefault": "기본설정 사용",
|
||||||
"description": "상세 내역",
|
"description": "상세 내역",
|
||||||
"show": "보이기",
|
|
||||||
"hide": "숨기기",
|
|
||||||
"errors": {
|
"errors": {
|
||||||
"scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다."
|
"scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다.",
|
||||||
|
"invalidProperties": "유효하지 않은 속성:"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keyboard": {
|
"keyboard": {
|
||||||
@ -319,10 +422,11 @@
|
|||||||
"global": "글로벌",
|
"global": "글로벌",
|
||||||
"workspace": "작업공간",
|
"workspace": "작업공간",
|
||||||
"selectAll": "모든 노드 선택",
|
"selectAll": "모든 노드 선택",
|
||||||
"selectAllConnected": "모든 연결된 노드 선택",
|
"selectNone": "노드 선택 취소",
|
||||||
|
"selectAllConnected": "연결된 모든 노드 선택",
|
||||||
"addRemoveNode": "노드 추가/삭제",
|
"addRemoveNode": "노드 추가/삭제",
|
||||||
"editSelected": "선택된 노드 수정",
|
"editSelected": "선택된 노드 수정",
|
||||||
"deleteSelected": "선택된 노드나 링크를 삭제",
|
"deleteSelected": "선택된 노드 또는 링크 삭제",
|
||||||
"importNode": "노드 불러오기",
|
"importNode": "노드 불러오기",
|
||||||
"exportNode": "노드 내보내기",
|
"exportNode": "노드 내보내기",
|
||||||
"nudgeNode": "선택된 노드 이동 (1px)",
|
"nudgeNode": "선택된 노드 이동 (1px)",
|
||||||
@ -332,9 +436,14 @@
|
|||||||
"copyNode": "선택된 노드 복사",
|
"copyNode": "선택된 노드 복사",
|
||||||
"cutNode": "선택된 노드 잘라내기",
|
"cutNode": "선택된 노드 잘라내기",
|
||||||
"pasteNode": "노드 붙여넣기",
|
"pasteNode": "노드 붙여넣기",
|
||||||
|
"copyGroupStyle": "그룹 스타일 복사하기",
|
||||||
|
"pasteGroupStyle": "그룹 스타일 붙여넣기",
|
||||||
"undoChange": "마지막 변경 되돌리기",
|
"undoChange": "마지막 변경 되돌리기",
|
||||||
|
"redoChange": "다시 실행하기",
|
||||||
"searchBox": "검색창 열기",
|
"searchBox": "검색창 열기",
|
||||||
"managePalette": "팔렛트 관리"
|
"managePalette": "팔렛트 관리",
|
||||||
|
"actionList": "액션 목록",
|
||||||
|
"splitWireWithLinks": "링크 노드로 선택 항목 분할"
|
||||||
},
|
},
|
||||||
"library": {
|
"library": {
|
||||||
"library": "라이브러리",
|
"library": "라이브러리",
|
||||||
@ -342,12 +451,15 @@
|
|||||||
"saveToLibrary": "라이브러리로 저장...",
|
"saveToLibrary": "라이브러리로 저장...",
|
||||||
"typeLibrary": "__type__ 라이브러리",
|
"typeLibrary": "__type__ 라이브러리",
|
||||||
"unnamedType": "이름없는 __type__",
|
"unnamedType": "이름없는 __type__",
|
||||||
|
"exportedToLibrary": "노드를 라이브러리로 내보냈습니다.",
|
||||||
"dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?",
|
"dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?",
|
||||||
"invalidFilename": "파일명이 올바르지 않습니다",
|
"invalidFilename": "파일명이 올바르지 않습니다",
|
||||||
"savedNodes": "저장된 노드",
|
"savedNodes": "저장된 노드",
|
||||||
"savedType": "저장된 __type__",
|
"savedType": "저장된 __type__",
|
||||||
"saveFailed": "저장 실패 : __message__",
|
"saveFailed": "저장 실패 : __message__",
|
||||||
|
"newFolder": "새로운 폴더",
|
||||||
"types": {
|
"types": {
|
||||||
|
"local": "로컬",
|
||||||
"examples": "예시"
|
"examples": "예시"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -358,9 +470,13 @@
|
|||||||
"addCategory": "추가 ...",
|
"addCategory": "추가 ...",
|
||||||
"label": {
|
"label": {
|
||||||
"subflows": "서브 플로우",
|
"subflows": "서브 플로우",
|
||||||
|
"network": "네트워크",
|
||||||
|
"common": "일반",
|
||||||
"input": "입력",
|
"input": "입력",
|
||||||
"output": "출력",
|
"output": "출력",
|
||||||
"function": "기능",
|
"function": "기능",
|
||||||
|
"sequence": "sequence",
|
||||||
|
"parser": "parser",
|
||||||
"social": "소셜",
|
"social": "소셜",
|
||||||
"storage": "저장",
|
"storage": "저장",
|
||||||
"analysis": "분석",
|
"analysis": "분석",
|
||||||
@ -379,7 +495,8 @@
|
|||||||
"nodeEnabled_plural": "노드가 활성화 되었습니다:",
|
"nodeEnabled_plural": "노드가 활성화 되었습니다:",
|
||||||
"nodeDisabled": "노드가 비활성화 되었습니다:",
|
"nodeDisabled": "노드가 비활성화 되었습니다:",
|
||||||
"nodeDisabled_plural": "노드가 비활성화 되었습니다:",
|
"nodeDisabled_plural": "노드가 비활성화 되었습니다:",
|
||||||
"nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다"
|
"nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다",
|
||||||
|
"unknownNodeRegistered": "Error loading node: <ul><li>__type__<br>__error__</li></ul>"
|
||||||
},
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"title": "팔렛트 관리",
|
"title": "팔렛트 관리",
|
||||||
@ -426,6 +543,8 @@
|
|||||||
"sortAZ": "a-z",
|
"sortAZ": "a-z",
|
||||||
"sortRecent": "최근",
|
"sortRecent": "최근",
|
||||||
"more": "+ __count__ 개 더 보기",
|
"more": "+ __count__ 개 더 보기",
|
||||||
|
"upload": "Upload module tgz file",
|
||||||
|
"refresh": "모듈 목록 새로 고침",
|
||||||
"errors": {
|
"errors": {
|
||||||
"catalogLoadFailed": "<p>노드 카탈로그를 설치하지 못했습니다.</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
"catalogLoadFailed": "<p>노드 카탈로그를 설치하지 못했습니다.</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||||
"installFailed": "<p>설치 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
"installFailed": "<p>설치 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||||
@ -466,6 +585,7 @@
|
|||||||
"label": "정보",
|
"label": "정보",
|
||||||
"node": "노드",
|
"node": "노드",
|
||||||
"type": "타입",
|
"type": "타입",
|
||||||
|
"group": "Group",
|
||||||
"module": "모듈",
|
"module": "모듈",
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"status": "상태",
|
"status": "상태",
|
||||||
@ -488,7 +608,23 @@
|
|||||||
"nodeHelp": "노드 도움말",
|
"nodeHelp": "노드 도움말",
|
||||||
"none": "없음",
|
"none": "없음",
|
||||||
"arrayItems": "__count__ 개의 항목",
|
"arrayItems": "__count__ 개의 항목",
|
||||||
"showTips": "설정에서 도움말을 열 수 있습니다. "
|
"showTips": "설정에서 도움말을 열 수 있습니다. ",
|
||||||
|
"outline": "개요",
|
||||||
|
"empty": "비우기",
|
||||||
|
"globalConfig": "전역 설정 노드",
|
||||||
|
"triggerAction": "트리거 작업",
|
||||||
|
"find": "작업 공간에서 찾기"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"name": "도움말",
|
||||||
|
"label": "도움말",
|
||||||
|
"search": "도움말 검색",
|
||||||
|
"nodeHelp": "노드 도움말 보기",
|
||||||
|
"showHelp": "도움말 보기",
|
||||||
|
"showInOutline": "요약 보기",
|
||||||
|
"showTopics": "토픽 보기",
|
||||||
|
"noHelp": "선택한 도움말 항목이 없습니다",
|
||||||
|
"changeLog": "릴리즈 정보"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"name": "노드 설정",
|
"name": "노드 설정",
|
||||||
@ -498,7 +634,9 @@
|
|||||||
"subflows": "보조 플로우",
|
"subflows": "보조 플로우",
|
||||||
"flows": "플로우",
|
"flows": "플로우",
|
||||||
"filterAll": "전체",
|
"filterAll": "전체",
|
||||||
|
"showAllConfigNodes": "모든 설정 노드 보기",
|
||||||
"filterUnused": "미사용",
|
"filterUnused": "미사용",
|
||||||
|
"showAllUnusedConfigNodes": "사용하지 않는 모든 설정 노드 보기",
|
||||||
"filtered": "__count__ 개 숨김"
|
"filtered": "__count__ 개 숨김"
|
||||||
},
|
},
|
||||||
"context": {
|
"context": {
|
||||||
@ -509,8 +647,11 @@
|
|||||||
"empty": "공백",
|
"empty": "공백",
|
||||||
"node": "노드",
|
"node": "노드",
|
||||||
"flow": "플로우",
|
"flow": "플로우",
|
||||||
"global": "Global",
|
"global": "글로벌",
|
||||||
"deleteConfirm": "정말로 이 아이템을 지우시겠습니까?"
|
"deleteConfirm": "정말로 이 아이템을 지우시겠습니까?",
|
||||||
|
"autoRefresh": "선택 변경 시 새로 고침",
|
||||||
|
"refrsh": "새로고침",
|
||||||
|
"delete": "삭제"
|
||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"name": "팔레트 관리",
|
"name": "팔레트 관리",
|
||||||
@ -525,6 +666,7 @@
|
|||||||
"noSummaryAvailable": "요약 없음",
|
"noSummaryAvailable": "요약 없음",
|
||||||
"editDescription": "프로젝트 상세내역 수정",
|
"editDescription": "프로젝트 상세내역 수정",
|
||||||
"editDependencies": "프로젝트 의존성 수정",
|
"editDependencies": "프로젝트 의존성 수정",
|
||||||
|
"noDescriptionAvailable": "설명 없음",
|
||||||
"editReadme": "README.md 수정",
|
"editReadme": "README.md 수정",
|
||||||
"showProjectSettings": "프로젝트 설정 보이기",
|
"showProjectSettings": "프로젝트 설정 보이기",
|
||||||
"projectSettings": {
|
"projectSettings": {
|
||||||
@ -537,6 +679,10 @@
|
|||||||
"files": "파일",
|
"files": "파일",
|
||||||
"flow": "플로우",
|
"flow": "플로우",
|
||||||
"credentials": "인증정보",
|
"credentials": "인증정보",
|
||||||
|
"package": "Package",
|
||||||
|
"packageCreate": "변경 내용이 저장될 때 파일이 생성됩니다",
|
||||||
|
"fileNotExist": "파일이 존재하지 않습니다",
|
||||||
|
"selectFile": "파일 선택",
|
||||||
"invalidEncryptionKey": "잘못된 암호화 키",
|
"invalidEncryptionKey": "잘못된 암호화 키",
|
||||||
"encryptionEnabled": "암호화 활성화",
|
"encryptionEnabled": "암호화 활성화",
|
||||||
"encryptionDisabled": "암호화 비활성화",
|
"encryptionDisabled": "암호화 비활성화",
|
||||||
@ -674,15 +820,29 @@
|
|||||||
"bin": "buffer",
|
"bin": "buffer",
|
||||||
"date": "timestamp",
|
"date": "timestamp",
|
||||||
"jsonata": "expression",
|
"jsonata": "expression",
|
||||||
"env": "env variable"
|
"env": "env variable",
|
||||||
|
"cred": "credential"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"editableList": {
|
"editableList": {
|
||||||
"add": "추가"
|
"add": "추가",
|
||||||
|
"addTitle": "add an item"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
|
"history": "Search history",
|
||||||
|
"clear": "clear all",
|
||||||
"empty": "결과 없음",
|
"empty": "결과 없음",
|
||||||
"addNode": "노드 추가 ..."
|
"addNode": "노드 추가 ...",
|
||||||
|
"options": {
|
||||||
|
"configNodes": "설정 노드",
|
||||||
|
"unusedConfigNodes": "사용되지 않는 설정 노드",
|
||||||
|
"invalidNodes": "잘못된 노드",
|
||||||
|
"uknownNodes": "알 수 없는 노드",
|
||||||
|
"unusedSubflows": "사용되지 않는 서브 플로우",
|
||||||
|
"hiddenFlows": "숨겨진 플로우",
|
||||||
|
"modifiedNodes": "수정된 노드 및 플로우",
|
||||||
|
"thisFlow": "현재 플로우"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"expressionEditor": {
|
"expressionEditor": {
|
||||||
"functions": "기능",
|
"functions": "기능",
|
||||||
@ -703,15 +863,36 @@
|
|||||||
"eval": "형식 오류 :\n __message__"
|
"eval": "형식 오류 :\n __message__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"monaco": {
|
||||||
|
"setTheme": "테마 설정"
|
||||||
|
},
|
||||||
"jsEditor": {
|
"jsEditor": {
|
||||||
"title": "자바스크립트 에디터"
|
"title": "자바스크립트 에디터"
|
||||||
},
|
},
|
||||||
|
"textEditor": {
|
||||||
|
"title": "텍스트 에디터"
|
||||||
|
},
|
||||||
"jsonEditor": {
|
"jsonEditor": {
|
||||||
"title": "JSON 에디터",
|
"title": "JSON 에디터",
|
||||||
"format": "JSON 형식"
|
"format": "JSON 형식",
|
||||||
|
"rawMode": "JSON 수정",
|
||||||
|
"uiMode": "비주얼 편집기",
|
||||||
|
"rawMode-readonly": "JSON",
|
||||||
|
"uiMode-readonly": "비주얼",
|
||||||
|
"insertAbove": "위로 삽입",
|
||||||
|
"insertBelow": "아래로 삽입",
|
||||||
|
"addItem": "속성 추가",
|
||||||
|
"copyPath": "속성의 키값 복사",
|
||||||
|
"expandItems": "속성 펼치기",
|
||||||
|
"collapseItems": "속성 접기",
|
||||||
|
"duplicate": "복사",
|
||||||
|
"error": {
|
||||||
|
"invalidJSON": "비유효한 JSON: "
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"markdownEditor": {
|
"markdownEditor": {
|
||||||
"title": "Markdown 에디터",
|
"title": "Markdown 에디터",
|
||||||
|
"expand": "Expand",
|
||||||
"format": "Markdown 형식",
|
"format": "Markdown 형식",
|
||||||
"heading1": "제목 레벨1",
|
"heading1": "제목 레벨1",
|
||||||
"heading2": "제목 레벨2",
|
"heading2": "제목 레벨2",
|
||||||
@ -741,6 +922,7 @@
|
|||||||
"desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.",
|
"desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.",
|
||||||
"create": "프로젝트 생성",
|
"create": "프로젝트 생성",
|
||||||
"clone": "프로젝트 복제",
|
"clone": "프로젝트 복제",
|
||||||
|
"openExistingProject": "기존 프로젝트 열기",
|
||||||
"not-right-now": "나중에"
|
"not-right-now": "나중에"
|
||||||
},
|
},
|
||||||
"git-config": {
|
"git-config": {
|
||||||
@ -858,7 +1040,8 @@
|
|||||||
"not-git": "git 저장소가 아닙니다",
|
"not-git": "git 저장소가 아닙니다",
|
||||||
"no-resource": "저장소아 없습니다",
|
"no-resource": "저장소아 없습니다",
|
||||||
"cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.",
|
"cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.",
|
||||||
"unexpected_error": "예기치 않은 에러"
|
"unexpected_error": "예기치 않은 에러",
|
||||||
|
"clearContext": "프로젝트 전환 시 context 삭제"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"confirm": "프로젝트를 정말 지우시겠습니까?"
|
"confirm": "프로젝트를 정말 지우시겠습니까?"
|
||||||
@ -897,7 +1080,26 @@
|
|||||||
},
|
},
|
||||||
"editor-tab": {
|
"editor-tab": {
|
||||||
"properties": "속성",
|
"properties": "속성",
|
||||||
|
"envProperties": "환경 변수",
|
||||||
|
"module": "모듈 속성",
|
||||||
"description": "상세 내역",
|
"description": "상세 내역",
|
||||||
"appearance": "모양"
|
"appearance": "모양",
|
||||||
|
"preview": "UI 프리뷰",
|
||||||
|
"defaultValue": "기본값"
|
||||||
|
},
|
||||||
|
"tourGuide": {
|
||||||
|
"takeATour": "둘러보기",
|
||||||
|
"start": "시작",
|
||||||
|
"next": "다음",
|
||||||
|
"welcomeTours": "버전 별 릴리즈 정보"
|
||||||
|
},
|
||||||
|
"diagnostics": {
|
||||||
|
"title": "시스템 정보"
|
||||||
|
},
|
||||||
|
"contextMenu": {
|
||||||
|
"insert": "삽입",
|
||||||
|
"node": "노드",
|
||||||
|
"junction": "접합",
|
||||||
|
"linkNodes": "링크 노드"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@
|
|||||||
},
|
},
|
||||||
"$sort": {
|
"$sort": {
|
||||||
"args": "array [, function]",
|
"args": "array [, function]",
|
||||||
"desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다. \n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다. \n\n `function(left,right)` \n\n 비교함수는 left와 right의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 right값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 ``true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다."
|
"desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다.\n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다.\n\n `function(left,right)`\n\n 비교함수는 `left`와 `right`의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 `right`값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 `true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다."
|
||||||
},
|
},
|
||||||
"$reverse": {
|
"$reverse": {
|
||||||
"args": "array",
|
"args": "array",
|
||||||
@ -205,7 +205,7 @@
|
|||||||
},
|
},
|
||||||
"$formatNumber": {
|
"$formatNumber": {
|
||||||
"args": "number, picture [, options]",
|
"args": "number, picture [, options]",
|
||||||
"desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다. \n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 fn:format-number의 동작과 같습니다. 인수의 문자열 picture은 fn:format-number 과 같은 구문으로 수치의 서식을 정의합니다. \n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다."
|
"desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다.\n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 `fn:format-number`의 동작과 같습니다. 인수의 문자열 `picture`은 `fn:format-number` 과 같은 구문으로 수치의 서식을 정의합니다.\n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다."
|
||||||
},
|
},
|
||||||
"$formatBase": {
|
"$formatBase": {
|
||||||
"args": "number [, radix]",
|
"args": "number [, radix]",
|
||||||
|
1208
packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json
vendored
Normal file
23
packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"tip0": "Você pode remover os nós ou links selecionados com {{core:delete-selection}}",
|
||||||
|
"tip1": "Procure por nós usando {{core:search}}",
|
||||||
|
"tip2": "{{core:toggle-sidebar}} irá alternar a visualização desta barra lateral",
|
||||||
|
"tip3": "Você pode gerenciar sua paleta de nós com {{core:manage-palette}}",
|
||||||
|
"tip4": "Seus nós de configuração de fluxo são listados no painel da barra lateral. Pode ser acessado a partir do menu ou com{{core:show-config-tab}}",
|
||||||
|
"tip5": "Habilite ou desabilite essas dicas na opção nas configurações",
|
||||||
|
"tip6": "Mova os nós selecionados usando o [left] [up] [down] e [right] chaves. Segure [shift] para empurrá-los ainda mais",
|
||||||
|
"tip7": "Arrastar um nó para um fio o unirá no link",
|
||||||
|
"tip8": "Exporte os nós selecionados ou a guia atual com {{core:show-export-dialog}}",
|
||||||
|
"tip9": "Importe um fluxo arrastando seu JSON para o editor ou com {{core:show-import-dialog}}",
|
||||||
|
"tip10": "[shift] [click] e arraste em uma porta de nó para mover todos os fios conectados ou apenas o selecionado",
|
||||||
|
"tip11": "Mostre a guia Informações com {{core:show-info-tab}} ou a guia Depurar com {{core:show-debug-tab}}",
|
||||||
|
"tip12": "[ctrl] [click] na área de trabalho para abrir a caixa de diálogo de adição rápida",
|
||||||
|
"tip13": "Mantenha pressionado [ctrl] enquanto você [click] em uma porta de nó para habilitar a ligação rápida",
|
||||||
|
"tip14": "Mantenha pressionado [shift] enquanto você [click] em um nó para também selecionar todos os seus nós conectados",
|
||||||
|
"tip15": "Mantenha pressionado [ctrl] enquanto você [click] em um nó para adicioná-lo ou removê-lo da seleção atual",
|
||||||
|
"tip16": "Alternar guias de fluxo com {{core:show-previous-tab}} e {{core:show-next-tab}}",
|
||||||
|
"tip17": "Você pode confirmar suas alterações na bandeja de edição do nó com {{core:confirm-edit-tray}} ou cancele-os com {{core:cancel-edit-tray}}",
|
||||||
|
"tip18": "Pressionando {{core:edit-selected-node}} irá editar o primeiro nó na seleção atual"
|
||||||
|
}
|
||||||
|
}
|
274
packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json
vendored
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
{
|
||||||
|
"$string": {
|
||||||
|
"args": "arg[, prettify]",
|
||||||
|
"desc": "Converte o tipo do parâmetro `arg` em uma cadeia de caracteres usando as seguintes regras de conversão de tipo:\n\n - Cadeia de caracteres não são alteradas\n - As funções são convertidas para uma cadeia de caracteres vazia\n - os tipos numérico infinito e NaN geram um erro porque não podem ser representados como um número JSON\n - Todos os outros valores são convertidos para uma cadeia de caracteres JSON usando a função `JSON.stringify`. Se `prettify` for verdadeira, então o JSON \"prettified\" é produzido. Isto é, uma linha por campo e as linhas serão indentadas com base na profundidade do campo."
|
||||||
|
},
|
||||||
|
"$length": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Retorna o número de caracteres na cadeia de caracteres `str`. Um erro é gerado se `str` não for uma cadeia de caracteres."
|
||||||
|
},
|
||||||
|
"$substring": {
|
||||||
|
"args": "str, start[, length]",
|
||||||
|
"desc": "Retorna uma cadeia de caracteres contendo os caracteres no primeiro parâmetro `str` começando na posição `start` (deslocamento zero). Se` length` for especificado, então a sub cadeia de caracteres conterá o máximo `length` de caracteres. Se` start` for negativo isso indica o número de caracteres a partir do fim de `str`."
|
||||||
|
},
|
||||||
|
"$substringBefore": {
|
||||||
|
"args": "str, chars",
|
||||||
|
"desc": "Retorna a sub cadeia de caracteres antes da primeira ocorrência da sequência de caracteres `chars` em `string`. Se` string` não contiver `chars`, então retorna `str`."
|
||||||
|
},
|
||||||
|
"$substringAfter": {
|
||||||
|
"args": "str, chars",
|
||||||
|
"desc": "Retorna a sub cadeia de caracteres após a primeira ocorrência da sequência de caracteres `chars` em `string`. Se `string` não contiver `chars`, então retorna `str`."
|
||||||
|
},
|
||||||
|
"$uppercase": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em maiúsculas."
|
||||||
|
},
|
||||||
|
"$lowercase": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em minúsculas."
|
||||||
|
},
|
||||||
|
"$trim": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Normaliza e retira todos os caracteres de espaço em branco em `str` aplicando as seguintes etapas:\n\n - Todas as tabulações, retornos de carro e avanços de linha são substituídos por espaços.\n- Sequências contíguas de espaços são reduzidas a um único espaço.\n- Espaços à direita e à esquerda são removidos.\n\n Se `str` não for especificado (isto é, esta função é chamada sem argumentos), então o valor do contexto é usado como o valor de `str`. Um erro é gerado se `str` não for uma cadeia de caracteres."
|
||||||
|
},
|
||||||
|
"$contains": {
|
||||||
|
"args": "str, pattern",
|
||||||
|
"desc": "Retorna `true` se `str` tiver correspondente em `pattern`, caso contrário, retorna `false`. Se `str` não for especificado (isto é, esta função é chamada com um argumento), então o valor do contexto é usado como o valor de `str`. O parâmetro `pattern` pode ser uma cadeia de caracteres ou uma expressão regular."
|
||||||
|
},
|
||||||
|
"$split": {
|
||||||
|
"args": "str[, separator][, limit]",
|
||||||
|
"desc": "Divide o parâmetro `str` em uma matriz de sub cadeia de caracteres. É um erro se `str` não for uma cadeia de caracteres. O parâmetro opcional `separator` especifica os caracteres dentro de `str` sobre os quais devem ser divididos como uma cadeia de caracteres ou expressão regular. Se `separator` não for especificado, a cadeia de caracteres vazia será assumida e `str` será dividido em uma matriz de caracteres únicos. É um erro se `separador` não for uma cadeia de caracteres. O parâmetro opcional `limit` é um número que especifica o número máximo de sub cadeia de caracteres a serem incluídas na matriz resultante. Quaisquer sub cadeia de caracteres adicionais são descartadas. Se `limit` não for especificado, então `str` será totalmente dividido sem limite para o tamanho da matriz resultante . É um erro se `limit` não for um número não negativo."
|
||||||
|
},
|
||||||
|
"$join": {
|
||||||
|
"args": "array[, separator]",
|
||||||
|
"desc": "Une uma matriz de cadeias de caracteres de componentes em uma única cadeia de caracteres concatenada com cada cadeia de caracteres de componente separada pelo parâmetro opcional `separator`. É um erro se a `matriz` de entrada contiver um item que não seja uma cadeia de caracteres. Se `separator` for não especificado, assume-se que é uma cadeia de caracteres vazia, ou seja, nenhum `separator` entre as cadeias de caracteres do componente. É um erro se `separator` não for uma cadeia de caracteres."
|
||||||
|
},
|
||||||
|
"$match": {
|
||||||
|
"args": "str, pattern [, limit]",
|
||||||
|
"desc": "Aplica a cadeia de caracteres `str` à expressão regular `pattern` e retorna uma matriz de objetos, com cada objeto contendo informações sobre cada ocorrência de uma correspondência dentro de `str`."
|
||||||
|
},
|
||||||
|
"$replace": {
|
||||||
|
"args": "str, pattern, replacement [, limit]",
|
||||||
|
"desc": "Encontra ocorrências de `pattern` dentro de `str` e as substitui por `replacement`.\n\nO parâmetro opcional `limit` é o número máximo de substituições."
|
||||||
|
},
|
||||||
|
"$now": {
|
||||||
|
"args": "$[picture [, timezone]]",
|
||||||
|
"desc": "Gera um carimbo de data/hora em formato compatível com ISO 8601 e o retorna como uma cadeia de caracteres. Se os parâmetros opcionais de imagem e fuso horário forem fornecidos, o carimbo de data/hora atual é formatado conforme descrito pela função `$fromMillis()`"
|
||||||
|
},
|
||||||
|
"$base64encode": {
|
||||||
|
"args": "string",
|
||||||
|
"desc": "Converte uma cadeia de caracteres ASCII em uma representação de base 64. Cada caractere na cadeia de caracteres é tratado como um byte de dados binários. Isso requer que todos os caracteres na cadeia de caracteres estejam no intervalo de 0x00 a 0xFF, o que inclui todos os caracteres em cadeias de caracteres codificadas em URI. Caracteres Unicode fora desse intervalo não são suportados."
|
||||||
|
},
|
||||||
|
"$base64decode": {
|
||||||
|
"args": "string",
|
||||||
|
"desc": "Converte bytes codificados de base 64 em uma cadeia de caracteres, usando uma página de código UTF-8 Unicode."
|
||||||
|
},
|
||||||
|
"$number": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Converte o parâmetro `arg` em um número usando as seguintes regras de conversão:\n\n - Os números permanecem inalterados\n - Cadeias de caracteres que contêm uma sequência de caracteres que representam um número JSON válido são convertidos para esse número\n - Todos os outros valores causam a geração de um erro."
|
||||||
|
},
|
||||||
|
"$abs": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Retorna o valor absoluto do parâmetro `number`."
|
||||||
|
},
|
||||||
|
"$floor": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Retorna o valor de `number` arredondado para baixo para o inteiro mais próximo que seja menor ou igual a `number`."
|
||||||
|
},
|
||||||
|
"$ceil": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Retorna o valor de `number` arredondado para o número inteiro mais próximo que é maior ou igual a `number`."
|
||||||
|
},
|
||||||
|
"$round": {
|
||||||
|
"args": "number [, precision]",
|
||||||
|
"desc": "Retorna o valor do parâmetro `number` arredondado para o número de casas decimais especificado pelo parâmetro opcional `precision`."
|
||||||
|
},
|
||||||
|
"$power": {
|
||||||
|
"args": "base, exponent",
|
||||||
|
"desc": "Retorna o valor de `base` elevado à potência de `exponent`."
|
||||||
|
},
|
||||||
|
"$sqrt": {
|
||||||
|
"args": "number",
|
||||||
|
"desc": "Retorna a raiz quadrada do valor do parâmetro `number`."
|
||||||
|
},
|
||||||
|
"$random": {
|
||||||
|
"args": "",
|
||||||
|
"desc": "Retorna um número pseudoaleatório maior ou igual a zero e menor que um."
|
||||||
|
},
|
||||||
|
"$millis": {
|
||||||
|
"args": "",
|
||||||
|
"desc": "Retorna o número de milissegundos desde o Unix Epoch (1º de janeiro de 1970 UTC) como um número. Todas as invocações de `$millis()` dentro de uma avaliação de uma expressão retornarão todas o mesmo valor."
|
||||||
|
},
|
||||||
|
"$sum": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna a soma aritmética de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
|
||||||
|
},
|
||||||
|
"$max": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna o número máximo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
|
||||||
|
},
|
||||||
|
"$min": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna o número mínimo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
|
||||||
|
},
|
||||||
|
"$average": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna o valor médio de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número."
|
||||||
|
},
|
||||||
|
"$boolean": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Converte o argumento em um booliano usando as seguintes regras:\n\n - `Boolean` : inalterado\n - `string`: vazio : `false`\n - `string`: não-vazio : `true`\n - `number`: `0` : `false`\n - `number`: não-zero : `true`\n - `null` : `false`\n - `array`: vazio : `false`\n - `array`: contém um membro que converte de tipo para `true` : `true`\n - `array`: todos os membros convertidos de tipo para `false` : `false`\n - `object`: vazio : `false`\n - `object`: não-vazio : `true`\n - `function` : `false`"
|
||||||
|
},
|
||||||
|
"$not": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Retorna booliano NOT no argumento. `Arg` é convertido de tipo primeiro para um booliano"
|
||||||
|
},
|
||||||
|
"$exists": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Retorna booliano `true` se a expressão `arg` for avaliada como um valor, ou `false` se a expressão não corresponder a nada (por exemplo, um caminho para uma referência de campo inexistente)."
|
||||||
|
},
|
||||||
|
"$count": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna o número de itens na matriz"
|
||||||
|
},
|
||||||
|
"$append": {
|
||||||
|
"args": "array, array",
|
||||||
|
"desc": "Anexa duas matrizes"
|
||||||
|
},
|
||||||
|
"$sort": {
|
||||||
|
"args": "array [, function]",
|
||||||
|
"desc": "Retorna uma matriz contendo todos os valores no parâmetro `array`, mas classificados em ordem.\n\nSe um comparador `function` for fornecido, então deve ser uma função que leva dois parâmetros:\n\n`function(left, right)`\n\nEsta função é invocada pelo algoritmo de classificação para comparar dois valores à esquerda e à direita. Se o valor de esquerda deve ser colocado após o valor de direita na ordem de classificação desejada, a função deve retornar o booliano `true` para indicar uma troca. Caso contrário, deve retornar `false`."
|
||||||
|
},
|
||||||
|
"$reverse": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna uma matriz contendo todos os valores do parâmetro `array`, mas na ordem reversa."
|
||||||
|
},
|
||||||
|
"$shuffle": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna uma matriz contendo todos os valores do parâmetro `array`, mas misturados em ordem aleatória."
|
||||||
|
},
|
||||||
|
"$zip": {
|
||||||
|
"args": "array, ...",
|
||||||
|
"desc": "Retorna uma matriz convolucional (compactada) contendo matrizes agrupadas de valores dos argumentos `array1`… `arrayN` do índice 0, 1, 2 ...."
|
||||||
|
},
|
||||||
|
"$keys": {
|
||||||
|
"args": "object",
|
||||||
|
"desc": "Retorna uma matriz contendo as chaves do objeto. Se o argumento for uma matriz de objetos, então a matriz retornada contém uma lista não duplicada de todas as chaves em todos os objetos."
|
||||||
|
},
|
||||||
|
"$lookup": {
|
||||||
|
"args": "object, key",
|
||||||
|
"desc": "Retorna o valor associado à chave no objeto. Se o primeiro argumento for uma matriz de objetos, todos os objetos na matriz são pesquisados e os valores associados a todas as ocorrências da chave são retornados."
|
||||||
|
},
|
||||||
|
"$spread": {
|
||||||
|
"args": "object",
|
||||||
|
"desc": "Divide um objeto que contém pares de chave/valor em uma matriz de objetos, cada um com um único par de chave/valor do objeto de entrada. Se o parâmetro for uma matriz de objetos, a matriz resultante conterá um objeto para cada par de chave/valor em todo objeto na matriz fornecida."
|
||||||
|
},
|
||||||
|
"$merge": {
|
||||||
|
"args": "array<object>",
|
||||||
|
"desc": "Mescla uma matriz de `objects` em um único `object` contendo todos os pares de chave/valor de cada um dos objetos na matriz de entrada. Se qualquer um dos objetos de entrada contiver a mesma chave, então o `object` retornado conterá o valor do último na matriz. É um erro se a matriz de entrada contiver um item que não seja um objeto."
|
||||||
|
},
|
||||||
|
"$sift": {
|
||||||
|
"args": "object, function",
|
||||||
|
"desc": "Retorna um objeto que contém apenas os pares de chave/valor do parâmetro `object` que satisfazem o predicado `function` passado como o segundo parâmetro.\n\nA `function` que é fornecida como o segundo parâmetro deve ter o seguinte assinatura:\n\n`function(value [, key [, object]])`"
|
||||||
|
},
|
||||||
|
"$each": {
|
||||||
|
"args": "object, function",
|
||||||
|
"desc": "Retorna uma matriz contendo os valores retornados por `function` quando aplicado a cada par chave/valor no `object`."
|
||||||
|
},
|
||||||
|
"$map": {
|
||||||
|
"args": "array, function",
|
||||||
|
"desc": "Retorna uma matriz contendo os resultados da aplicação do parâmetro `function` a cada valor no parâmetro `array`.\n\nA `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`"
|
||||||
|
},
|
||||||
|
"$filter": {
|
||||||
|
"args": "array, function",
|
||||||
|
"desc": "Retorna uma matriz contendo apenas os valores no parâmetro `array` que satisfazem o predicado `function`.\n\nThe `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`"
|
||||||
|
},
|
||||||
|
"$reduce": {
|
||||||
|
"args": "array, function [, init]",
|
||||||
|
"desc": "Retorna um valor agregado derivado da aplicação do parâmetro `function` sucessivamente a cada valor em `array` em combinação com o resultado da aplicação anterior da função.\n\nA função deve aceitar dois argumentos e se comportar como um operador inserido entre cada valor dentro de `array`. A assinatura da `function` deve estar no formato: `myfunc($accumulator, $value[, $index[, $array]])`\n\nO parâmetro opcional `init` é usado como o valor inicial na agregação."
|
||||||
|
},
|
||||||
|
"$flowContext": {
|
||||||
|
"args": "string[, string]",
|
||||||
|
"desc": "Recupera uma propriedade de contexto de fluxo.\n\nEsta é uma função definida pelo Node-RED."
|
||||||
|
},
|
||||||
|
"$globalContext": {
|
||||||
|
"args": "string[, string]",
|
||||||
|
"desc": "Recupera uma propriedade de contexto global.\n\nEsta é uma função definida pelo Node-RED."
|
||||||
|
},
|
||||||
|
"$pad": {
|
||||||
|
"args": "string, width [, char]",
|
||||||
|
"desc": "Retorna uma cópia da `string` com preenchimento extra, se necessário, de forma que seu número total de caracteres seja pelo menos o valor absoluto do parâmetro `width`.\n\nSe `width` for um número positivo, a cadeia de caracteres será preenchida à direita; se negativo, é preenchida à esquerda.\n\nO argumento opcional `char` especifica os caracteres de preenchimento a serem usados. Se não for especificado, o padrão é o caractere de espaço."
|
||||||
|
},
|
||||||
|
"$fromMillis": {
|
||||||
|
"args": "number, [, picture [, timezone]]",
|
||||||
|
"desc": "Converta o `number` que representa os milissegundos desde a época do Unix (1 January, 1970 UTC) em uma representação de cadeia de caracteres formatada do carimbo de data/hora conforme especificado pela cadeia de caracteres de imagem.\n\nSe o parâmetro opcional `image` for omitido, o carimbo de data/hora será formatado no formato ISO 8601.\n\nSe a cadeia de caracteresopcional `picture` for fornecida, o carimbo de data/hora é formatado de acordo com a representação especificada nessa cadeia de caracteres. O comportamento desta função é consistente com a versão de dois argumentos da função XPath/XQuery `format-dateTime` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o carimbo de data/hora é formatado e tem a mesma sintaxe de `format-dateTime`.\n\nSe a cadeia de caracteres opcional `timezone` for fornecida, o carimbo de data/hora formatado estará nesse fuso horário. A cadeia de caracteres `timezone` deve estar no formato '± HHMM', onde ± é o sinal de mais ou menos e HHMM é o deslocamento em horas e minutos do UTC. Deslocamento positivo para fusos horários a leste do UTC, deslocamento negativo para fusos horários a oeste do UTC."
|
||||||
|
},
|
||||||
|
"$formatNumber": {
|
||||||
|
"args": "number, picture [, options]",
|
||||||
|
"desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação decimal conforme especificado pela cadeia de caracteres `picture`.\n\n O comportamento desta função é consistente com a função XPath/XQuery `fn:format-number` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn:format-number`.\n\nO terceiro argumento opcional `options` é usado para substituir os caracteres de formatação específicos da localidade padrão, como o separador decimal. Se fornecido, este argumento deve ser um objeto contendo pares de nome/valor especificados na seção de formato decimal da especificação XPath F&O 3.1."
|
||||||
|
},
|
||||||
|
"$formatBase": {
|
||||||
|
"args": "number [, radix]",
|
||||||
|
"desc": "Converte o `number` em uma cadeia de caracteres e o formata em um inteiro representado na base do número especificada pelo argumento `radix`. Se `radix` não for especificado, o padrão é a base 10. `radix` pode estar entre 2 e 36, caso contrário, um erro será gerado."
|
||||||
|
},
|
||||||
|
"$toMillis": {
|
||||||
|
"args": "timestamp",
|
||||||
|
"desc": "Converta o tipo de uma cadeia de caracteres `timestamp` no formato ISO 8601 para o número de milissegundos desde a época do Unix (1 January, 1970 UTC) como um número. Um erro é gerado se a cadeia de caracteres não estiver no formato correto."
|
||||||
|
},
|
||||||
|
"$env": {
|
||||||
|
"args": "arg",
|
||||||
|
"desc": "Retorna o valor de uma variável de ambiente.\n\nEsta é uma função definida pelo Node-RED."
|
||||||
|
},
|
||||||
|
"$eval": {
|
||||||
|
"args": "expr [, context]",
|
||||||
|
"desc": "Analisa e avalia a cadeia de caracteres `expr` que contém um JSON literal ou uma expressão JSONata usando o contexto atual como o contexto para avaliação."
|
||||||
|
},
|
||||||
|
"$formatInteger": {
|
||||||
|
"args": "number, picture",
|
||||||
|
"desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação inteira conforme especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn:format-integer` do Especificação XPath F&O 3.1."
|
||||||
|
},
|
||||||
|
"$parseInteger": {
|
||||||
|
"args": "string, picture",
|
||||||
|
"desc": "Examina e troca o conteúdo do parâmetro `string` para um inteiro (como um número JSON) usando o formato especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres `picture` tem o mesmo formato que `$formatInteger`."
|
||||||
|
},
|
||||||
|
"$error": {
|
||||||
|
"args": "[str]",
|
||||||
|
"desc": "Gera um erro com uma mensagem. O (parâmetro) opcional `str` substituirá a mensagem padrão de `$error() function evaluated`"
|
||||||
|
},
|
||||||
|
"$assert": {
|
||||||
|
"args": "arg, str",
|
||||||
|
"desc": "Se `arg` for verdadeiro, a função retorna indefinido. Se `arg` for falso, uma exceção é gerada com `str` como a mensagem da exceção."
|
||||||
|
},
|
||||||
|
"$single": {
|
||||||
|
"args": "array, function",
|
||||||
|
"desc": "Retorna o único valor no parâmetro `array` que satisfaz o predicado `function` (isto é, O (parâmetro) `function` retorna o booliano `true` quando passado o valor). Gera uma exceção se o número de valores correspondentes não for exatamente um .\n\nA função deve ser fornecida na seguinte assinatura: `function(value [, index [, array]])` onde 'value' é cada entrada da matriz, 'index' é a posição desse valor e toda a matriz é passada como o terceiro argumento"
|
||||||
|
},
|
||||||
|
"$encodeUrlComponent": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Codifica um componente Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere.\n\nExemplo: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
|
||||||
|
},
|
||||||
|
"$encodeUrl": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Codifica um Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere.\n\nExemplo: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
|
||||||
|
},
|
||||||
|
"$decodeUrlComponent": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Decodifica um componente Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrlComponent.\n\nExemplo: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
|
||||||
|
},
|
||||||
|
"$decodeUrl": {
|
||||||
|
"args": "str",
|
||||||
|
"desc": "Decodifica um Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrl.\n\nExemplo: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
|
||||||
|
},
|
||||||
|
"$distinct": {
|
||||||
|
"args": "array",
|
||||||
|
"desc": "Retorna uma matriz com valores duplicados removidos da `array`"
|
||||||
|
},
|
||||||
|
"$type": {
|
||||||
|
"args": "value",
|
||||||
|
"desc": "Retorna o tipo de `value` como uma cadeia de caracteres. Se `value` for indefinido, retornará `undefined`"
|
||||||
|
},
|
||||||
|
"$moment": {
|
||||||
|
"args": "[str]",
|
||||||
|
"desc": "Obtém um objeto de dados usando a biblioteca 'Moment'."
|
||||||
|
}
|
||||||
|
}
|
@ -1133,8 +1133,10 @@
|
|||||||
"languages" : {
|
"languages" : {
|
||||||
"de": "Немецкий",
|
"de": "Немецкий",
|
||||||
"en-US": "Английский",
|
"en-US": "Английский",
|
||||||
|
"fr": "Французский",
|
||||||
"ja": "Японский",
|
"ja": "Японский",
|
||||||
"ko": "Корейский",
|
"ko": "Корейский",
|
||||||
|
"pt-BR":"португальский",
|
||||||
"ru": "Русский",
|
"ru": "Русский",
|
||||||
"zh-CN": "Китайский (упрощенный)",
|
"zh-CN": "Китайский (упрощенный)",
|
||||||
"zh-TW": "Китайский (традиционный)"
|
"zh-TW": "Китайский (традиционный)"
|
||||||
|
@ -237,7 +237,7 @@
|
|||||||
},
|
},
|
||||||
"$assert": {
|
"$assert": {
|
||||||
"args": "arg, str",
|
"args": "arg, str",
|
||||||
"desc": "Если значение `arg` равно true, функция возвращает значение undefined. Если значение `arg` равно false, генерируется исключение с `str` в качестве сообщения об исключении."
|
"desc": "Если значение `arg` равно `true`, функция возвращает значение undefined. Если значение `arg` равно `false`, генерируется исключение с `str` в качестве сообщения об исключении."
|
||||||
},
|
},
|
||||||
"$single": {
|
"$single": {
|
||||||
"args": "array, function",
|
"args": "array, function",
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"next": "下一个",
|
"next": "下一个",
|
||||||
"clone": "克隆项目",
|
"clone": "克隆项目",
|
||||||
"cont": "继续",
|
"cont": "继续",
|
||||||
"style": "风格",
|
"style": "样式",
|
||||||
"line": "大纲",
|
"line": "大纲",
|
||||||
"fill": "填充",
|
"fill": "填充",
|
||||||
"label": "标签",
|
"label": "标签",
|
||||||
@ -54,16 +54,16 @@
|
|||||||
"delete": "你确定要删除 __label__ ?",
|
"delete": "你确定要删除 __label__ ?",
|
||||||
"dropFlowHere": "把流程放到这里",
|
"dropFlowHere": "把流程放到这里",
|
||||||
"addFlow": "添加流程",
|
"addFlow": "添加流程",
|
||||||
"addFlowToRight": "右侧添加流程",
|
"addFlowToRight": "在右侧新增流程",
|
||||||
"hideFlow": "隐藏流程",
|
"hideFlow": "隐藏流程",
|
||||||
"hideOtherFlows": "隐藏其他流程",
|
"hideOtherFlows": "隐藏其它流程",
|
||||||
"showAllFlows": "显示所有流程",
|
"showAllFlows": "显示所有流程",
|
||||||
"hideAllFlows": "隐藏所有流程",
|
"hideAllFlows": "隐藏所有流程",
|
||||||
"hiddenFlows": "列出 __count__ 个隐藏流程",
|
"hiddenFlows": "列出 __count__ 个隐藏流程",
|
||||||
"hiddenFlows_plural": "列出 __count__ 个隐藏流程",
|
"hiddenFlows_plural": "列出 __count__ 个隐藏流程",
|
||||||
"showLastHiddenFlow": "显示最后一个隐藏流程",
|
"showLastHiddenFlow": "显示最后一个隐藏流程",
|
||||||
"listFlows": "流程表",
|
"listFlows": "流程一览",
|
||||||
"listSubflows": "子流程表",
|
"listSubflows": "列出子流程",
|
||||||
"status": "状态",
|
"status": "状态",
|
||||||
"enabled": "有效",
|
"enabled": "有效",
|
||||||
"disabled": "无效",
|
"disabled": "无效",
|
||||||
@ -75,8 +75,8 @@
|
|||||||
"view": {
|
"view": {
|
||||||
"view": "显示",
|
"view": "显示",
|
||||||
"grid": "网格",
|
"grid": "网格",
|
||||||
"storeZoom": "加载时恢复缩放级别",
|
"storeZoom": "加载时还原缩放尺寸",
|
||||||
"storePosition": "加载时恢复滚动位置",
|
"storePosition": "加载时还原滚动位置",
|
||||||
"showGrid": "显示网格",
|
"showGrid": "显示网格",
|
||||||
"snapGrid": "对齐网格",
|
"snapGrid": "对齐网格",
|
||||||
"gridSize": "网格尺寸",
|
"gridSize": "网格尺寸",
|
||||||
@ -117,8 +117,8 @@
|
|||||||
"editPalette": "节点管理",
|
"editPalette": "节点管理",
|
||||||
"other": "其他",
|
"other": "其他",
|
||||||
"showTips": "显示小提示",
|
"showTips": "显示小提示",
|
||||||
"showWelcomeTours": "显示新版本的导览",
|
"showWelcomeTours": "显示新版本向导",
|
||||||
"help": "Node-RED网页",
|
"help": "Node-RED 文档主页",
|
||||||
"projects": "项目",
|
"projects": "项目",
|
||||||
"projects-new": "新建",
|
"projects-new": "新建",
|
||||||
"projects-open": "打开",
|
"projects-open": "打开",
|
||||||
@ -130,19 +130,19 @@
|
|||||||
"ungroupSelection": "取消选择组",
|
"ungroupSelection": "取消选择组",
|
||||||
"groupMergeSelection": "合并选择",
|
"groupMergeSelection": "合并选择",
|
||||||
"groupRemoveSelection": "从组中移除",
|
"groupRemoveSelection": "从组中移除",
|
||||||
"arrange": "排列",
|
"arrange": "布局",
|
||||||
"alignLeft": "左对齐",
|
"alignLeft": "左对齐",
|
||||||
"alignCenter": "水平居中对齐",
|
"alignCenter": "居中对齐",
|
||||||
"alignRight": "右对齐",
|
"alignRight": "右对齐",
|
||||||
"alignTop": "顶部对齐",
|
"alignTop": "顶部对齐",
|
||||||
"alignMiddle": "垂直居中对齐",
|
"alignMiddle": "垂直居中对齐",
|
||||||
"alignBottom": "底部对齐",
|
"alignBottom": "底部对齐",
|
||||||
"distributeHorizontally": "横向分布",
|
"distributeHorizontally": "横向分布",
|
||||||
"distributeVertically": "垂直分布",
|
"distributeVertically": "垂直分布",
|
||||||
"moveToBack": "移动到最底层",
|
"moveToBack": "置于底层",
|
||||||
"moveToFront": "移动到最顶层",
|
"moveToFront": "置于顶层",
|
||||||
"moveBackwards": "向后移动一层",
|
"moveBackwards": "向后移动",
|
||||||
"moveForwards": "向前移动一层"
|
"moveForwards": "向前移动"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
@ -153,7 +153,7 @@
|
|||||||
"search-flows": "搜索流程",
|
"search-flows": "搜索流程",
|
||||||
"search-prev": "上一个",
|
"search-prev": "上一个",
|
||||||
"search-next": "下一个",
|
"search-next": "下一个",
|
||||||
"search-counter": "\"__term__\" __count__ 个 __result__ "
|
"search-counter": "\"__term__\" __result__ of __count__"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"loggedInAs": "作为 __name__ 登录",
|
"loggedInAs": "作为 __name__ 登录",
|
||||||
@ -170,8 +170,8 @@
|
|||||||
},
|
},
|
||||||
"notification": {
|
"notification": {
|
||||||
"state": {
|
"state": {
|
||||||
"flowsStopped": "流程停止",
|
"flowsStopped": "流程已停止",
|
||||||
"flowsStarted": "流程开始"
|
"flowsStarted": "流程已启动"
|
||||||
},
|
},
|
||||||
"warning": "<strong>警告</strong>: __message__",
|
"warning": "<strong>警告</strong>: __message__",
|
||||||
"warnings": {
|
"warnings": {
|
||||||
@ -179,7 +179,7 @@
|
|||||||
"nodeActionDisabled": "节点操作已禁用",
|
"nodeActionDisabled": "节点操作已禁用",
|
||||||
"nodeActionDisabledSubflow": "节点动作在子流程中被禁用",
|
"nodeActionDisabledSubflow": "节点动作在子流程中被禁用",
|
||||||
"missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息",
|
"missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息",
|
||||||
"missing-modules": "<p>由于缺少模块,流程停止。</p>",
|
"missing-modules": "<p>流程因缺少模块而停止。</p>",
|
||||||
"safe-mode": "<p>流程以安全模式停止。</p><p>您可以修改流程并部署更改以重新启动。</p>",
|
"safe-mode": "<p>流程以安全模式停止。</p><p>您可以修改流程并部署更改以重新启动。</p>",
|
||||||
"restartRequired": "Node-RED必须重新启动,以启用升级的模块",
|
"restartRequired": "Node-RED必须重新启动,以启用升级的模块",
|
||||||
"credentials_load_failed": "<p>由于无法解密凭据,因此流程停止。</p><p>流程凭据文件已加密,但是项目的加密密钥丢失或无效。</p>",
|
"credentials_load_failed": "<p>由于无法解密凭据,因此流程停止。</p><p>流程凭据文件已加密,但是项目的加密密钥丢失或无效。</p>",
|
||||||
@ -240,13 +240,15 @@
|
|||||||
"subflow_plural": "__count__ 子流程",
|
"subflow_plural": "__count__ 子流程",
|
||||||
"replacedNodes": "__count__ 个节点被置换",
|
"replacedNodes": "__count__ 个节点被置换",
|
||||||
"replacedNodes_plural": "__count__ 个节点被置换",
|
"replacedNodes_plural": "__count__ 个节点被置换",
|
||||||
"pasteNodes": "在这里粘贴节点",
|
"pasteNodes": "在下方粘贴节点 ",
|
||||||
"selectFile": "选择要导入的文件",
|
"selectFile": "导入节点文件",
|
||||||
"importNodes": "导入节点",
|
"importNodes": "导入节点",
|
||||||
"exportNodes": "导出节点至剪贴板",
|
"exportNodes": "导出节点至剪贴板",
|
||||||
"download": "下载",
|
"download": "下载",
|
||||||
"importUnrecognised": "导入了无法识别的类型:",
|
"importUnrecognised": "导入了无法识别的类型:",
|
||||||
"importUnrecognised_plural": "导入了无法识别的类型:",
|
"importUnrecognised_plural": "导入了无法识别的类型:",
|
||||||
|
"importDuplicate": "导入了重复节点:",
|
||||||
|
"importDuplicate_plural": "导入了重复节点:",
|
||||||
"nodesExported": "节点导出到了剪贴板",
|
"nodesExported": "节点导出到了剪贴板",
|
||||||
"nodesImported": "导入:",
|
"nodesImported": "导入:",
|
||||||
"nodeCopied": "已复制 __count__ 个节点",
|
"nodeCopied": "已复制 __count__ 个节点",
|
||||||
@ -260,7 +262,7 @@
|
|||||||
"recoveredNodesNotification": "<p>导入的节点缺少有效的流ID</p><p>已将它们添加到名为 '__flowName__'的新流中。</p>",
|
"recoveredNodesNotification": "<p>导入的节点缺少有效的流ID</p><p>已将它们添加到名为 '__flowName__'的新流中。</p>",
|
||||||
"export": {
|
"export": {
|
||||||
"selected": "已选择的节点",
|
"selected": "已选择的节点",
|
||||||
"current": "现在的节点",
|
"current": "当前节点",
|
||||||
"all": "所有流程",
|
"all": "所有流程",
|
||||||
"compact": "紧凑",
|
"compact": "紧凑",
|
||||||
"formatted": "已格式化",
|
"formatted": "已格式化",
|
||||||
@ -292,12 +294,16 @@
|
|||||||
},
|
},
|
||||||
"deploy": {
|
"deploy": {
|
||||||
"deploy": "部署",
|
"deploy": "部署",
|
||||||
"full": "全面",
|
"full": "全部",
|
||||||
"fullDesc": "在工作区中部署所有内容",
|
"fullDesc": "在工作区中部署所有内容",
|
||||||
"modifiedFlows": "已修改的流程",
|
"modifiedFlows": "已修改的流程",
|
||||||
"modifiedFlowsDesc": "只部署包含已更改节点的流",
|
"modifiedFlowsDesc": "只部署包含已更改节点的流",
|
||||||
"modifiedNodes": "已更改的节点",
|
"modifiedNodes": "已更改的节点",
|
||||||
"modifiedNodesDesc": "只部署已经更改的节点",
|
"modifiedNodesDesc": "只部署已经更改的节点",
|
||||||
|
"startFlows": "启动",
|
||||||
|
"startFlowsDesc": "启动流程",
|
||||||
|
"stopFlows": "停止",
|
||||||
|
"stopFlowsDesc": "停止流程",
|
||||||
"restartFlows": "重启流程",
|
"restartFlows": "重启流程",
|
||||||
"restartFlowsDesc": "重新启动当前部署的流程",
|
"restartFlowsDesc": "重新启动当前部署的流程",
|
||||||
"successfulDeploy": "部署成功",
|
"successfulDeploy": "部署成功",
|
||||||
@ -305,8 +311,8 @@
|
|||||||
"deployFailed": "部署失败: __message__",
|
"deployFailed": "部署失败: __message__",
|
||||||
"unusedConfigNodes": "您有一些未使用的配置节点",
|
"unusedConfigNodes": "您有一些未使用的配置节点",
|
||||||
"unusedConfigNodesButton": "搜索未使用的配置节点",
|
"unusedConfigNodesButton": "搜索未使用的配置节点",
|
||||||
"unknownNodesButton":"搜索未知节点",
|
"unknownNodesButton": "查找未知节点",
|
||||||
"invalidNodesButton":"搜索无效节点",
|
"invalidNodesButton": "查找无效节点",
|
||||||
"errors": {
|
"errors": {
|
||||||
"noResponse": "服务器没有响应"
|
"noResponse": "服务器没有响应"
|
||||||
},
|
},
|
||||||
@ -376,19 +382,20 @@
|
|||||||
"output": "输出:",
|
"output": "输出:",
|
||||||
"status": "状态节点",
|
"status": "状态节点",
|
||||||
"deleteSubflow": "删除子流程",
|
"deleteSubflow": "删除子流程",
|
||||||
|
"confirmDelete": "您确定要删除此子流程?",
|
||||||
"info": "详细描述",
|
"info": "详细描述",
|
||||||
"category": "类别",
|
"category": "类别",
|
||||||
"module": "模块",
|
"module": "模块",
|
||||||
"license": "许可证",
|
"license": "许可",
|
||||||
"licenseNone": "无",
|
"licenseNone": "无",
|
||||||
"licenseOther": "其他",
|
"licenseOther": "其它",
|
||||||
"type": "节点类型",
|
"type": "节点类型",
|
||||||
"version": "版本",
|
"version": "版本",
|
||||||
"versionPlaceholder": "x.y.z",
|
"versionPlaceholder": "x.y.z",
|
||||||
"keys": "关键字",
|
"keys": "关键字",
|
||||||
"keysPlaceholder": "逗号分隔的关键字",
|
"keysPlaceholder": "使用英文逗号分隔关键字",
|
||||||
"author": "作者",
|
"author": "作者",
|
||||||
"authorPlaceholder": "你的名字<email@example.com>",
|
"authorPlaceholder": "名字 <email@example.com>",
|
||||||
"desc": "描述",
|
"desc": "描述",
|
||||||
"env": {
|
"env": {
|
||||||
"restore": "恢复为默认子流",
|
"restore": "恢复为默认子流",
|
||||||
@ -484,9 +491,8 @@
|
|||||||
"unassigned": "未分配",
|
"unassigned": "未分配",
|
||||||
"global": "全局",
|
"global": "全局",
|
||||||
"workspace": "工作区",
|
"workspace": "工作区",
|
||||||
"editor": "编辑对话框",
|
|
||||||
"selectAll": "选择所有节点",
|
"selectAll": "选择所有节点",
|
||||||
"selectNone": "不选择所有节点",
|
"selectNone": "取消所有选择",
|
||||||
"selectAllConnected": "选择所有连接的节点",
|
"selectAllConnected": "选择所有连接的节点",
|
||||||
"addRemoveNode": "从选择中添加/删除节点",
|
"addRemoveNode": "从选择中添加/删除节点",
|
||||||
"editSelected": "编辑选定节点",
|
"editSelected": "编辑选定节点",
|
||||||
@ -503,18 +509,18 @@
|
|||||||
"copyGroupStyle": "复制组样式",
|
"copyGroupStyle": "复制组样式",
|
||||||
"pasteGroupStyle": "粘贴组样式",
|
"pasteGroupStyle": "粘贴组样式",
|
||||||
"undoChange": "撤消",
|
"undoChange": "撤消",
|
||||||
"redoChange": "恢复",
|
"redoChange": "重做",
|
||||||
"searchBox": "打开搜索框",
|
"searchBox": "打开搜索框",
|
||||||
"managePalette": "管理面板",
|
"managePalette": "管理面板",
|
||||||
"actionList": "动作列表",
|
"actionList": "动作列表",
|
||||||
"splitWireWithLinks": "使用链接节点拆分选择"
|
"splitWireWithLinks": "使用Link节点拆分已选项"
|
||||||
},
|
},
|
||||||
"library": {
|
"library": {
|
||||||
"library": "库",
|
"library": "库",
|
||||||
"openLibrary": "打开库...",
|
"openLibrary": "打开库...",
|
||||||
"saveToLibrary": "保存到库...",
|
"saveToLibrary": "保存到库...",
|
||||||
"typeLibrary": "__type__类型库",
|
"typeLibrary": "__type__类型库",
|
||||||
"unnamedType": "未命名__type__",
|
"unnamedType": "无名__type__",
|
||||||
"exportedToLibrary": "节点导出到库",
|
"exportedToLibrary": "节点导出到库",
|
||||||
"dialogSaveOverwrite": "一个叫做__libraryName__的__libraryType__已经存在,您需要覆盖么?",
|
"dialogSaveOverwrite": "一个叫做__libraryName__的__libraryType__已经存在,您需要覆盖么?",
|
||||||
"invalidFilename": "无效的文件名",
|
"invalidFilename": "无效的文件名",
|
||||||
@ -523,23 +529,23 @@
|
|||||||
"saveFailed": "保存失败: __message__",
|
"saveFailed": "保存失败: __message__",
|
||||||
"newFolder": "新文件夹",
|
"newFolder": "新文件夹",
|
||||||
"types": {
|
"types": {
|
||||||
"local": "本地的",
|
"local": "本地存储",
|
||||||
"examples": "例子"
|
"examples": "示例"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"noInfo": "无可用信息",
|
"noInfo": "无可用信息",
|
||||||
"filter": "过滤节点",
|
"filter": "过滤已安装模块",
|
||||||
"search": "搜索模块",
|
"search": "搜索模块",
|
||||||
"addCategory": "添加新的...",
|
"addCategory": "添加新的...",
|
||||||
"label": {
|
"label": {
|
||||||
"subflows": "子流程",
|
"subflows": "子流程",
|
||||||
"network": "网络",
|
"network": "网络",
|
||||||
"common": "共通",
|
"common": "通用",
|
||||||
"input": "输入",
|
"input": "输入",
|
||||||
"output": "输出",
|
"output": "输出",
|
||||||
"function": "功能",
|
"function": "功能",
|
||||||
"sequence": "序列",
|
"sequence": "序列化",
|
||||||
"parser": "解析",
|
"parser": "解析",
|
||||||
"social": "社交",
|
"social": "社交",
|
||||||
"storage": "存储",
|
"storage": "存储",
|
||||||
@ -560,7 +566,7 @@
|
|||||||
"nodeDisabled": "禁用节点:",
|
"nodeDisabled": "禁用节点:",
|
||||||
"nodeDisabled_plural": "禁用多个节点:",
|
"nodeDisabled_plural": "禁用多个节点:",
|
||||||
"nodeUpgraded": "节点模块__module__升级到__version__版本",
|
"nodeUpgraded": "节点模块__module__升级到__version__版本",
|
||||||
"unknownNodeRegistered": "加载节点时出错: <ul><li>__type__<br>__error__</li></ul>"
|
"unknownNodeRegistered": "加载节点错误: <ul><li>__type__<br>__error__</li></ul>"
|
||||||
},
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"title": "面板管理",
|
"title": "面板管理",
|
||||||
@ -608,26 +614,26 @@
|
|||||||
"sortRecent": "日期顺序",
|
"sortRecent": "日期顺序",
|
||||||
"more": "增加 __count__ 个",
|
"more": "增加 __count__ 个",
|
||||||
"upload": "上传模块tgz文件",
|
"upload": "上传模块tgz文件",
|
||||||
"refresh": "刷新模块列表",
|
"refresh": "更新模块列表",
|
||||||
"errors": {
|
"errors": {
|
||||||
"catalogLoadFailed": "<p>无法加载节点目录。</p><p>查看浏览器控制台了解更多信息</p>",
|
"catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息",
|
||||||
"installFailed": "<p>无法安装: __module__</p><p>__message__</p><p>查看日志了解更多信息</p>",
|
"installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息",
|
||||||
"removeFailed": "<p>无法删除: __module__</p><p>__message__</p><p>查看日志了解更多信息</p>",
|
"removeFailed": "无法删除: __module__<br>__message__<br>查看日志了解更多信息",
|
||||||
"updateFailed": "<p>无法更新: __module__</p><p>__message__</p><p>查看日志了解更多信息</p>",
|
"updateFailed": "无法更新: __module__<br>__message__<br>查看日志了解更多信息",
|
||||||
"enableFailed": "<p>无法启用: __module__</p><p>__message__</p><p查看日志了解更多信息</p>",
|
"enableFailed": "无法启用: __module__<br>__message__<br>查看日志了解更多信息",
|
||||||
"disableFailed": "<p>无法禁用: __module__</p><p>__message__</p><p>查看日志了解更多信息</p>"
|
"disableFailed": "无法禁用: __module__<br>__message__<br>查看日志了解更多信息"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"install": {
|
"install": {
|
||||||
"body": "<p>'__module__'安装中</p><p>在安装之前,请阅读节点的文档。 某些节点的依赖关系不能自动解决可能需要重新启动Node-RED。</p>",
|
"body": "在安装之前,请阅读节点的文档,某些节点的依赖关系不能自动解决,可能需要重新启动Node-RED。",
|
||||||
"title": "安装节点"
|
"title": "安装节点"
|
||||||
},
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"body": "<p>'__module__'删除中</p><p>删除节点将从Node-RED卸载它。节点可能会继续使用资源,直到重新启动Node-RED。</p>",
|
"body": "删除节点将从Node-RED卸载它。节点可能会继续使用资源,直到重新启动Node-RED。",
|
||||||
"title": "删除节点"
|
"title": "删除节点"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"body": "<p>'__module__'升级中</p><p>更新节点将需要重新启动Node-RED来完成更新,该过程必须由手动完成。</p>",
|
"body": "更新节点将需要重新启动Node-RED来完成更新,该过程必须由手动完成。",
|
||||||
"title": "更新节点"
|
"title": "更新节点"
|
||||||
},
|
},
|
||||||
"cannotUpdate": {
|
"cannotUpdate": {
|
||||||
@ -677,8 +683,6 @@
|
|||||||
"empty": "空的",
|
"empty": "空的",
|
||||||
"globalConfig": "全局配置节点",
|
"globalConfig": "全局配置节点",
|
||||||
"triggerAction": "触发动作",
|
"triggerAction": "触发动作",
|
||||||
"showFlow": "显示",
|
|
||||||
"hideFlow": "隐藏",
|
|
||||||
"find": "在工作区中查找"
|
"find": "在工作区中查找"
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
@ -714,14 +718,14 @@
|
|||||||
"node": "节点",
|
"node": "节点",
|
||||||
"flow": "流程",
|
"flow": "流程",
|
||||||
"global": "全局",
|
"global": "全局",
|
||||||
"deleteConfirm": "你确定要删除这个项目吗?",
|
"deleteConfirm": "确定要删除这个项目吗?",
|
||||||
"autoRefresh": "刷新选择更改",
|
"autoRefresh": "刷新选择更改",
|
||||||
"refrsh": "刷新",
|
"refrsh": "刷新",
|
||||||
"delete": "删除"
|
"delete": "删除"
|
||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"name": "节点管理",
|
"name": "模块管理",
|
||||||
"label": "节点"
|
"label": "模块"
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
"label": "项目",
|
"label": "项目",
|
||||||
@ -757,7 +761,7 @@
|
|||||||
"changeTheEncryptionKey": "更改加密密钥",
|
"changeTheEncryptionKey": "更改加密密钥",
|
||||||
"currentKey": "当前密钥",
|
"currentKey": "当前密钥",
|
||||||
"newKey": "新密钥",
|
"newKey": "新密钥",
|
||||||
"credentialsAlert": "这将删除所有现有证书",
|
"credentialsAlert": "将删除所有现有证书",
|
||||||
"versionControl": "版本控制",
|
"versionControl": "版本控制",
|
||||||
"branches": "分支",
|
"branches": "分支",
|
||||||
"noBranches": "没有分支",
|
"noBranches": "没有分支",
|
||||||
@ -770,7 +774,7 @@
|
|||||||
"remoteName": "远程仓库名",
|
"remoteName": "远程仓库名",
|
||||||
"nameRule": "只能包含A-Z 0-9 _ -",
|
"nameRule": "只能包含A-Z 0-9 _ -",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"urlRule": "https://, ssh:// or file://",
|
"urlRule": "https://, ssh:// 或 file://",
|
||||||
"urlRule2": "网址中不能包含用户名/密码",
|
"urlRule2": "网址中不能包含用户名/密码",
|
||||||
"noRemotes": "没有远程仓库",
|
"noRemotes": "没有远程仓库",
|
||||||
"deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?",
|
"deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?",
|
||||||
@ -884,7 +888,7 @@
|
|||||||
},
|
},
|
||||||
"typedInput": {
|
"typedInput": {
|
||||||
"type": {
|
"type": {
|
||||||
"str": "字符串",
|
"str": "文本",
|
||||||
"num": "数字",
|
"num": "数字",
|
||||||
"re": "正则表达式",
|
"re": "正则表达式",
|
||||||
"bool": "布尔值",
|
"bool": "布尔值",
|
||||||
@ -898,33 +902,33 @@
|
|||||||
},
|
},
|
||||||
"editableList": {
|
"editableList": {
|
||||||
"add": "添加",
|
"add": "添加",
|
||||||
"addTitle": "添加一个物品"
|
"addTitle": "添加项"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"history": "查询历史",
|
"history": "搜索历史",
|
||||||
"clear": "清除所有",
|
"clear": "清除所有",
|
||||||
"empty": "找不到匹配",
|
"empty": "找不到匹配项",
|
||||||
"addNode": "添加一个节点...",
|
"addNode": "添加节点...",
|
||||||
"options": {
|
"options": {
|
||||||
"configNodes": "配置节点",
|
"configNodes": "配置节点",
|
||||||
"unusedConfigNodes": "未使用的配置节点",
|
"unusedConfigNodes": "未使用的配置节点",
|
||||||
"invalidNodes": "无效的节点",
|
"invalidNodes": "无效的节点",
|
||||||
"uknownNodes": "未知的节点",
|
"uknownNodes": "未知的节点",
|
||||||
"unusedSubflows": "未使用的子流程",
|
"unusedSubflows": "未使用的子流程",
|
||||||
"hiddenFlows": "隐藏流程",
|
"hiddenFlows": "隐藏的流程",
|
||||||
"modifiedNodes": "修改节点和流程",
|
"modifiedNodes": "已修改的节点或流程",
|
||||||
"thisFlow": "当前流程"
|
"thisFlow": "当前流程"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"expressionEditor": {
|
"expressionEditor": {
|
||||||
"functions": "功能",
|
"functions": "函数",
|
||||||
"functionReference": "功能reference",
|
"functionReference": "函数引用",
|
||||||
"insert": "插入",
|
"insert": "插入",
|
||||||
"title": "JSONata 表达式编辑器",
|
"title": "JSONata 表达式编辑器",
|
||||||
"test": "测试",
|
"test": "测试",
|
||||||
"data": "示例消息",
|
"data": "示例消息",
|
||||||
"result": "结果",
|
"result": "结果",
|
||||||
"format": "格式表达方法",
|
"format": "格式表达式",
|
||||||
"compatMode": "兼容模式启用",
|
"compatMode": "兼容模式启用",
|
||||||
"compatModeDesc": "<h3>JSONata的兼容模式</h3><p> 目前的表达式仍然参考<code>msg</code>,所以将以兼容性模式进行评估。请更新表达式,使其不使用<code>msg</code>,因为此模式将在将来删除。</p><p> 当JSONata支持首次添加到Node-RED时,它需要表达式引用<code>msg</code>对象。例如<code>msg.payload</code>将用于访问有效负载。</p><p> 这样便不再需要表达式直接针对消息进行评估。要访问有效负载,表达式应该只是<code>payload</code>.</p>",
|
"compatModeDesc": "<h3>JSONata的兼容模式</h3><p> 目前的表达式仍然参考<code>msg</code>,所以将以兼容性模式进行评估。请更新表达式,使其不使用<code>msg</code>,因为此模式将在将来删除。</p><p> 当JSONata支持首次添加到Node-RED时,它需要表达式引用<code>msg</code>对象。例如<code>msg.payload</code>将用于访问有效负载。</p><p> 这样便不再需要表达式直接针对消息进行评估。要访问有效负载,表达式应该只是<code>payload</code>.</p>",
|
||||||
"noMatch": "无匹配结果",
|
"noMatch": "无匹配结果",
|
||||||
@ -934,8 +938,8 @@
|
|||||||
"context-unsupported": "无法测试上下文函数\n $flowContext 或 $globalContext",
|
"context-unsupported": "无法测试上下文函数\n $flowContext 或 $globalContext",
|
||||||
"env-unsupported": "无法测试 $env 函数",
|
"env-unsupported": "无法测试 $env 函数",
|
||||||
"moment-unsupported": "无法测试 $moment 函数",
|
"moment-unsupported": "无法测试 $moment 函数",
|
||||||
"clone-unsupported": "C无法测试 $clone 函数",
|
"clone-unsupported": "无法测试 $clone 函数",
|
||||||
"eval": "评估表达式错误:\n __message__"
|
"eval": "计算表达式错误:\n __message__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"monaco": {
|
"monaco": {
|
||||||
@ -951,15 +955,15 @@
|
|||||||
"title": "JSON 编辑器",
|
"title": "JSON 编辑器",
|
||||||
"format": "格式化JSON",
|
"format": "格式化JSON",
|
||||||
"rawMode": "编辑 JSON",
|
"rawMode": "编辑 JSON",
|
||||||
"uiMode": "Visual编辑器",
|
"uiMode": "可视化编辑器",
|
||||||
"rawMode-readonly": "JSON",
|
"rawMode-readonly": "原始JSON",
|
||||||
"uiMode-readonly": "Visual",
|
"uiMode-readonly": "可视化",
|
||||||
"insertAbove": "在上方插入",
|
"insertAbove": "在上方插入",
|
||||||
"insertBelow": "在下方插入",
|
"insertBelow": "在下方插入",
|
||||||
"addItem": "添加项目",
|
"addItem": "添加项目",
|
||||||
"copyPath": "复制路径到项目",
|
"copyPath": "复制路径到项目",
|
||||||
"expandItems": "展开项目",
|
"expandItems": "展开项目",
|
||||||
"collapseItems": "收合项目",
|
"collapseItems": "折叠项目",
|
||||||
"duplicate": "重复",
|
"duplicate": "重复",
|
||||||
"error": {
|
"error": {
|
||||||
"invalidJSON": "无效的JSON: "
|
"invalidJSON": "无效的JSON: "
|
||||||
@ -983,10 +987,10 @@
|
|||||||
"toggle-preview": "切换预览"
|
"toggle-preview": "切换预览"
|
||||||
},
|
},
|
||||||
"bufferEditor": {
|
"bufferEditor": {
|
||||||
"title": "缓冲区编辑器",
|
"title": "Buffer 编辑器",
|
||||||
"modeString": "作为UTF-8字符串处理",
|
"modeString": "作为UTF-8字符串处理",
|
||||||
"modeArray": "作为JSON数组处理",
|
"modeArray": "作为JSON数组处理",
|
||||||
"modeDesc": "<h3>缓冲区编辑器</h3><p>缓冲区类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON,它将被视为UTF-8字符串,并被转换为单个字符代码点的数组。</p><p>例如,<code>Hello World</code>的值会被转换为JSON数组:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
"modeDesc": "<h3>Buffer 编辑器</h3><p>Buffer类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON,它将被视为UTF-8字符串,并被转换为单个字符代码点的数组。</p><p>例如,<code>Hello World</code>的值会被转换为JSON数组:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
||||||
},
|
},
|
||||||
"projects": {
|
"projects": {
|
||||||
"config-git": "配置Git客户端",
|
"config-git": "配置Git客户端",
|
||||||
@ -998,7 +1002,7 @@
|
|||||||
"create": "建立专案",
|
"create": "建立专案",
|
||||||
"clone": "克隆仓库",
|
"clone": "克隆仓库",
|
||||||
"openExistingProject": "打开现有项目",
|
"openExistingProject": "打开现有项目",
|
||||||
"not-right-now": "不是现在"
|
"not-right-now": "稍后"
|
||||||
},
|
},
|
||||||
"git-config": {
|
"git-config": {
|
||||||
"setup": "设置您的版本控制客户端",
|
"setup": "设置您的版本控制客户端",
|
||||||
@ -1077,7 +1081,7 @@
|
|||||||
},
|
},
|
||||||
"create-success": {
|
"create-success": {
|
||||||
"success": "您已经成功创建了第一个项目!",
|
"success": "您已经成功创建了第一个项目!",
|
||||||
"desc0": "现在您可以像往常一样继续使用Node-RED。",
|
"desc0": "现在,您可以像往常一样继续使用Node-RED。",
|
||||||
"desc1": "侧栏中的“信息”标签显示了您当前的活动项目。名称旁边的按钮可用于访问项目设置视图。",
|
"desc1": "侧栏中的“信息”标签显示了您当前的活动项目。名称旁边的按钮可用于访问项目设置视图。",
|
||||||
"desc2": "侧栏中的“历史记录”标签可用于查看项目中已更改的文件并提交。它向您显示了提交的完整历史记录,并允许您将更改推送到远程存储库。"
|
"desc2": "侧栏中的“历史记录”标签可用于查看项目中已更改的文件并提交。它向您显示了提交的完整历史记录,并允许您将更改推送到远程存储库。"
|
||||||
},
|
},
|
||||||
@ -1100,7 +1104,7 @@
|
|||||||
"desc0": "用来保护您的凭证的短语",
|
"desc0": "用来保护您的凭证的短语",
|
||||||
"desc1": "凭证文件不会被加密,其内容很容易阅读",
|
"desc1": "凭证文件不会被加密,其内容很容易阅读",
|
||||||
"git-url": "Git存储库URL",
|
"git-url": "Git存储库URL",
|
||||||
"protocols": "https://, ssh:// or file://",
|
"protocols": "https://, ssh:// 或 file://",
|
||||||
"auth-failed": "验证失败",
|
"auth-failed": "验证失败",
|
||||||
"username": "用户名",
|
"username": "用户名",
|
||||||
"password": "密码",
|
"password": "密码",
|
||||||
@ -1116,7 +1120,7 @@
|
|||||||
"no-resource": "找不到存储库",
|
"no-resource": "找不到存储库",
|
||||||
"cant-get-ssh-key-path": "错误!无法获取所选的SSH密钥路径。",
|
"cant-get-ssh-key-path": "错误!无法获取所选的SSH密钥路径。",
|
||||||
"unexpected_error": "意外的错误",
|
"unexpected_error": "意外的错误",
|
||||||
"clearContext": "切换项目时清除上下文"
|
"clearContext": "更改项目时清除上下文"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"confirm": "您确定要删除此项目吗?"
|
"confirm": "您确定要删除此项目吗?"
|
||||||
@ -1143,6 +1147,17 @@
|
|||||||
"create": "创建分支",
|
"create": "创建分支",
|
||||||
"current": "当前的"
|
"current": "当前的"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"de": "德语",
|
||||||
|
"en-US": "英文",
|
||||||
|
"fr": "法语",
|
||||||
|
"ja": "日语",
|
||||||
|
"ko": "韩文",
|
||||||
|
"pt-BR":"葡萄牙语",
|
||||||
|
"ru":"俄語",
|
||||||
|
"zh-CN": "简体中文",
|
||||||
|
"zh-TW": "繁体中文"
|
||||||
|
},
|
||||||
"create-default-file-set": {
|
"create-default-file-set": {
|
||||||
"no-active": "没有活动项目就无法创建默认文件集",
|
"no-active": "没有活动项目就无法创建默认文件集",
|
||||||
"no-empty": "无法在非空项目上创建默认文件集",
|
"no-empty": "无法在非空项目上创建默认文件集",
|
||||||
@ -1164,33 +1179,33 @@
|
|||||||
"defaultValue": "默认值"
|
"defaultValue": "默认值"
|
||||||
},
|
},
|
||||||
"tourGuide": {
|
"tourGuide": {
|
||||||
"takeATour": "游览一下",
|
"takeATour": "查看更新内容",
|
||||||
"start": "开始",
|
"start": "开始",
|
||||||
"next": "Next",
|
"next": "下一个",
|
||||||
"welcomeTours": "欢迎游览"
|
"welcomeTours": "欢迎使用 Node-RED"
|
||||||
},
|
},
|
||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"title": "系统信息"
|
"title": "系统信息"
|
||||||
},
|
},
|
||||||
"languages": {
|
"languages": {
|
||||||
"de": "德语",
|
"de": "德语-Deutsch",
|
||||||
"en-US": "英文",
|
"en-US": "英文-English",
|
||||||
"ja": "日语",
|
"ja": "日语-日本",
|
||||||
"ko": "韩文",
|
"ko": "韩文-한국인",
|
||||||
"ru": "俄文",
|
"ru": "俄语-Русский",
|
||||||
"zh-CN": "简体中文",
|
"zh-CN": "简体中文",
|
||||||
"zh-TW": "繁体中文"
|
"zh-TW": "繁體中文"
|
||||||
},
|
},
|
||||||
"validator": {
|
"validator": {
|
||||||
"errors": {
|
"errors": {
|
||||||
"invalid-json": "无效的JSON数据: __error__",
|
"invalid-json": "无效的 JSON 数据: __error__",
|
||||||
"invalid-json-prop": "__prop__: 无效的JSON数据: __error__",
|
"invalid-json-prop": "__prop__: 无效的 JSON 数据: __error__",
|
||||||
"invalid-prop": "无效的属性表达式",
|
"invalid-prop": "无效的属性表达式",
|
||||||
"invalid-prop-prop": "__prop__: 无效的属性表达式",
|
"invalid-prop-prop": "__prop__: 无效的属性表达式",
|
||||||
"invalid-num": "无效的数字",
|
"invalid-num": "无效的数字",
|
||||||
"invalid-num-prop": "__prop__: 无效的数字",
|
"invalid-num-prop": "__prop__: 无效的数字",
|
||||||
"invalid-regexp": "无效的输入模式",
|
"invalid-regexp": "输入格式无效",
|
||||||
"invalid-regex-prop": "__prop__: 无效的输入模式",
|
"invalid-regex-prop": "__prop__: 输入格式无效",
|
||||||
"missing-required-prop": "__prop__: 缺少属性值",
|
"missing-required-prop": "__prop__: 缺少属性值",
|
||||||
"invalid-config": "__prop__: 无效的配置节点",
|
"invalid-config": "__prop__: 无效的配置节点",
|
||||||
"missing-config": "__prop__: 缺少配置节点",
|
"missing-config": "__prop__: 缺少配置节点",
|
||||||
|
@ -137,7 +137,7 @@
|
|||||||
},
|
},
|
||||||
"$sort": {
|
"$sort": {
|
||||||
"args": "array [, function]",
|
"args": "array [, function]",
|
||||||
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后,那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
|
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)`\n\n该比较函数是为了比较`left`和`right`两个值而被排序算法调用的。如果用户希望`left`的值被置于`right`的值之后,那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
|
||||||
},
|
},
|
||||||
"$reverse": {
|
"$reverse": {
|
||||||
"args": "array",
|
"args": "array",
|
||||||
@ -237,7 +237,7 @@
|
|||||||
},
|
},
|
||||||
"$assert": {
|
"$assert": {
|
||||||
"args": "arg, str",
|
"args": "arg, str",
|
||||||
"desc": "如果 `arg` 为真,则该函数返回。 如果arg为假,则抛出带有str的异常作为异常消息。"
|
"desc": "如果 `arg` 为真,则该函数返回。 如果`arg`为假,则抛出带有`str`的异常作为异常消息。"
|
||||||
},
|
},
|
||||||
"$single": {
|
"$single": {
|
||||||
"args": "array, function",
|
"args": "array, function",
|
||||||
|
@ -1088,8 +1088,11 @@
|
|||||||
"languages": {
|
"languages": {
|
||||||
"de": "德語",
|
"de": "德語",
|
||||||
"en-US": "英語",
|
"en-US": "英語",
|
||||||
|
"fr": "法語",
|
||||||
"ja": "日語",
|
"ja": "日語",
|
||||||
"ko": "韓語",
|
"ko": "韓語",
|
||||||
|
"pt-BR":"葡萄牙语",
|
||||||
|
"ru":"俄語",
|
||||||
"zh-CN": "簡體中文",
|
"zh-CN": "簡體中文",
|
||||||
"zh-TW": "繁體中文"
|
"zh-TW": "繁體中文"
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@
|
|||||||
},
|
},
|
||||||
"$sort": {
|
"$sort": {
|
||||||
"args": "array [, function]",
|
"args": "array [, function]",
|
||||||
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較left和right兩個值而被排序演算法調用的。如果使用者希望left的值被置於right的值之後,那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
|
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較`left`和`right`兩個值而被排序演算法調用的。如果使用者希望left的值被置於`right`的值之後,那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
|
||||||
},
|
},
|
||||||
"$reverse": {
|
"$reverse": {
|
||||||
"args": "array",
|
"args": "array",
|
||||||
@ -237,7 +237,7 @@
|
|||||||
},
|
},
|
||||||
"$assert": {
|
"$assert": {
|
||||||
"args": "arg, str",
|
"args": "arg, str",
|
||||||
"desc": "如果`arg`為真,則該函數返回。 如果arg為假,則拋出帶有str的異常作為異常消息。"
|
"desc": "如果`arg`為真,則該函數返回。 如果`arg`為假,則拋出帶有`str`的異常作為異常消息。"
|
||||||
},
|
},
|
||||||
"$single": {
|
"$single": {
|
||||||
"args": "array, function",
|
"args": "array, function",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@node-red/editor-client",
|
"name": "@node-red/editor-client",
|
||||||
"version": "3.0.2",
|
"version": "3.1.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -378,7 +378,8 @@ RED.history = (function() {
|
|||||||
if (ev.addToGroup) {
|
if (ev.addToGroup) {
|
||||||
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
|
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
|
||||||
inverseEv.removeFromGroup = ev.addToGroup;
|
inverseEv.removeFromGroup = ev.addToGroup;
|
||||||
} else if (ev.removeFromGroup) {
|
}
|
||||||
|
if (ev.removeFromGroup) {
|
||||||
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
|
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
|
||||||
inverseEv.addToGroup = ev.removeFromGroup;
|
inverseEv.addToGroup = ev.removeFromGroup;
|
||||||
}
|
}
|
||||||
@ -421,6 +422,9 @@ RED.history = (function() {
|
|||||||
ev.node[i] = ev.changes[i];
|
ev.node[i] = ev.changes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ev.node.dirty = true;
|
||||||
|
ev.node.changed = ev.changed;
|
||||||
|
|
||||||
var eventType;
|
var eventType;
|
||||||
switch(ev.node.type) {
|
switch(ev.node.type) {
|
||||||
case 'tab': eventType = "flows"; break;
|
case 'tab': eventType = "flows"; break;
|
||||||
@ -434,7 +438,9 @@ RED.history = (function() {
|
|||||||
|
|
||||||
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
|
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-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) {
|
if (ev.subflow) {
|
||||||
inverseEv.subflow = {};
|
inverseEv.subflow = {};
|
||||||
@ -509,8 +515,6 @@ RED.history = (function() {
|
|||||||
inverseEv.links.push(ev.createdLinks[i]);
|
inverseEv.links.push(ev.createdLinks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ev.node.dirty = true;
|
|
||||||
ev.node.changed = ev.changed;
|
|
||||||
} else if (ev.t == "createSubflow") {
|
} else if (ev.t == "createSubflow") {
|
||||||
inverseEv = {
|
inverseEv = {
|
||||||
t: "deleteSubflow",
|
t: "deleteSubflow",
|
||||||
@ -646,6 +650,12 @@ RED.history = (function() {
|
|||||||
ev.groups[i].nodes = [];
|
ev.groups[i].nodes = [];
|
||||||
RED.nodes.addGroup(ev.groups[i]);
|
RED.nodes.addGroup(ev.groups[i]);
|
||||||
RED.group.addToGroup(ev.groups[i],nodes);
|
RED.group.addToGroup(ev.groups[i],nodes);
|
||||||
|
if (ev.groups[i].g) {
|
||||||
|
const parentGroup = RED.nodes.group(ev.groups[i].g)
|
||||||
|
if (parentGroup) {
|
||||||
|
RED.group.addToGroup(parentGroup, ev.groups[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ev.t == "addToGroup") {
|
} else if (ev.t == "addToGroup") {
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
* @namespace RED.nodes
|
* @namespace RED.nodes
|
||||||
*/
|
*/
|
||||||
RED.nodes = (function() {
|
RED.nodes = (function() {
|
||||||
|
|
||||||
var PORT_TYPE_INPUT = 1;
|
var PORT_TYPE_INPUT = 1;
|
||||||
var PORT_TYPE_OUTPUT = 0;
|
var PORT_TYPE_OUTPUT = 0;
|
||||||
|
|
||||||
@ -47,6 +46,9 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
function setDirty(d) {
|
function setDirty(d) {
|
||||||
dirty = d;
|
dirty = d;
|
||||||
|
if (!d) {
|
||||||
|
allNodes.clearState()
|
||||||
|
}
|
||||||
RED.events.emit("workspace:dirty",{dirty:dirty});
|
RED.events.emit("workspace:dirty",{dirty:dirty});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,12 +65,12 @@ RED.nodes = (function() {
|
|||||||
defaults: {
|
defaults: {
|
||||||
label: {value:""},
|
label: {value:""},
|
||||||
disabled: {value: false},
|
disabled: {value: false},
|
||||||
|
locked: {value: false},
|
||||||
info: {value: ""},
|
info: {value: ""},
|
||||||
env: {value: []}
|
env: {value: []}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var exports = {
|
var exports = {
|
||||||
setModulePendingUpdated: function(module,version) {
|
setModulePendingUpdated: function(module,version) {
|
||||||
moduleList[module].pending_version = version;
|
moduleList[module].pending_version = version;
|
||||||
@ -238,22 +240,72 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
// allNodes holds information about the Flow nodes.
|
// allNodes holds information about the Flow nodes.
|
||||||
var allNodes = (function() {
|
var allNodes = (function() {
|
||||||
|
// Map node.id -> node
|
||||||
var nodes = {};
|
var nodes = {};
|
||||||
|
// Map tab.id -> Array of nodes on that tab
|
||||||
var tabMap = {};
|
var tabMap = {};
|
||||||
|
// Map tab.id -> Set of dirty object ids on that tab
|
||||||
|
var tabDirtyMap = {};
|
||||||
|
// Map tab.id -> Set of object ids of things deleted from the tab that weren't otherwise dirty
|
||||||
|
var tabDeletedNodesMap = {};
|
||||||
|
// Set of object ids of things added to a tab after initial import
|
||||||
|
var addedDirtyObjects = new Set()
|
||||||
|
|
||||||
|
function changeCollectionDepth(tabNodes, toMove, direction, singleStep) {
|
||||||
|
const result = []
|
||||||
|
const moved = new Set();
|
||||||
|
const startIndex = direction ? tabNodes.length - 1 : 0
|
||||||
|
const endIndex = direction ? -1 : tabNodes.length
|
||||||
|
const step = direction ? -1 : 1
|
||||||
|
let target = startIndex // Only used for all-the-way moves
|
||||||
|
for (let i = startIndex; i != endIndex; i += step) {
|
||||||
|
if (toMove.size === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const n = tabNodes[i]
|
||||||
|
if (toMove.has(n)) {
|
||||||
|
if (singleStep) {
|
||||||
|
if (i !== startIndex && !moved.has(tabNodes[i - step])) {
|
||||||
|
tabNodes.splice(i, 1)
|
||||||
|
tabNodes.splice(i - step, 0, n)
|
||||||
|
n._reordered = true
|
||||||
|
result.push(n)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i !== target) {
|
||||||
|
tabNodes.splice(i, 1)
|
||||||
|
tabNodes.splice(target, 0, n)
|
||||||
|
n._reordered = true
|
||||||
|
result.push(n)
|
||||||
|
}
|
||||||
|
target += step
|
||||||
|
}
|
||||||
|
toMove.delete(n);
|
||||||
|
moved.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
var api = {
|
var api = {
|
||||||
addTab: function(id) {
|
addTab: function(id) {
|
||||||
tabMap[id] = [];
|
tabMap[id] = [];
|
||||||
|
tabDirtyMap[id] = new Set();
|
||||||
|
tabDeletedNodesMap[id] = new Set();
|
||||||
},
|
},
|
||||||
hasTab: function(z) {
|
hasTab: function(z) {
|
||||||
return tabMap.hasOwnProperty(z)
|
return tabMap.hasOwnProperty(z)
|
||||||
},
|
},
|
||||||
removeTab: function(id) {
|
removeTab: function(id) {
|
||||||
delete tabMap[id];
|
delete tabMap[id];
|
||||||
|
delete tabDirtyMap[id];
|
||||||
|
delete tabDeletedNodesMap[id];
|
||||||
},
|
},
|
||||||
addNode: function(n) {
|
addNode: function(n) {
|
||||||
nodes[n.id] = n;
|
nodes[n.id] = n;
|
||||||
if (tabMap.hasOwnProperty(n.z)) {
|
if (tabMap.hasOwnProperty(n.z)) {
|
||||||
tabMap[n.z].push(n);
|
tabMap[n.z].push(n);
|
||||||
|
api.addObjectToWorkspace(n.z, n.id, n.changed || n.moved)
|
||||||
} else {
|
} else {
|
||||||
console.warn("Node added to unknown tab/subflow:",n);
|
console.warn("Node added to unknown tab/subflow:",n);
|
||||||
tabMap["_"] = tabMap["_"] || [];
|
tabMap["_"] = tabMap["_"] || [];
|
||||||
@ -267,8 +319,37 @@ RED.nodes = (function() {
|
|||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
tabMap[n.z].splice(i,1);
|
tabMap[n.z].splice(i,1);
|
||||||
}
|
}
|
||||||
|
api.removeObjectFromWorkspace(n.z, n.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Add an object to our dirty/clean tracking state
|
||||||
|
* @param {String} z
|
||||||
|
* @param {String} id
|
||||||
|
* @param {Boolean} isDirty
|
||||||
|
*/
|
||||||
|
addObjectToWorkspace: function (z, id, isDirty) {
|
||||||
|
if (isDirty) {
|
||||||
|
addedDirtyObjects.add(id)
|
||||||
|
}
|
||||||
|
if (tabDeletedNodesMap[z].has(id)) {
|
||||||
|
tabDeletedNodesMap[z].delete(id)
|
||||||
|
}
|
||||||
|
api.markNodeDirty(z, id, isDirty)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Remove an object from our dirty/clean tracking state
|
||||||
|
* @param {String} z
|
||||||
|
* @param {String} id
|
||||||
|
*/
|
||||||
|
removeObjectFromWorkspace: function (z, id) {
|
||||||
|
if (!addedDirtyObjects.has(id)) {
|
||||||
|
tabDeletedNodesMap[z].add(id)
|
||||||
|
} else {
|
||||||
|
addedDirtyObjects.delete(id)
|
||||||
|
}
|
||||||
|
api.markNodeDirty(z, id, false)
|
||||||
|
},
|
||||||
hasNode: function(id) {
|
hasNode: function(id) {
|
||||||
return nodes.hasOwnProperty(id);
|
return nodes.hasOwnProperty(id);
|
||||||
},
|
},
|
||||||
@ -280,152 +361,54 @@ RED.nodes = (function() {
|
|||||||
n.z = newZ;
|
n.z = newZ;
|
||||||
api.addNode(n)
|
api.addNode(n)
|
||||||
},
|
},
|
||||||
moveNodesForwards: function(nodes) {
|
/**
|
||||||
var result = [];
|
* @param {array} nodes
|
||||||
|
* @param {boolean} direction true:forwards false:back
|
||||||
|
* @param {boolean} singleStep true:single-step false:all-the-way
|
||||||
|
*/
|
||||||
|
changeDepth: function(nodes, direction, singleStep) {
|
||||||
if (!Array.isArray(nodes)) {
|
if (!Array.isArray(nodes)) {
|
||||||
nodes = [nodes]
|
nodes = [nodes]
|
||||||
}
|
}
|
||||||
// Can only do this for nodes on the same tab.
|
let result = []
|
||||||
// Use nodes[0] to get the z
|
const tabNodes = tabMap[nodes[0].z];
|
||||||
var tabNodes = tabMap[nodes[0].z];
|
const toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" }));
|
||||||
var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" }));
|
if (toMove.size > 0) {
|
||||||
var moved = new Set();
|
result = result.concat(changeCollectionDepth(tabNodes, toMove, direction, singleStep))
|
||||||
for (var i = tabNodes.length-1; i >= 0; i--) {
|
|
||||||
if (toMove.size === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var n = tabNodes[i];
|
|
||||||
if (toMove.has(n)) {
|
|
||||||
// This is a node to move.
|
|
||||||
if (i < tabNodes.length-1 && !moved.has(tabNodes[i+1])) {
|
|
||||||
// Remove from current position
|
|
||||||
tabNodes.splice(i,1);
|
|
||||||
// Add it back one position higher
|
|
||||||
tabNodes.splice(i+1,0,n);
|
|
||||||
n._reordered = true;
|
|
||||||
result.push(n);
|
|
||||||
}
|
|
||||||
toMove.delete(n);
|
|
||||||
moved.add(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.length > 0) {
|
if (result.length > 0) {
|
||||||
RED.events.emit('nodes:reorder',{
|
RED.events.emit('nodes:reorder',{
|
||||||
z: nodes[0].z,
|
z: nodes[0].z,
|
||||||
nodes: result
|
nodes: result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
}
|
||||||
|
|
||||||
|
const groupNodes = groupsByZ[nodes[0].z] || []
|
||||||
|
const groupsToMove = new Set(nodes.filter(function(n) { return n.type === 'group'}))
|
||||||
|
if (groupsToMove.size > 0) {
|
||||||
|
const groupResult = changeCollectionDepth(groupNodes, groupsToMove, direction, singleStep)
|
||||||
|
if (groupResult.length > 0) {
|
||||||
|
result = result.concat(groupResult)
|
||||||
|
RED.events.emit('groups:reorder',{
|
||||||
|
z: nodes[0].z,
|
||||||
|
nodes: groupResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.view.redraw(true)
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
moveNodesForwards: function(nodes) {
|
||||||
|
return api.changeDepth(nodes, true, true)
|
||||||
},
|
},
|
||||||
moveNodesBackwards: function(nodes) {
|
moveNodesBackwards: function(nodes) {
|
||||||
var result = [];
|
return api.changeDepth(nodes, false, true)
|
||||||
if (!Array.isArray(nodes)) {
|
|
||||||
nodes = [nodes]
|
|
||||||
}
|
|
||||||
// Can only do this for nodes on the same tab.
|
|
||||||
// Use nodes[0] to get the z
|
|
||||||
var tabNodes = tabMap[nodes[0].z];
|
|
||||||
var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" }));
|
|
||||||
var moved = new Set();
|
|
||||||
for (var i = 0; i < tabNodes.length; i++) {
|
|
||||||
if (toMove.size === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var n = tabNodes[i];
|
|
||||||
if (toMove.has(n)) {
|
|
||||||
// This is a node to move.
|
|
||||||
if (i > 0 && !moved.has(tabNodes[i-1])) {
|
|
||||||
// Remove from current position
|
|
||||||
tabNodes.splice(i,1);
|
|
||||||
// Add it back one position lower
|
|
||||||
tabNodes.splice(i-1,0,n);
|
|
||||||
n._reordered = true;
|
|
||||||
result.push(n);
|
|
||||||
}
|
|
||||||
toMove.delete(n);
|
|
||||||
moved.add(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.length > 0) {
|
|
||||||
RED.events.emit('nodes:reorder',{
|
|
||||||
z: nodes[0].z,
|
|
||||||
nodes: result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
moveNodesToFront: function(nodes) {
|
moveNodesToFront: function(nodes) {
|
||||||
var result = [];
|
return api.changeDepth(nodes, true, false)
|
||||||
if (!Array.isArray(nodes)) {
|
|
||||||
nodes = [nodes]
|
|
||||||
}
|
|
||||||
// Can only do this for nodes on the same tab.
|
|
||||||
// Use nodes[0] to get the z
|
|
||||||
var tabNodes = tabMap[nodes[0].z];
|
|
||||||
var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" }));
|
|
||||||
var target = tabNodes.length-1;
|
|
||||||
for (var i = tabNodes.length-1; i >= 0; i--) {
|
|
||||||
if (toMove.size === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var n = tabNodes[i];
|
|
||||||
if (toMove.has(n)) {
|
|
||||||
// This is a node to move.
|
|
||||||
if (i < target) {
|
|
||||||
// Remove from current position
|
|
||||||
tabNodes.splice(i,1);
|
|
||||||
tabNodes.splice(target,0,n);
|
|
||||||
n._reordered = true;
|
|
||||||
result.push(n);
|
|
||||||
}
|
|
||||||
target--;
|
|
||||||
toMove.delete(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.length > 0) {
|
|
||||||
RED.events.emit('nodes:reorder',{
|
|
||||||
z: nodes[0].z,
|
|
||||||
nodes: result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
moveNodesToBack: function(nodes) {
|
moveNodesToBack: function(nodes) {
|
||||||
var result = [];
|
return api.changeDepth(nodes, false, false)
|
||||||
if (!Array.isArray(nodes)) {
|
|
||||||
nodes = [nodes]
|
|
||||||
}
|
|
||||||
// Can only do this for nodes on the same tab.
|
|
||||||
// Use nodes[0] to get the z
|
|
||||||
var tabNodes = tabMap[nodes[0].z];
|
|
||||||
var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" }));
|
|
||||||
var target = 0;
|
|
||||||
for (var i = 0; i < tabNodes.length; i++) {
|
|
||||||
if (toMove.size === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var n = tabNodes[i];
|
|
||||||
if (toMove.has(n)) {
|
|
||||||
// This is a node to move.
|
|
||||||
if (i > target) {
|
|
||||||
// Remove from current position
|
|
||||||
tabNodes.splice(i,1);
|
|
||||||
// Add it back one position lower
|
|
||||||
tabNodes.splice(target,0,n);
|
|
||||||
n._reordered = true;
|
|
||||||
result.push(n);
|
|
||||||
}
|
|
||||||
target++;
|
|
||||||
toMove.delete(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.length > 0) {
|
|
||||||
RED.events.emit('nodes:reorder',{
|
|
||||||
z: nodes[0].z,
|
|
||||||
nodes: result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
getNodes: function(z) {
|
getNodes: function(z) {
|
||||||
return tabMap[z];
|
return tabMap[z];
|
||||||
@ -433,6 +416,33 @@ RED.nodes = (function() {
|
|||||||
clear: function() {
|
clear: function() {
|
||||||
nodes = {};
|
nodes = {};
|
||||||
tabMap = {};
|
tabMap = {};
|
||||||
|
tabDirtyMap = {};
|
||||||
|
tabDeletedNodesMap = {};
|
||||||
|
addedDirtyObjects = new Set();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Clear all internal state on what is dirty.
|
||||||
|
*/
|
||||||
|
clearState: function () {
|
||||||
|
// Called when a deploy happens, we can forget about added/remove
|
||||||
|
// items as they have now been deployed.
|
||||||
|
addedDirtyObjects = new Set()
|
||||||
|
const flowsToCheck = new Set()
|
||||||
|
for (const [z, set] of Object.entries(tabDeletedNodesMap)) {
|
||||||
|
if (set.size > 0) {
|
||||||
|
set.clear()
|
||||||
|
flowsToCheck.add(z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [z, set] of Object.entries(tabDirtyMap)) {
|
||||||
|
if (set.size > 0) {
|
||||||
|
set.clear()
|
||||||
|
flowsToCheck.add(z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const z of flowsToCheck) {
|
||||||
|
api.checkTabState(z)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
eachNode: function(cb) {
|
eachNode: function(cb) {
|
||||||
var nodeList,i,j;
|
var nodeList,i,j;
|
||||||
@ -498,7 +508,7 @@ RED.nodes = (function() {
|
|||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
getNodeOrder: function(z) {
|
getNodeOrder: function(z) {
|
||||||
return tabMap[z].map(function(n) { return n.id })
|
return (groupsByZ[z] || []).concat(tabMap[z]).map(n => n.id)
|
||||||
},
|
},
|
||||||
setNodeOrder: function(z, order) {
|
setNodeOrder: function(z, order) {
|
||||||
var orderMap = {};
|
var orderMap = {};
|
||||||
@ -510,6 +520,41 @@ RED.nodes = (function() {
|
|||||||
B._reordered = true;
|
B._reordered = true;
|
||||||
return orderMap[A.id] - orderMap[B.id];
|
return orderMap[A.id] - orderMap[B.id];
|
||||||
})
|
})
|
||||||
|
if (groupsByZ[z]) {
|
||||||
|
groupsByZ[z].sort(function(A,B) {
|
||||||
|
return orderMap[A.id] - orderMap[B.id];
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Update our records if an object is dirty or not
|
||||||
|
* @param {String} z tab id
|
||||||
|
* @param {String} id object id
|
||||||
|
* @param {Boolean} dirty whether the object is dirty or not
|
||||||
|
*/
|
||||||
|
markNodeDirty: function(z, id, dirty) {
|
||||||
|
if (tabDirtyMap[z]) {
|
||||||
|
if (dirty) {
|
||||||
|
tabDirtyMap[z].add(id)
|
||||||
|
} else {
|
||||||
|
tabDirtyMap[z].delete(id)
|
||||||
|
}
|
||||||
|
api.checkTabState(z)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Check if a tab should update its contentsChange flag
|
||||||
|
* @param {String} z tab id
|
||||||
|
*/
|
||||||
|
checkTabState: function (z) {
|
||||||
|
const ws = workspaces[z]
|
||||||
|
if (ws) {
|
||||||
|
const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0
|
||||||
|
if (Boolean(ws.contentsChanged) !== contentsChanged) {
|
||||||
|
ws.contentsChanged = contentsChanged
|
||||||
|
RED.events.emit("flows:change", ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return api;
|
return api;
|
||||||
@ -575,15 +620,53 @@ 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}'`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node.z && (prop === 'changed' || prop === 'moved')) {
|
||||||
|
setTimeout(() => {
|
||||||
|
allNodes.markNodeDirty(node.z, node.id, node.changed || node.moved)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
node[prop] = value;
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addNode(n) {
|
function addNode(n) {
|
||||||
|
let newNode
|
||||||
|
if (!n.__isProxy__) {
|
||||||
|
newNode = new Proxy(n, nodeProxyHandler)
|
||||||
|
} else {
|
||||||
|
newNode = n
|
||||||
|
}
|
||||||
|
|
||||||
if (n.type.indexOf("subflow") !== 0) {
|
if (n.type.indexOf("subflow") !== 0) {
|
||||||
n["_"] = n._def._;
|
n["_"] = n._def._;
|
||||||
} else {
|
} else {
|
||||||
var subflowId = n.type.substring(8);
|
var subflowId = n.type.substring(8);
|
||||||
var sf = RED.nodes.subflow(subflowId);
|
var sf = RED.nodes.subflow(subflowId);
|
||||||
if (sf) {
|
if (sf) {
|
||||||
sf.instances.push(sf);
|
sf.instances.push(newNode);
|
||||||
}
|
}
|
||||||
n["_"] = RED._;
|
n["_"] = RED._;
|
||||||
}
|
}
|
||||||
@ -600,12 +683,13 @@ RED.nodes = (function() {
|
|||||||
});
|
});
|
||||||
n.i = nextId+1;
|
n.i = nextId+1;
|
||||||
}
|
}
|
||||||
allNodes.addNode(n);
|
allNodes.addNode(newNode);
|
||||||
if (!nodeLinks[n.id]) {
|
if (!nodeLinks[n.id]) {
|
||||||
nodeLinks[n.id] = {in:[],out:[]};
|
nodeLinks[n.id] = {in:[],out:[]};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RED.events.emit('nodes:add',n);
|
RED.events.emit('nodes:add',newNode);
|
||||||
|
return newNode
|
||||||
}
|
}
|
||||||
function addLink(l) {
|
function addLink(l) {
|
||||||
if (nodeLinks[l.source.id]) {
|
if (nodeLinks[l.source.id]) {
|
||||||
@ -632,10 +716,16 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
if (l.source.z === l.target.z && linkTabMap[l.source.z]) {
|
if (l.source.z === l.target.z && linkTabMap[l.source.z]) {
|
||||||
linkTabMap[l.source.z].push(l);
|
linkTabMap[l.source.z].push(l);
|
||||||
|
allNodes.addObjectToWorkspace(l.source.z, getLinkId(l), true)
|
||||||
}
|
}
|
||||||
RED.events.emit("links:add",l);
|
RED.events.emit("links:add",l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLinkId(link) {
|
||||||
|
return link.source.id + ':' + link.sourcePort + ':' + link.target.id
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function getNode(id) {
|
function getNode(id) {
|
||||||
if (id in configNodes) {
|
if (id in configNodes) {
|
||||||
return configNodes[id];
|
return configNodes[id];
|
||||||
@ -830,6 +920,7 @@ RED.nodes = (function() {
|
|||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
linkTabMap[l.source.z].splice(index,1)
|
linkTabMap[l.source.z].splice(index,1)
|
||||||
}
|
}
|
||||||
|
allNodes.removeObjectFromWorkspace(l.source.z, getLinkId(l))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RED.events.emit("links:remove",l);
|
RED.events.emit("links:remove",l);
|
||||||
@ -999,6 +1090,11 @@ RED.nodes = (function() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDownstreamNodes(node) {
|
||||||
|
const downstreamLinks = nodeLinks[node.id].out
|
||||||
|
const downstreamNodes = new Set(downstreamLinks.map(l => l.target))
|
||||||
|
return Array.from(downstreamNodes)
|
||||||
|
}
|
||||||
function getAllDownstreamNodes(node) {
|
function getAllDownstreamNodes(node) {
|
||||||
return getAllFlowNodes(node,'down').filter(function(n) { return n !== node });
|
return getAllFlowNodes(node,'down').filter(function(n) { return n !== node });
|
||||||
}
|
}
|
||||||
@ -1046,6 +1142,9 @@ RED.nodes = (function() {
|
|||||||
node.type = n.type;
|
node.type = n.type;
|
||||||
for (var d in n._def.defaults) {
|
for (var d in n._def.defaults) {
|
||||||
if (n._def.defaults.hasOwnProperty(d)) {
|
if (n._def.defaults.hasOwnProperty(d)) {
|
||||||
|
if (d === 'locked' && !n.locked) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
node[d] = n[d];
|
node[d] = n[d];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1369,7 +1468,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node.type !== "subflow") {
|
if (node.type !== "subflow") {
|
||||||
var convertedNode = RED.nodes.convertNode(node);
|
var convertedNode = RED.nodes.convertNode(node, { credentials: false });
|
||||||
for (var d in node._def.defaults) {
|
for (var d in node._def.defaults) {
|
||||||
if (node._def.defaults[d].type) {
|
if (node._def.defaults[d].type) {
|
||||||
var nodeList = node[d];
|
var nodeList = node[d];
|
||||||
@ -1402,7 +1501,7 @@ RED.nodes = (function() {
|
|||||||
nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes));
|
nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var convertedSubflow = convertSubflow(node);
|
var convertedSubflow = convertSubflow(node, { credentials: false });
|
||||||
nns.push(convertedSubflow);
|
nns.push(convertedSubflow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1651,6 +1750,7 @@ RED.nodes = (function() {
|
|||||||
* Options:
|
* Options:
|
||||||
* - generateIds - whether to replace all node ids
|
* - generateIds - whether to replace all node ids
|
||||||
* - addFlow - whether to import nodes to a new tab
|
* - addFlow - whether to import nodes to a new tab
|
||||||
|
* - markChanged - whether to set changed=true on all newly imported objects
|
||||||
* - reimport - if node has a .z property, dont overwrite it
|
* - reimport - if node has a .z property, dont overwrite it
|
||||||
* Only applicible when `generateIds` is false
|
* Only applicible when `generateIds` is false
|
||||||
* - importMap - how to resolve any conflicts.
|
* - importMap - how to resolve any conflicts.
|
||||||
@ -1659,7 +1759,7 @@ RED.nodes = (function() {
|
|||||||
* - id:replace - import over the top of existing
|
* - id:replace - import over the top of existing
|
||||||
*/
|
*/
|
||||||
function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) {
|
function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) {
|
||||||
const defOpts = { generateIds: false, addFlow: false, reimport: false, importMap: {} }
|
const defOpts = { generateIds: false, addFlow: false, markChanged: false, reimport: false, importMap: {} }
|
||||||
options = Object.assign({}, defOpts, options)
|
options = Object.assign({}, defOpts, options)
|
||||||
options.importMap = options.importMap || {}
|
options.importMap = options.importMap || {}
|
||||||
const createNewIds = options.generateIds;
|
const createNewIds = options.generateIds;
|
||||||
@ -1685,7 +1785,7 @@ RED.nodes = (function() {
|
|||||||
newNodes = newNodesObj;
|
newNodes = newNodesObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$.isArray(newNodes)) {
|
if (!Array.isArray(newNodes)) {
|
||||||
newNodes = [newNodes];
|
newNodes = [newNodes];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1983,6 +2083,9 @@ RED.nodes = (function() {
|
|||||||
if (!n.z) {
|
if (!n.z) {
|
||||||
delete configNode.z;
|
delete configNode.z;
|
||||||
}
|
}
|
||||||
|
if (options.markChanged) {
|
||||||
|
configNode.changed = true
|
||||||
|
}
|
||||||
if (n.hasOwnProperty('d')) {
|
if (n.hasOwnProperty('d')) {
|
||||||
configNode.d = n.d;
|
configNode.d = n.d;
|
||||||
}
|
}
|
||||||
@ -2045,6 +2148,9 @@ RED.nodes = (function() {
|
|||||||
if (n.hasOwnProperty('g')) {
|
if (n.hasOwnProperty('g')) {
|
||||||
node.g = n.g;
|
node.g = n.g;
|
||||||
}
|
}
|
||||||
|
if (options.markChanged) {
|
||||||
|
node.changed = true
|
||||||
|
}
|
||||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||||
if (subflow_denylist[n.z]) {
|
if (subflow_denylist[n.z]) {
|
||||||
continue;
|
continue;
|
||||||
@ -2276,7 +2382,7 @@ RED.nodes = (function() {
|
|||||||
// get added
|
// get added
|
||||||
if (activeSubflow && /^link /.test(n.type) && n.links) {
|
if (activeSubflow && /^link /.test(n.type) && n.links) {
|
||||||
n.links = n.links.filter(function(id) {
|
n.links = n.links.filter(function(id) {
|
||||||
var otherNode = RED.nodes.node(id);
|
const otherNode = node_map[id] || RED.nodes.node(id);
|
||||||
return (otherNode && otherNode.z === activeWorkspace)
|
return (otherNode && otherNode.z === activeWorkspace)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2326,19 +2432,6 @@ RED.nodes = (function() {
|
|||||||
if (n.g && !new_group_set.has(n.g)) {
|
if (n.g && !new_group_set.has(n.g)) {
|
||||||
delete 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) {
|
if (!n.g) {
|
||||||
groupDepthMap[n.id] = 0;
|
groupDepthMap[n.id] = 0;
|
||||||
}
|
}
|
||||||
@ -2361,21 +2454,22 @@ RED.nodes = (function() {
|
|||||||
return groupDepthMap[A.id] - groupDepthMap[B.id];
|
return groupDepthMap[A.id] - groupDepthMap[B.id];
|
||||||
});
|
});
|
||||||
for (i=0;i<new_groups.length;i++) {
|
for (i=0;i<new_groups.length;i++) {
|
||||||
n = new_groups[i];
|
new_groups[i] = addGroup(new_groups[i]);
|
||||||
addGroup(n);
|
node_map[new_groups[i].id] = new_groups[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0;i<new_junctions.length;i++) {
|
for (i=0;i<new_junctions.length;i++) {
|
||||||
var junction = new_junctions[i];
|
new_junctions[i] = addJunction(new_junctions[i]);
|
||||||
addJunction(junction);
|
node_map[new_junctions[i].id] = new_junctions[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Now the nodes have been fully updated, add them.
|
// Now the nodes have been fully updated, add them.
|
||||||
for (i=0;i<new_nodes.length;i++) {
|
for (i=0;i<new_nodes.length;i++) {
|
||||||
var node = new_nodes[i];
|
new_nodes[i] = addNode(new_nodes[i])
|
||||||
addNode(node);
|
node_map[new_nodes[i].id] = new_nodes[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally validate them all.
|
// Finally validate them all.
|
||||||
// This has to be done after everything is added so that any checks for
|
// This has to be done after everything is added so that any checks for
|
||||||
// dependent config nodes will pass
|
// dependent config nodes will pass
|
||||||
@ -2383,6 +2477,39 @@ RED.nodes = (function() {
|
|||||||
var node = new_nodes[i];
|
var node = new_nodes[i];
|
||||||
RED.editor.validateNode(node);
|
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();
|
RED.workspaces.refresh();
|
||||||
|
|
||||||
@ -2511,11 +2638,17 @@ RED.nodes = (function() {
|
|||||||
junctions = {};
|
junctions = {};
|
||||||
junctionsByZ = {};
|
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);
|
var subflowIds = Object.keys(subflows);
|
||||||
subflowIds.forEach(function(id) {
|
subflowIds.forEach(function(id) {
|
||||||
RED.subflow.removeSubflow(id)
|
RED.subflow.removeSubflow(id)
|
||||||
});
|
});
|
||||||
var workspaceIds = Object.keys(workspaces);
|
|
||||||
workspaceIds.forEach(function(id) {
|
workspaceIds.forEach(function(id) {
|
||||||
RED.workspaces.remove(workspaces[id]);
|
RED.workspaces.remove(workspaces[id]);
|
||||||
});
|
});
|
||||||
@ -2536,10 +2669,15 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addGroup(group) {
|
function addGroup(group) {
|
||||||
|
if (!group.__isProxy__) {
|
||||||
|
group = new Proxy(group, nodeProxyHandler)
|
||||||
|
}
|
||||||
groupsByZ[group.z] = groupsByZ[group.z] || [];
|
groupsByZ[group.z] = groupsByZ[group.z] || [];
|
||||||
groupsByZ[group.z].push(group);
|
groupsByZ[group.z].push(group);
|
||||||
groups[group.id] = group;
|
groups[group.id] = group;
|
||||||
|
allNodes.addObjectToWorkspace(group.z, group.id, group.changed || group.moved)
|
||||||
RED.events.emit("groups:add",group);
|
RED.events.emit("groups:add",group);
|
||||||
|
return group
|
||||||
}
|
}
|
||||||
function removeGroup(group) {
|
function removeGroup(group) {
|
||||||
var i = groupsByZ[group.z].indexOf(group);
|
var i = groupsByZ[group.z].indexOf(group);
|
||||||
@ -2554,19 +2692,28 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
RED.group.markDirty(group);
|
RED.group.markDirty(group);
|
||||||
|
allNodes.removeObjectFromWorkspace(group.z, group.id)
|
||||||
delete groups[group.id];
|
delete groups[group.id];
|
||||||
RED.events.emit("groups:remove",group);
|
RED.events.emit("groups:remove",group);
|
||||||
}
|
}
|
||||||
|
function getGroupOrder(z) {
|
||||||
|
const groups = groupsByZ[z]
|
||||||
|
return groups.map(g => g.id)
|
||||||
|
}
|
||||||
|
|
||||||
function addJunction(junction) {
|
function addJunction(junction) {
|
||||||
|
if (!junction.__isProxy__) {
|
||||||
|
junction = new Proxy(junction, nodeProxyHandler)
|
||||||
|
}
|
||||||
junctionsByZ[junction.z] = junctionsByZ[junction.z] || []
|
junctionsByZ[junction.z] = junctionsByZ[junction.z] || []
|
||||||
junctionsByZ[junction.z].push(junction)
|
junctionsByZ[junction.z].push(junction)
|
||||||
junctions[junction.id] = junction;
|
junctions[junction.id] = junction;
|
||||||
if (!nodeLinks[junction.id]) {
|
if (!nodeLinks[junction.id]) {
|
||||||
nodeLinks[junction.id] = {in:[],out:[]};
|
nodeLinks[junction.id] = {in:[],out:[]};
|
||||||
}
|
}
|
||||||
|
allNodes.addObjectToWorkspace(junction.z, junction.id, junction.changed || junction.moved)
|
||||||
RED.events.emit("junctions:add", junction)
|
RED.events.emit("junctions:add", junction)
|
||||||
|
return junction
|
||||||
}
|
}
|
||||||
function removeJunction(junction) {
|
function removeJunction(junction) {
|
||||||
var i = junctionsByZ[junction.z].indexOf(junction)
|
var i = junctionsByZ[junction.z].indexOf(junction)
|
||||||
@ -2576,6 +2723,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
delete junctions[junction.id]
|
delete junctions[junction.id]
|
||||||
delete nodeLinks[junction.id];
|
delete nodeLinks[junction.id];
|
||||||
|
allNodes.removeObjectFromWorkspace(junction.z, junction.id)
|
||||||
RED.events.emit("junctions:remove", junction)
|
RED.events.emit("junctions:remove", junction)
|
||||||
|
|
||||||
var removedLinks = links.filter(function(l) { return (l.source === junction) || (l.target === junction); });
|
var removedLinks = links.filter(function(l) { return (l.source === junction) || (l.target === junction); });
|
||||||
@ -2813,6 +2961,9 @@ RED.nodes = (function() {
|
|||||||
RED.view.redraw(true);
|
RED.view.redraw(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
RED.events.on('deploy', function () {
|
||||||
|
allNodes.clearState()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
registry:registry,
|
registry:registry,
|
||||||
setNodeList: registry.setNodeList,
|
setNodeList: registry.setNodeList,
|
||||||
@ -2861,7 +3012,7 @@ RED.nodes = (function() {
|
|||||||
},
|
},
|
||||||
addWorkspace: addWorkspace,
|
addWorkspace: addWorkspace,
|
||||||
removeWorkspace: removeWorkspace,
|
removeWorkspace: removeWorkspace,
|
||||||
getWorkspaceOrder: function() { return workspacesOrder },
|
getWorkspaceOrder: function() { return [...workspacesOrder] },
|
||||||
setWorkspaceOrder: function(order) { workspacesOrder = order; },
|
setWorkspaceOrder: function(order) { workspacesOrder = order; },
|
||||||
workspace: getWorkspace,
|
workspace: getWorkspace,
|
||||||
|
|
||||||
@ -2915,6 +3066,20 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
eachGroup: function(cb) {
|
||||||
|
for (var group of Object.values(groups)) {
|
||||||
|
if (cb(group) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eachJunction: function(cb) {
|
||||||
|
for (var junction of Object.values(junctions)) {
|
||||||
|
if (cb(junction) === false) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
node: getNode,
|
node: getNode,
|
||||||
|
|
||||||
@ -2937,6 +3102,7 @@ RED.nodes = (function() {
|
|||||||
getAllFlowNodes: getAllFlowNodes,
|
getAllFlowNodes: getAllFlowNodes,
|
||||||
getAllUpstreamNodes: getAllUpstreamNodes,
|
getAllUpstreamNodes: getAllUpstreamNodes,
|
||||||
getAllDownstreamNodes: getAllDownstreamNodes,
|
getAllDownstreamNodes: getAllDownstreamNodes,
|
||||||
|
getDownstreamNodes: getDownstreamNodes,
|
||||||
getNodeIslands: getNodeIslands,
|
getNodeIslands: getNodeIslands,
|
||||||
createExportableNodeSet: createExportableNodeSet,
|
createExportableNodeSet: createExportableNodeSet,
|
||||||
createCompleteNodeSet: createCompleteNodeSet,
|
createCompleteNodeSet: createCompleteNodeSet,
|
||||||
|
@ -249,8 +249,37 @@ var RED = (function() {
|
|||||||
RED.nodes.import(nodes.flows);
|
RED.nodes.import(nodes.flows);
|
||||||
RED.nodes.dirty(false);
|
RED.nodes.dirty(false);
|
||||||
RED.view.redraw(true);
|
RED.view.redraw(true);
|
||||||
if (/^#flow\/.+$/.test(currentHash)) {
|
if (/^#(flow|node|group)\/.+$/.test(currentHash)) {
|
||||||
RED.workspaces.show(currentHash.substring(6),true);
|
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
|
||||||
|
RED.view.select(nodeToShow.id)
|
||||||
|
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
|
||||||
|
RED.view.select(nodeToShow.id)
|
||||||
|
if (showEditDialog) {
|
||||||
|
RED.editor.editGroup(nodeToShow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (RED.workspaces.count() > 0) {
|
if (RED.workspaces.count() > 0) {
|
||||||
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||||
@ -643,11 +672,6 @@ var RED = (function() {
|
|||||||
]});
|
]});
|
||||||
|
|
||||||
menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [
|
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-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-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"},
|
{id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"},
|
||||||
@ -657,7 +681,12 @@ var RED = (function() {
|
|||||||
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
|
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
|
||||||
null,
|
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-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);
|
menuOptions.push(null);
|
||||||
@ -702,7 +731,7 @@ var RED = (function() {
|
|||||||
}
|
}
|
||||||
menuOptions.push({id:"menu-item-help",
|
menuOptions.push({id:"menu-item-help",
|
||||||
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
|
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
|
||||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
href: RED.settings.theme("menu.menu-item-help.url","https://nodered.org/docs")
|
||||||
});
|
});
|
||||||
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
|
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
|
||||||
|
|
||||||
@ -750,6 +779,7 @@ var RED = (function() {
|
|||||||
RED.deploy.init(RED.settings.theme("deployButton",null));
|
RED.deploy.init(RED.settings.theme("deployButton",null));
|
||||||
|
|
||||||
RED.keyboard.init(buildMainMenu);
|
RED.keyboard.init(buildMainMenu);
|
||||||
|
RED.envVar.init();
|
||||||
|
|
||||||
RED.nodes.init();
|
RED.nodes.init();
|
||||||
RED.runtime.init()
|
RED.runtime.init()
|
||||||
|
@ -33,8 +33,8 @@ RED.settings = (function () {
|
|||||||
if (!hasLocalStorage()) {
|
if (!hasLocalStorage()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key === "auth-tokens") {
|
if (key.startsWith("auth-tokens")) {
|
||||||
localStorage.setItem(key, JSON.stringify(value));
|
localStorage.setItem(key+this.authTokensSuffix, JSON.stringify(value));
|
||||||
} else {
|
} else {
|
||||||
RED.utils.setMessageProperty(userSettings,key,value);
|
RED.utils.setMessageProperty(userSettings,key,value);
|
||||||
saveUserSettings();
|
saveUserSettings();
|
||||||
@ -52,8 +52,8 @@ RED.settings = (function () {
|
|||||||
if (!hasLocalStorage()) {
|
if (!hasLocalStorage()) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (key === "auth-tokens") {
|
if (key.startsWith("auth-tokens")) {
|
||||||
return JSON.parse(localStorage.getItem(key));
|
return JSON.parse(localStorage.getItem(key+this.authTokensSuffix));
|
||||||
} else {
|
} else {
|
||||||
var v;
|
var v;
|
||||||
try { v = RED.utils.getMessageProperty(userSettings,key); } catch(err) {}
|
try { v = RED.utils.getMessageProperty(userSettings,key); } catch(err) {}
|
||||||
@ -71,8 +71,8 @@ RED.settings = (function () {
|
|||||||
if (!hasLocalStorage()) {
|
if (!hasLocalStorage()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (key === "auth-tokens") {
|
if (key.startsWith("auth-tokens")) {
|
||||||
localStorage.removeItem(key);
|
localStorage.removeItem(key+this.authTokensSuffix);
|
||||||
} else {
|
} else {
|
||||||
delete userSettings[key];
|
delete userSettings[key];
|
||||||
saveUserSettings();
|
saveUserSettings();
|
||||||
@ -99,6 +99,8 @@ RED.settings = (function () {
|
|||||||
|
|
||||||
var init = function (options, done) {
|
var init = function (options, done) {
|
||||||
var accessTokenMatch = /[?&]access_token=(.*?)(?:$|&)/.exec(window.location.search);
|
var accessTokenMatch = /[?&]access_token=(.*?)(?:$|&)/.exec(window.location.search);
|
||||||
|
var path=window.location.pathname.slice(0,-1);
|
||||||
|
RED.settings.authTokensSuffix=path.replace(/\//g, '-');
|
||||||
if (accessTokenMatch) {
|
if (accessTokenMatch) {
|
||||||
var accessToken = accessTokenMatch[1];
|
var accessToken = accessTokenMatch[1];
|
||||||
RED.settings.set("auth-tokens",{access_token: accessToken});
|
RED.settings.set("auth-tokens",{access_token: accessToken});
|
||||||
|
@ -423,11 +423,10 @@ RED.clipboard = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showImportNodes(mode) {
|
function showImportNodes(library = 'clipboard') {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mode = mode || "clipboard";
|
|
||||||
|
|
||||||
dialogContainer.empty();
|
dialogContainer.empty();
|
||||||
dialogContainer.append($(importNodesDialog));
|
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("keyup", validateImport);
|
||||||
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
|
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
|
||||||
|
|
||||||
if (RED.workspaces.active() === 0) {
|
if (RED.workspaces.active() === 0 || RED.workspaces.isLocked()) {
|
||||||
$("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected");
|
$("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected");
|
||||||
$("#red-ui-clipboard-dialog-import-opt-new").addClass("selected");
|
$("#red-ui-clipboard-dialog-import-opt-new").addClass("selected");
|
||||||
} else {
|
} else {
|
||||||
@ -533,8 +532,8 @@ RED.clipboard = (function() {
|
|||||||
$("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
|
$("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
|
||||||
})
|
})
|
||||||
|
|
||||||
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode);
|
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+library);
|
||||||
if (mode === 'clipboard') {
|
if (library === 'clipboard') {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
|
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
|
||||||
},100)
|
},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) {
|
if (disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = mode || "clipboard";
|
|
||||||
|
|
||||||
dialogContainer.empty();
|
dialogContainer.empty();
|
||||||
dialogContainer.append($(exportNodesDialog));
|
dialogContainer.append($(exportNodesDialog));
|
||||||
|
|
||||||
@ -654,7 +656,12 @@ RED.clipboard = (function() {
|
|||||||
$("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select();
|
$("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select();
|
||||||
|
|
||||||
dialogContainer.i18n();
|
dialogContainer.i18n();
|
||||||
|
|
||||||
var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini";
|
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) {
|
$("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
@ -670,7 +677,8 @@ RED.clipboard = (function() {
|
|||||||
var nodes = JSON.parse(flow);
|
var nodes = JSON.parse(flow);
|
||||||
|
|
||||||
format = $(this).attr('id');
|
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);
|
flow = JSON.stringify(nodes,null,4);
|
||||||
} else {
|
} else {
|
||||||
flow = JSON.stringify(nodes);
|
flow = JSON.stringify(nodes);
|
||||||
@ -679,6 +687,7 @@ RED.clipboard = (function() {
|
|||||||
setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50);
|
setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50);
|
||||||
|
|
||||||
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
|
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
|
||||||
|
RED.settings.set("editor.dialog.export.pretty", pretty)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -722,7 +731,7 @@ RED.clipboard = (function() {
|
|||||||
nodes.unshift(parentNode);
|
nodes.unshift(parentNode);
|
||||||
nodes = RED.nodes.createExportableNodeSet(nodes);
|
nodes = RED.nodes.createExportableNodeSet(nodes);
|
||||||
} else if (type === 'full') {
|
} else if (type === 'full') {
|
||||||
nodes = RED.nodes.createCompleteNodeSet(false);
|
nodes = RED.nodes.createCompleteNodeSet({ credentials: false });
|
||||||
}
|
}
|
||||||
if (nodes !== null) {
|
if (nodes !== null) {
|
||||||
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
||||||
@ -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") {
|
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
||||||
$("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
|
$("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
|
||||||
} else {
|
} else {
|
||||||
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
|
$("#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 dialogHeight = 400;
|
||||||
var winHeight = $(window).height();
|
var winHeight = $(window).height();
|
||||||
@ -1266,15 +1278,17 @@ RED.clipboard = (function() {
|
|||||||
RED.keyboard.add("#red-ui-drop-target", "escape" ,hideDropTarget);
|
RED.keyboard.add("#red-ui-drop-target", "escape" ,hideDropTarget);
|
||||||
|
|
||||||
$('#red-ui-workspace-chart').on("dragenter",function(event) {
|
$('#red-ui-workspace-chart').on("dragenter",function(event) {
|
||||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
|
if (!RED.workspaces.isLocked() && (
|
||||||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
$.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").css({display:'table'}).focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#red-ui-drop-target').on("dragover",function(event) {
|
$('#red-ui-drop-target').on("dragover",function(event) {
|
||||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
|
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.isLocked()) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1282,6 +1296,7 @@ RED.clipboard = (function() {
|
|||||||
hideDropTarget();
|
hideDropTarget();
|
||||||
})
|
})
|
||||||
.on("drop",function(event) {
|
.on("drop",function(event) {
|
||||||
|
if (!RED.workspaces.isLocked()) {
|
||||||
try {
|
try {
|
||||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||||
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
||||||
@ -1304,6 +1319,7 @@ RED.clipboard = (function() {
|
|||||||
// Ensure any errors throw above doesn't stop the drop target from
|
// Ensure any errors throw above doesn't stop the drop target from
|
||||||
// being hidden.
|
// being hidden.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
hideDropTarget();
|
hideDropTarget();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
@ -417,6 +417,9 @@
|
|||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
cancel: function() {
|
||||||
|
this.element.sortable("cancel");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
@ -94,8 +94,8 @@ RED.menu = (function() {
|
|||||||
|
|
||||||
var link = $(linkContent).appendTo(item);
|
var link = $(linkContent).appendTo(item);
|
||||||
opt.link = link;
|
opt.link = link;
|
||||||
if (typeof opt.onselect === 'string') {
|
if (typeof opt.onselect === 'string' || opt.shortcut) {
|
||||||
var shortcut = RED.keyboard.getShortcut(opt.onselect);
|
var shortcut = opt.shortcut || RED.keyboard.getShortcut(opt.onselect);
|
||||||
if (shortcut && shortcut.key) {
|
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"));
|
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 scrollLeft;
|
||||||
var scrollRight;
|
var scrollRight;
|
||||||
@ -161,7 +183,7 @@ RED.tabs = (function() {
|
|||||||
// Assume this is wheel event which might not trigger
|
// Assume this is wheel event which might not trigger
|
||||||
// the scroll event, so do things manually
|
// the scroll event, so do things manually
|
||||||
var sl = scrollContainer.scrollLeft();
|
var sl = scrollContainer.scrollLeft();
|
||||||
sl -= evt.originalEvent.deltaY;
|
sl += evt.originalEvent.deltaY;
|
||||||
scrollContainer.scrollLeft(sl);
|
scrollContainer.scrollLeft(sl);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -807,23 +829,22 @@ RED.tabs = (function() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
removeTab(tab.id);
|
removeTab(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"));
|
|
||||||
}
|
}
|
||||||
|
// 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);
|
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
|
||||||
if (options.onselect) {
|
if (options.onselect) {
|
||||||
$('<i class="red-ui-tabs-badge-changed fa fa-circle"></i>').appendTo(badges);
|
|
||||||
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
|
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,6 +959,9 @@ RED.tabs = (function() {
|
|||||||
activeIndex: function() {
|
activeIndex: function() {
|
||||||
return ul.find("li.active").index()
|
return ul.find("li.active").index()
|
||||||
},
|
},
|
||||||
|
getTabIndex: function (id) {
|
||||||
|
return ul.find("a[href='#"+id+"']").parent().index()
|
||||||
|
},
|
||||||
contains: function(id) {
|
contains: function(id) {
|
||||||
return ul.find("a[href='#"+id+"']").length > 0;
|
return ul.find("a[href='#"+id+"']").length > 0;
|
||||||
},
|
},
|
||||||
|
@ -1,21 +1,6 @@
|
|||||||
RED.contextMenu = (function () {
|
RED.contextMenu = (function () {
|
||||||
|
|
||||||
let menu;
|
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() {
|
function disposeMenu() {
|
||||||
$(document).off("mousedown.red-ui-workspace-context-menu");
|
$(document).off("mousedown.red-ui-workspace-context-menu");
|
||||||
@ -28,7 +13,10 @@ RED.contextMenu = (function () {
|
|||||||
if (menu) {
|
if (menu) {
|
||||||
menu.remove()
|
menu.remove()
|
||||||
}
|
}
|
||||||
|
let menuItems = []
|
||||||
|
if (options.options) {
|
||||||
|
menuItems = options.options
|
||||||
|
} else if (options.type === 'workspace') {
|
||||||
const selection = RED.view.selection()
|
const selection = RED.view.selection()
|
||||||
const noSelection = !selection || Object.keys(selection).length === 0
|
const noSelection = !selection || Object.keys(selection).length === 0
|
||||||
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||||
@ -40,20 +28,28 @@ RED.contextMenu = (function () {
|
|||||||
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
|
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
|
||||||
const canDelete = hasSelection || hasLinks
|
const canDelete = hasSelection || hasLinks
|
||||||
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
||||||
|
const canEdit = !RED.workspaces.isLocked()
|
||||||
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
|
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 offset = $("#red-ui-workspace-chart").offset()
|
||||||
|
|
||||||
// addX/addY must be the position in the workspace accounting for both scroll and scale
|
let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()
|
||||||
// The +5 is because we display the contextMenu -5,-5 to actual click position
|
let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()
|
||||||
let addX = (options.x + 5 - offset.left + $("#red-ui-workspace-chart").scrollLeft()) / RED.view.scale()
|
|
||||||
let addY = (options.y + 5 - offset.top + $("#red-ui-workspace-chart").scrollTop()) / RED.view.scale()
|
|
||||||
|
|
||||||
const menuItems = [
|
if (RED.view.snapGrid) {
|
||||||
{ onselect: 'core:show-action-list', onpostselect: function () { } },
|
const gridSize = RED.view.gridSize()
|
||||||
{
|
addX = gridSize * Math.floor(addX / gridSize)
|
||||||
label: RED._("contextMenu.insert"),
|
addY = gridSize * Math.floor(addY / gridSize)
|
||||||
options: [
|
}
|
||||||
|
|
||||||
|
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"),
|
label: RED._("contextMenu.node"),
|
||||||
onselect: function () {
|
onselect: function () {
|
||||||
@ -64,15 +60,12 @@ RED.contextMenu = (function () {
|
|||||||
// spliceMultiple: isMultipleLinks
|
// spliceMultiple: isMultipleLinks
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onpostselect: function() {
|
disabled: !canEdit
|
||||||
// ensure quick add dialog search input has focus
|
|
||||||
$('#red-ui-type-search-input').trigger('focus')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
(hasLinks) ? { // has least 1 wire selected
|
(hasLinks) ? { // has least 1 wire selected
|
||||||
label: RED._("contextMenu.junction"),
|
label: RED._("contextMenu.junction"),
|
||||||
onselect: 'core:split-wires-with-junctions',
|
onselect: 'core:split-wires-with-junctions',
|
||||||
disabled: !hasLinks
|
disabled: !canEdit || !hasLinks
|
||||||
} : {
|
} : {
|
||||||
label: RED._("contextMenu.junction"),
|
label: RED._("contextMenu.junction"),
|
||||||
onselect: function () {
|
onselect: function () {
|
||||||
@ -86,56 +79,106 @@ RED.contextMenu = (function () {
|
|||||||
w: 0, h: 0,
|
w: 0, h: 0,
|
||||||
outputs: 1,
|
outputs: 1,
|
||||||
inputs: 1,
|
inputs: 1,
|
||||||
dirty: true
|
dirty: true,
|
||||||
|
moved: true
|
||||||
}
|
}
|
||||||
|
const junction = RED.nodes.addJunction(nn);
|
||||||
const historyEvent = {
|
const historyEvent = {
|
||||||
dirty: RED.nodes.dirty(),
|
dirty: RED.nodes.dirty(),
|
||||||
t: 'add',
|
t: 'add',
|
||||||
junctions: [nn]
|
junctions: [junction]
|
||||||
}
|
}
|
||||||
RED.nodes.addJunction(nn);
|
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
RED.view.select({nodes: [nn] });
|
RED.view.select({nodes: [junction] });
|
||||||
RED.view.redraw(true)
|
RED.view.redraw(true)
|
||||||
}
|
},
|
||||||
|
disabled: !canEdit
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: RED._("contextMenu.linkNodes"),
|
label: RED._("contextMenu.linkNodes"),
|
||||||
onselect: 'core:split-wire-with-link-nodes',
|
onselect: 'core:split-wire-with-link-nodes',
|
||||||
disabled: !hasLinks
|
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 },
|
||||||
]
|
]
|
||||||
|
})
|
||||||
|
if (hasGroup) {
|
||||||
|
menuItems[menuItems.length - 1].options.push(
|
||||||
|
{ onselect: 'core:merge-selection-to-group', label: RED._("menu.label.groupMergeSelection") }
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (canRemoveFromGroup) {
|
||||||
|
menuItems[menuItems.length - 1].options.push(
|
||||||
|
{ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
menuItems[menuItems.length - 1].options.push(
|
||||||
|
null,
|
||||||
|
{ onselect: 'core:copy-group-style', disabled: !hasGroup },
|
||||||
|
{ onselect: 'core:paste-group-style', disabled: !hasGroup}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
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(
|
menuItems.push(
|
||||||
null,
|
null,
|
||||||
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
|
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
|
||||||
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
|
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
|
||||||
null,
|
null,
|
||||||
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection },
|
{ 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: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:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() },
|
||||||
{ onselect: 'core:delete-selection', disabled: !canDelete },
|
{ 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:show-export-dialog', label: RED._("menu.label.export") },
|
||||||
{ onselect: 'core:select-all-nodes' }
|
{ onselect: 'core:select-all-nodes' },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (hasSelection) {
|
|
||||||
menuItems.push(
|
|
||||||
null,
|
|
||||||
isGroup ?
|
|
||||||
{ onselect: 'core:ungroup-selection', disabled: !isGroup }
|
|
||||||
: { onselect: 'core:group-selection', disabled: !hasSelection }
|
|
||||||
)
|
|
||||||
if (canRemoveFromGroup) {
|
|
||||||
menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") })
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var direction = "right";
|
var direction = "right";
|
||||||
|
@ -557,7 +557,17 @@ RED.deploy = (function() {
|
|||||||
} else {
|
} else {
|
||||||
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
||||||
}
|
}
|
||||||
|
const flowsToLock = new Set()
|
||||||
|
function ensureUnlocked(id) {
|
||||||
|
const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null);
|
||||||
|
const isLocked = flow ? flow.locked : false;
|
||||||
|
if (flow && isLocked) {
|
||||||
|
flow.locked = false;
|
||||||
|
flowsToLock.add(flow)
|
||||||
|
}
|
||||||
|
}
|
||||||
RED.nodes.eachNode(function (node) {
|
RED.nodes.eachNode(function (node) {
|
||||||
|
ensureUnlocked(node.z)
|
||||||
if (node.changed) {
|
if (node.changed) {
|
||||||
node.dirty = true;
|
node.dirty = true;
|
||||||
node.changed = false;
|
node.changed = false;
|
||||||
@ -570,7 +580,32 @@ RED.deploy = (function() {
|
|||||||
delete node.credentials;
|
delete node.credentials;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
RED.nodes.eachGroup(function (node) {
|
||||||
|
ensureUnlocked(node.z)
|
||||||
|
if (node.changed) {
|
||||||
|
node.dirty = true;
|
||||||
|
node.changed = false;
|
||||||
|
}
|
||||||
|
if (node.moved) {
|
||||||
|
node.dirty = true;
|
||||||
|
node.moved = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
RED.nodes.eachJunction(function (node) {
|
||||||
|
ensureUnlocked(node.z)
|
||||||
|
if (node.changed) {
|
||||||
|
node.dirty = true;
|
||||||
|
node.changed = false;
|
||||||
|
}
|
||||||
|
if (node.moved) {
|
||||||
|
node.dirty = true;
|
||||||
|
node.moved = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
RED.nodes.eachConfig(function (confNode) {
|
RED.nodes.eachConfig(function (confNode) {
|
||||||
|
if (confNode.z) {
|
||||||
|
ensureUnlocked(confNode.z)
|
||||||
|
}
|
||||||
confNode.changed = false;
|
confNode.changed = false;
|
||||||
if (confNode.credentials) {
|
if (confNode.credentials) {
|
||||||
delete confNode.credentials;
|
delete confNode.credentials;
|
||||||
@ -580,8 +615,16 @@ RED.deploy = (function() {
|
|||||||
subflow.changed = false;
|
subflow.changed = false;
|
||||||
});
|
});
|
||||||
RED.nodes.eachWorkspace(function (ws) {
|
RED.nodes.eachWorkspace(function (ws) {
|
||||||
|
if (ws.changed || ws.added) {
|
||||||
|
ensureUnlocked(ws.z)
|
||||||
ws.changed = false;
|
ws.changed = false;
|
||||||
|
delete ws.added
|
||||||
|
RED.events.emit("flows:change", ws)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
flowsToLock.forEach(flow => {
|
||||||
|
flow.locked = true
|
||||||
|
})
|
||||||
// Once deployed, cannot undo back to a clean state
|
// Once deployed, cannot undo back to a clean state
|
||||||
RED.history.markAllDirty();
|
RED.history.markAllDirty();
|
||||||
RED.view.redraw();
|
RED.view.redraw();
|
||||||
|
@ -720,10 +720,13 @@ RED.editor = (function() {
|
|||||||
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
|
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
|
||||||
oldValues[d] = editing_node[d];
|
oldValues[d] = editing_node[d];
|
||||||
} else {
|
} else {
|
||||||
|
// Dont clone the group node `nodes` array
|
||||||
|
if (editing_node.type !== 'group' || d !== "nodes") {
|
||||||
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
|
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var rc = editing_node._def.oneditsave.call(editing_node);
|
var rc = editing_node._def.oneditsave.call(editing_node);
|
||||||
@ -862,6 +865,7 @@ RED.editor = (function() {
|
|||||||
function showEditDialog(node, defaultTab) {
|
function showEditDialog(node, defaultTab) {
|
||||||
if (buildingEditDialog) { return }
|
if (buildingEditDialog) { return }
|
||||||
buildingEditDialog = true;
|
buildingEditDialog = true;
|
||||||
|
if (node.z && RED.workspaces.isLocked(node.z)) { return }
|
||||||
var editing_node = node;
|
var editing_node = node;
|
||||||
var removeInfoEditorOnClose = false;
|
var removeInfoEditorOnClose = false;
|
||||||
var skipInfoRefreshOnClose = false;
|
var skipInfoRefreshOnClose = false;
|
||||||
@ -1047,6 +1051,13 @@ RED.editor = (function() {
|
|||||||
|
|
||||||
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
||||||
|
|
||||||
|
var helpButton = $('<button type="button" class="red-ui-button"><i class="fa fa-book"></button>').on("click", function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
RED.sidebar.help.show(editing_node.type);
|
||||||
|
}).appendTo(trayFooterLeft);
|
||||||
|
RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp"));
|
||||||
|
|
||||||
$('<input id="node-input-node-disabled" type="checkbox">').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({
|
$('<input id="node-input-node-disabled" type="checkbox">').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({
|
||||||
enabledIcon: "fa-circle-thin",
|
enabledIcon: "fa-circle-thin",
|
||||||
disabledIcon: "fa-ban",
|
disabledIcon: "fa-ban",
|
||||||
@ -1150,6 +1161,8 @@ RED.editor = (function() {
|
|||||||
var editing_config_node = RED.nodes.node(id);
|
var editing_config_node = RED.nodes.node(id);
|
||||||
var activeEditPanes = [];
|
var activeEditPanes = [];
|
||||||
|
|
||||||
|
if (editing_config_node && editing_config_node.z && RED.workspaces.isLocked(editing_config_node.z)) { return }
|
||||||
|
|
||||||
var configNodeScope = ""; // default to global
|
var configNodeScope = ""; // default to global
|
||||||
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
|
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
|
||||||
if (activeSubflow) {
|
if (activeSubflow) {
|
||||||
@ -1192,6 +1205,13 @@ RED.editor = (function() {
|
|||||||
|
|
||||||
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
||||||
|
|
||||||
|
var helpButton = $('<button type="button" class="red-ui-button"><i class="fa fa-book"></button>').on("click", function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
RED.sidebar.help.show(editing_config_node.type);
|
||||||
|
}).appendTo(trayFooterLeft);
|
||||||
|
RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp"));
|
||||||
|
|
||||||
$('<input id="node-config-input-node-disabled" type="checkbox">').prop("checked",!!editing_config_node.d).appendTo(trayFooterLeft).toggleButton({
|
$('<input id="node-config-input-node-disabled" type="checkbox">').prop("checked",!!editing_config_node.d).appendTo(trayFooterLeft).toggleButton({
|
||||||
enabledIcon: "fa-circle-thin",
|
enabledIcon: "fa-circle-thin",
|
||||||
disabledIcon: "fa-ban",
|
disabledIcon: "fa-ban",
|
||||||
@ -1696,6 +1716,7 @@ RED.editor = (function() {
|
|||||||
function showEditGroupDialog(group, defaultTab) {
|
function showEditGroupDialog(group, defaultTab) {
|
||||||
if (buildingEditDialog) { return }
|
if (buildingEditDialog) { return }
|
||||||
buildingEditDialog = true;
|
buildingEditDialog = true;
|
||||||
|
if (group.z && RED.workspaces.isLocked(group.z)) { return }
|
||||||
var editing_node = group;
|
var editing_node = group;
|
||||||
editStack.push(group);
|
editStack.push(group);
|
||||||
RED.view.state(RED.state.EDITING);
|
RED.view.state(RED.state.EDITING);
|
||||||
@ -1855,11 +1876,15 @@ RED.editor = (function() {
|
|||||||
workspace.disabled = disabled;
|
workspace.disabled = disabled;
|
||||||
|
|
||||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
||||||
if (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) {
|
if (editState.changed) {
|
||||||
var historyEvent = {
|
var historyEvent = {
|
||||||
t: "edit",
|
t: "edit",
|
||||||
@ -1900,6 +1925,7 @@ RED.editor = (function() {
|
|||||||
var trayBody = tray.find('.red-ui-tray-body');
|
var trayBody = tray.find('.red-ui-tray-body');
|
||||||
trayBody.parent().css('overflow','hidden');
|
trayBody.parent().css('overflow','hidden');
|
||||||
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
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 = [
|
var nodeEditPanes = [
|
||||||
'editor-tab-flow-properties',
|
'editor-tab-flow-properties',
|
||||||
@ -1914,6 +1940,18 @@ RED.editor = (function() {
|
|||||||
disabledIcon: "fa-ban",
|
disabledIcon: "fa-ban",
|
||||||
invertState: true
|
invertState: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!workspace.hasOwnProperty("locked")) {
|
||||||
|
workspace.locked = false;
|
||||||
|
}
|
||||||
|
$('<input id="node-input-locked" type="checkbox">').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({
|
||||||
|
enabledLabel: RED._("common.label.unlocked"),
|
||||||
|
enabledIcon: "fa-unlock-alt",
|
||||||
|
disabledLabel: RED._("common.label.locked"),
|
||||||
|
disabledIcon: "fa-lock",
|
||||||
|
invertState: true
|
||||||
|
})
|
||||||
|
|
||||||
prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) {
|
prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) {
|
||||||
activeEditPanes = _activeEditPanes;
|
activeEditPanes = _activeEditPanes;
|
||||||
trayBody.i18n();
|
trayBody.i18n();
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
selectedCodeEditor = RED.editor.codeEditor[defaultEditor];
|
selectedCodeEditor = RED.editor.codeEditor[defaultEditor];
|
||||||
initialised = selectedCodeEditor.init();
|
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) {
|
function create(options) {
|
||||||
@ -64,6 +67,7 @@
|
|||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var editor = null;
|
||||||
if (this.editor.type === MONACO) {
|
if (this.editor.type === MONACO) {
|
||||||
// compatibility (see above note)
|
// compatibility (see above note)
|
||||||
if (!options.element && !options.id) {
|
if (!options.element && !options.id) {
|
||||||
@ -74,10 +78,14 @@
|
|||||||
console.warn("createEditor() options.element or options.id is not valid", options);
|
console.warn("createEditor() options.element or options.id is not valid", options);
|
||||||
$("#dialog-form").append('<div id="' + options.id + '" style="display: none;" />');
|
$("#dialog-form").append('<div id="' + options.id + '" style="display: none;" />');
|
||||||
}
|
}
|
||||||
return this.editor.create(options);
|
editor = this.editor.create(options);
|
||||||
} else {
|
} 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 {
|
return {
|
||||||
|
@ -59,18 +59,21 @@ RED.editor.codeEditor.monaco = (function() {
|
|||||||
//TODO: get from externalModules.js For now this is enough for feature parity with ACE (and then some).
|
//TODO: get from externalModules.js For now this is enough for feature parity with ACE (and then some).
|
||||||
const knownModules = {
|
const knownModules = {
|
||||||
"assert": {package: "node", module: "assert", path: "node/assert.d.ts" },
|
"assert": {package: "node", module: "assert", path: "node/assert.d.ts" },
|
||||||
|
"assert/strict": {package: "node", module: "assert/strict", path: "node/assert/strict.d.ts" },
|
||||||
"async_hooks": {package: "node", module: "async_hooks", path: "node/async_hooks.d.ts" },
|
"async_hooks": {package: "node", module: "async_hooks", path: "node/async_hooks.d.ts" },
|
||||||
"buffer": {package: "node", module: "buffer", path: "node/buffer.d.ts" },
|
"buffer": {package: "node", module: "buffer", path: "node/buffer.d.ts" },
|
||||||
"child_process": {package: "node", module: "child_process", path: "node/child_process.d.ts" },
|
"child_process": {package: "node", module: "child_process", path: "node/child_process.d.ts" },
|
||||||
"cluster": {package: "node", module: "cluster", path: "node/cluster.d.ts" },
|
"cluster": {package: "node", module: "cluster", path: "node/cluster.d.ts" },
|
||||||
"console": {package: "node", module: "console", path: "node/console.d.ts" },
|
"console": {package: "node", module: "console", path: "node/console.d.ts" },
|
||||||
"constants": {package: "node", module: "constants", path: "node/constants.d.ts" },
|
|
||||||
"crypto": {package: "node", module: "crypto", path: "node/crypto.d.ts" },
|
"crypto": {package: "node", module: "crypto", path: "node/crypto.d.ts" },
|
||||||
"dgram": {package: "node", module: "dgram", path: "node/dgram.d.ts" },
|
"dgram": {package: "node", module: "dgram", path: "node/dgram.d.ts" },
|
||||||
|
"diagnostics_channel.d": {package: "node", module: "diagnostics_channel", path: "node/diagnostics_channel.d.ts" },
|
||||||
"dns": {package: "node", module: "dns", path: "node/dns.d.ts" },
|
"dns": {package: "node", module: "dns", path: "node/dns.d.ts" },
|
||||||
|
"dns/promises": {package: "node", module: "dns/promises", path: "node/dns/promises.d.ts" },
|
||||||
"domain": {package: "node", module: "domain", path: "node/domain.d.ts" },
|
"domain": {package: "node", module: "domain", path: "node/domain.d.ts" },
|
||||||
"events": {package: "node", module: "events", path: "node/events.d.ts" },
|
"events": {package: "node", module: "events", path: "node/events.d.ts" },
|
||||||
"fs": {package: "node", module: "fs", path: "node/fs.d.ts" },
|
"fs": {package: "node", module: "fs", path: "node/fs.d.ts" },
|
||||||
|
"fs/promises": {package: "node", module: "fs/promises", path: "node/fs/promises.d.ts" },
|
||||||
"globals": {package: "node", module: "globals", path: "node/globals.d.ts" },
|
"globals": {package: "node", module: "globals", path: "node/globals.d.ts" },
|
||||||
"http": {package: "node", module: "http", path: "node/http.d.ts" },
|
"http": {package: "node", module: "http", path: "node/http.d.ts" },
|
||||||
"http2": {package: "node", module: "http2", path: "node/http2.d.ts" },
|
"http2": {package: "node", module: "http2", path: "node/http2.d.ts" },
|
||||||
@ -84,8 +87,13 @@ RED.editor.codeEditor.monaco = (function() {
|
|||||||
"querystring": {package: "node", module: "querystring", path: "node/querystring.d.ts" },
|
"querystring": {package: "node", module: "querystring", path: "node/querystring.d.ts" },
|
||||||
"readline": {package: "node", module: "readline", path: "node/readline.d.ts" },
|
"readline": {package: "node", module: "readline", path: "node/readline.d.ts" },
|
||||||
"stream": {package: "node", module: "stream", path: "node/stream.d.ts" },
|
"stream": {package: "node", module: "stream", path: "node/stream.d.ts" },
|
||||||
|
"stream/consumers": {package: "node", module: "stream/consumers", path: "node/stream/consumers.d.ts" },
|
||||||
|
"stream/promises": {package: "node", module: "stream/promises", path: "node/stream/promises.d.ts" },
|
||||||
|
"stream/web": {package: "node", module: "stream/web", path: "node/stream/web.d.ts" },
|
||||||
"string_decoder": {package: "node", module: "string_decoder", path: "node/string_decoder.d.ts" },
|
"string_decoder": {package: "node", module: "string_decoder", path: "node/string_decoder.d.ts" },
|
||||||
|
"test": {package: "node", module: "test", path: "node/test.d.ts" },
|
||||||
"timers": {package: "node", module: "timers", path: "node/timers.d.ts" },
|
"timers": {package: "node", module: "timers", path: "node/timers.d.ts" },
|
||||||
|
"timers/promises": {package: "node", module: "timers/promises", path: "node/timers/promises.d.ts" },
|
||||||
"tls": {package: "node", module: "tls", path: "node/tls.d.ts" },
|
"tls": {package: "node", module: "tls", path: "node/tls.d.ts" },
|
||||||
"trace_events": {package: "node", module: "trace_events", path: "node/trace_events.d.ts" },
|
"trace_events": {package: "node", module: "trace_events", path: "node/trace_events.d.ts" },
|
||||||
"tty": {package: "node", module: "tty", path: "node/tty.d.ts" },
|
"tty": {package: "node", module: "tty", path: "node/tty.d.ts" },
|
||||||
@ -100,7 +108,7 @@ RED.editor.codeEditor.monaco = (function() {
|
|||||||
"node-red-util": {package: "node-red", module: "util", path: "node-red/util.d.ts" },
|
"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" },
|
"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"] , knownModules["util"] ];
|
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"], knownModules["timers"] , knownModules["util"] ];
|
||||||
|
|
||||||
const modulesCache = {};
|
const modulesCache = {};
|
||||||
|
|
||||||
@ -1160,19 +1168,19 @@ RED.editor.codeEditor.monaco = (function() {
|
|||||||
// Warning: 4
|
// Warning: 4
|
||||||
// Error: 8
|
// Error: 8
|
||||||
ed.getAnnotations = function getAnnotations() {
|
ed.getAnnotations = function getAnnotations() {
|
||||||
var aceCompatibleMarkers = [];
|
let aceCompatibleMarkers;
|
||||||
try {
|
try {
|
||||||
var _model = ed.getModel();
|
const _model = ed.getModel();
|
||||||
if (_model !== null) {
|
if (_model !== null) {
|
||||||
var id = _model._languageId; // e.g. javascript
|
const id = _model.getLanguageId(); // e.g. javascript
|
||||||
var ra = _model._associatedResource.authority; //e.g. model
|
const ra = _model.uri.authority; // e.g. model
|
||||||
var rp = _model._associatedResource.path; //e.g. /18
|
const rp = _model.uri.path; // e.g. /18
|
||||||
var rs = _model._associatedResource.scheme; //e.g. inmemory
|
const rs = _model.uri.scheme; // e.g. inmemory
|
||||||
var modelMarkers = monaco.editor.getModelMarkers(_model) || [];
|
const modelMarkers = monaco.editor.getModelMarkers(_model) || [];
|
||||||
var thisEditorsMarkers = modelMarkers.filter(function (marker) {
|
const thisEditorsMarkers = modelMarkers.filter(function (marker) {
|
||||||
var _ra = marker.resource.authority; //e.g. model
|
const _ra = marker.resource.authority; // e.g. model
|
||||||
var _rp = marker.resource.path; //e.g. /18
|
const _rp = marker.resource.path; // e.g. /18
|
||||||
var _rs = marker.resource.scheme; //e.g. inmemory
|
const _rs = marker.resource.scheme; // e.g. inmemory
|
||||||
return marker.owner == id && _ra === ra && _rp === rp && _rs === rs;
|
return marker.owner == id && _ra === ra && _rp === rp && _rs === rs;
|
||||||
})
|
})
|
||||||
aceCompatibleMarkers = thisEditorsMarkers.map(function (marker) {
|
aceCompatibleMarkers = thisEditorsMarkers.map(function (marker) {
|
||||||
|
@ -2,7 +2,7 @@ RED.editor.envVarList = (function() {
|
|||||||
|
|
||||||
var currentLocale = 'en-US';
|
var currentLocale = 'en-US';
|
||||||
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
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
|
* Create env var edit interface
|
||||||
|
@ -294,7 +294,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var result = expr.evaluate(legacyMode?{msg:parsedData}:parsedData);
|
expr.evaluate(legacyMode?{msg:parsedData}:parsedData, null, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
testResultEditor.setValue(RED._("expressionEditor.errors.eval",{message:err.message}),-1);
|
||||||
|
} else {
|
||||||
if (usesContext) {
|
if (usesContext) {
|
||||||
testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
|
testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
|
||||||
return;
|
return;
|
||||||
@ -319,6 +322,8 @@
|
|||||||
formattedResult = RED._("expressionEditor.noMatch");
|
formattedResult = RED._("expressionEditor.noMatch");
|
||||||
}
|
}
|
||||||
testResultEditor.setValue(formattedResult,-1);
|
testResultEditor.setValue(formattedResult,-1);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
testResultEditor.setValue(RED._("expressionEditor.errors.eval",{message:err.message}),-1);
|
testResultEditor.setValue(RED._("expressionEditor.errors.eval",{message:err.message}),-1);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,61 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
(function() {
|
(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">'+
|
var toolbarTemplate = '<div style="margin-bottom: 5px">'+
|
||||||
'<span class="button-group">'+
|
'<span class="button-group">'+
|
||||||
@ -114,6 +169,7 @@
|
|||||||
var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop();
|
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").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
|
||||||
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
|
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
|
||||||
|
mermaid.init();
|
||||||
},200);
|
},200);
|
||||||
})
|
})
|
||||||
if (options.header) {
|
if (options.header) {
|
||||||
@ -122,6 +178,7 @@
|
|||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
|
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
|
||||||
|
mermaid.init();
|
||||||
}
|
}
|
||||||
panels = RED.panels.create({
|
panels = RED.panels.create({
|
||||||
id:"red-ui-editor-type-markdown-panels",
|
id:"red-ui-editor-type-markdown-panels",
|
||||||
@ -148,10 +205,14 @@
|
|||||||
});
|
});
|
||||||
RED.popover.tooltip($("#node-btn-markdown-preview"), RED._("markdownEditor.toggle-preview"));
|
RED.popover.tooltip($("#node-btn-markdown-preview"), RED._("markdownEditor.toggle-preview"));
|
||||||
|
|
||||||
if (options.cursor && !expressionEditor._initState) {
|
if(!expressionEditor._initState) {
|
||||||
|
if (options.cursor) {
|
||||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
expressionEditor.gotoLine(0, 0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
dialogForm.i18n();
|
dialogForm.i18n();
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
@ -215,6 +276,10 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return toolbar;
|
return toolbar;
|
||||||
|
},
|
||||||
|
postInit: function (editor, options) {
|
||||||
|
var elem = $("#"+options.id);
|
||||||
|
initImageDrag(elem, editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RED.editor.registerTypeEditor("_markdown", definition);
|
RED.editor.registerTypeEditor("_markdown", definition);
|
||||||
|
@ -52,8 +52,6 @@
|
|||||||
node.info = info;
|
node.info = info;
|
||||||
}
|
}
|
||||||
$("#red-ui-tab-"+(node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!node.disabled);
|
$("#red-ui-tab-"+(node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!node.disabled);
|
||||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!node.disabled);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
189
packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
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 (!gconf && list.editableList('length') === 0) {
|
||||||
|
// No existing global-config node and nothing in the list,
|
||||||
|
// so no need to do anything more
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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 (!gconf.credentials) {
|
||||||
|
gconf.credentials = {
|
||||||
|
_ : {},
|
||||||
|
map: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RED.actions.add("core:show-global-env", function() {
|
||||||
|
RED.userSettings.show('envvar');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -188,6 +188,8 @@ RED.group = (function() {
|
|||||||
var activateMerge = false;
|
var activateMerge = false;
|
||||||
var activateRemove = false;
|
var activateRemove = false;
|
||||||
var singleGroupSelected = false;
|
var singleGroupSelected = false;
|
||||||
|
var locked = RED.workspaces.isLocked()
|
||||||
|
|
||||||
if (activateGroup) {
|
if (activateGroup) {
|
||||||
singleGroupSelected = selection.nodes.length === 1 && selection.nodes[0].type === 'group';
|
singleGroupSelected = selection.nodes.length === 1 && selection.nodes[0].type === 'group';
|
||||||
selection.nodes.forEach(function (n) {
|
selection.nodes.forEach(function (n) {
|
||||||
@ -202,12 +204,12 @@ RED.group = (function() {
|
|||||||
activateMerge = (selection.nodes.length > 1);
|
activateMerge = (selection.nodes.length > 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RED.menu.setDisabled("menu-item-group-group", !activateGroup);
|
RED.menu.setDisabled("menu-item-group-group", locked || !activateGroup);
|
||||||
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
|
RED.menu.setDisabled("menu-item-group-ungroup", locked || !activateUngroup);
|
||||||
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
|
RED.menu.setDisabled("menu-item-group-merge", locked || !activateMerge);
|
||||||
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
|
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-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() })
|
RED.actions.add("core:group-selection", function() { groupSelection() })
|
||||||
@ -264,6 +266,7 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function pasteGroupStyle() {
|
function pasteGroupStyle() {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||||
if (groupStyleClipboard) {
|
if (groupStyleClipboard) {
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
@ -298,6 +301,7 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function groupSelection() {
|
function groupSelection() {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
@ -316,11 +320,12 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function ungroupSelection() {
|
function ungroupSelection() {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var newSelection = [];
|
var newSelection = [];
|
||||||
groups = selection.nodes.filter(function(n) { return n.type === "group" });
|
let groups = selection.nodes.filter(function(n) { return n.type === "group" });
|
||||||
|
|
||||||
var historyEvent = {
|
var historyEvent = {
|
||||||
t:"ungroup",
|
t:"ungroup",
|
||||||
@ -339,6 +344,7 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ungroup(g) {
|
function ungroup(g) {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
var parentGroup = RED.nodes.group(g.g);
|
var parentGroup = RED.nodes.group(g.g);
|
||||||
g.nodes.forEach(function(n) {
|
g.nodes.forEach(function(n) {
|
||||||
@ -365,6 +371,7 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mergeSelection() {
|
function mergeSelection() {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
@ -394,7 +401,7 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var existingGroup;
|
var existingGroup;
|
||||||
|
var mergedEnv = {}
|
||||||
// Second pass, ungroup any groups in the selection and add their contents
|
// Second pass, ungroup any groups in the selection and add their contents
|
||||||
// to the selection
|
// to the selection
|
||||||
for (var i=0; i<selection.nodes.length; i++) {
|
for (var i=0; i<selection.nodes.length; i++) {
|
||||||
@ -403,6 +410,11 @@ RED.group = (function() {
|
|||||||
if (!existingGroup) {
|
if (!existingGroup) {
|
||||||
existingGroup = n;
|
existingGroup = n;
|
||||||
}
|
}
|
||||||
|
if (n.env && n.env.length > 0) {
|
||||||
|
n.env.forEach(env => {
|
||||||
|
mergedEnv[env.name] = env
|
||||||
|
})
|
||||||
|
}
|
||||||
ungroupHistoryEvent.groups.push(n);
|
ungroupHistoryEvent.groups.push(n);
|
||||||
nodes = nodes.concat(ungroup(n));
|
nodes = nodes.concat(ungroup(n));
|
||||||
} else {
|
} else {
|
||||||
@ -420,6 +432,7 @@ RED.group = (function() {
|
|||||||
group.style = existingGroup.style;
|
group.style = existingGroup.style;
|
||||||
group.name = existingGroup.name;
|
group.name = existingGroup.name;
|
||||||
}
|
}
|
||||||
|
group.env = Object.values(mergedEnv)
|
||||||
RED.view.select({nodes:[group]})
|
RED.view.select({nodes:[group]})
|
||||||
}
|
}
|
||||||
historyEvent.events.push({
|
historyEvent.events.push({
|
||||||
@ -434,6 +447,7 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeSelection() {
|
function removeSelection() {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
@ -461,13 +475,22 @@ RED.group = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createGroup(nodes) {
|
function createGroup(nodes) {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (nodes.length === 0) {
|
if (nodes.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nodes.filter(function(n) { return n.type === "subflow" }).length > 0) {
|
const existingGroup = nodes[0].g
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
const n = nodes[i]
|
||||||
|
if (n.type === 'subflow') {
|
||||||
RED.notify(RED._("group.errors.cannotAddSubflowPorts"),"error");
|
RED.notify(RED._("group.errors.cannotAddSubflowPorts"),"error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (n.g !== existingGroup) {
|
||||||
|
console.warn("Cannot add nooes with different z properties")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// nodes is an array
|
// nodes is an array
|
||||||
// each node must be on the same tab (z)
|
// each node must be on the same tab (z)
|
||||||
var group = {
|
var group = {
|
||||||
@ -479,11 +502,16 @@ RED.group = (function() {
|
|||||||
y: Number.POSITIVE_INFINITY,
|
y: Number.POSITIVE_INFINITY,
|
||||||
w: 0,
|
w: 0,
|
||||||
h: 0,
|
h: 0,
|
||||||
_def: RED.group.def
|
_def: RED.group.def,
|
||||||
|
changed: true
|
||||||
}
|
}
|
||||||
|
|
||||||
group.z = nodes[0].z;
|
group.z = nodes[0].z;
|
||||||
RED.nodes.addGroup(group);
|
group = RED.nodes.addGroup(group);
|
||||||
|
|
||||||
|
if (existingGroup) {
|
||||||
|
addToGroup(RED.nodes.group(existingGroup), group)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addToGroup(group,nodes);
|
addToGroup(group,nodes);
|
||||||
@ -508,7 +536,7 @@ RED.group = (function() {
|
|||||||
if (!z) {
|
if (!z) {
|
||||||
z = n.z;
|
z = n.z;
|
||||||
} else if (z !== n.z) {
|
} else if (z !== n.z) {
|
||||||
throw new Error("Cannot add nooes with different z properties")
|
throw new Error("Cannot add nodes with different z properties")
|
||||||
}
|
}
|
||||||
if (n.g) {
|
if (n.g) {
|
||||||
// This is already in a group.
|
// This is already in a group.
|
||||||
@ -525,14 +553,10 @@ RED.group = (function() {
|
|||||||
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
|
throw new Error(RED._("group.errors.cannotCreateDiffGroups"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The nodes are already in a group. The assumption is they should be
|
// The nodes are already in a group - so we need to remove them first
|
||||||
// wrapped in the newly provided group, and that group added to in their
|
|
||||||
// place to the existing containing group.
|
|
||||||
if (g) {
|
if (g) {
|
||||||
g = RED.nodes.group(g);
|
g = RED.nodes.group(g);
|
||||||
g.nodes.push(group);
|
|
||||||
g.dirty = true;
|
g.dirty = true;
|
||||||
group.g = g.id;
|
|
||||||
}
|
}
|
||||||
// Second pass - add them to the group
|
// Second pass - add them to the group
|
||||||
for (i=0;i<nodes.length;i++) {
|
for (i=0;i<nodes.length;i++) {
|
||||||
@ -566,6 +590,7 @@ RED.group = (function() {
|
|||||||
markDirty(group);
|
markDirty(group);
|
||||||
}
|
}
|
||||||
function removeFromGroup(group, nodes, reparent) {
|
function removeFromGroup(group, nodes, reparent) {
|
||||||
|
if (RED.workspaces.isLocked()) { return }
|
||||||
if (!Array.isArray(nodes)) {
|
if (!Array.isArray(nodes)) {
|
||||||
nodes = [nodes];
|
nodes = [nodes];
|
||||||
}
|
}
|
||||||
@ -583,7 +608,7 @@ RED.group = (function() {
|
|||||||
n.dirty = true;
|
n.dirty = true;
|
||||||
var index = group.nodes.indexOf(n);
|
var index = group.nodes.indexOf(n);
|
||||||
group.nodes.splice(index,1);
|
group.nodes.splice(index,1);
|
||||||
if (reparent && group.g) {
|
if (reparent && parentGroup) {
|
||||||
n.g = group.g
|
n.g = group.g
|
||||||
parentGroup.nodes.push(n);
|
parentGroup.nodes.push(n);
|
||||||
} else {
|
} else {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
})();
|
@ -16,15 +16,17 @@
|
|||||||
RED.palette.editor = (function() {
|
RED.palette.editor = (function() {
|
||||||
|
|
||||||
var disabled = false;
|
var disabled = false;
|
||||||
|
let catalogues = []
|
||||||
|
const loadedCatalogs = []
|
||||||
var editorTabs;
|
var editorTabs;
|
||||||
var filterInput;
|
let filterInput;
|
||||||
var searchInput;
|
let searchInput;
|
||||||
var nodeList;
|
let nodeList;
|
||||||
var packageList;
|
let packageList;
|
||||||
var loadedList = [];
|
let fullList = []
|
||||||
var filteredList = [];
|
let loadedList = [];
|
||||||
var loadedIndex = {};
|
let filteredList = [];
|
||||||
|
let loadedIndex = {};
|
||||||
|
|
||||||
var typesInUse = {};
|
var typesInUse = {};
|
||||||
var nodeEntries = {};
|
var nodeEntries = {};
|
||||||
@ -162,7 +164,6 @@ RED.palette.editor = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getContrastingBorder(rgbColor){
|
function getContrastingBorder(rgbColor){
|
||||||
var parts = /^rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)[,)]/.exec(rgbColor);
|
var parts = /^rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)[,)]/.exec(rgbColor);
|
||||||
if (parts) {
|
if (parts) {
|
||||||
@ -369,10 +370,10 @@ RED.palette.editor = (function() {
|
|||||||
var activeSort = sortModulesRelevance;
|
var activeSort = sortModulesRelevance;
|
||||||
|
|
||||||
function handleCatalogResponse(err,catalog,index,v) {
|
function handleCatalogResponse(err,catalog,index,v) {
|
||||||
|
const url = catalog.url
|
||||||
catalogueLoadStatus.push(err||v);
|
catalogueLoadStatus.push(err||v);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (v.modules) {
|
if (v.modules) {
|
||||||
var a = false;
|
|
||||||
v.modules = v.modules.filter(function(m) {
|
v.modules = v.modules.filter(function(m) {
|
||||||
if (RED.utils.checkModuleAllowed(m.id,m.version,installAllowList,installDenyList)) {
|
if (RED.utils.checkModuleAllowed(m.id,m.version,installAllowList,installDenyList)) {
|
||||||
loadedIndex[m.id] = m;
|
loadedIndex[m.id] = m;
|
||||||
@ -389,13 +390,14 @@ RED.palette.editor = (function() {
|
|||||||
m.timestamp = 0;
|
m.timestamp = 0;
|
||||||
}
|
}
|
||||||
m.index = m.index.join(",").toLowerCase();
|
m.index = m.index.join(",").toLowerCase();
|
||||||
|
m.catalog = catalog;
|
||||||
|
m.catalogIndex = index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
loadedList = loadedList.concat(v.modules);
|
loadedList = loadedList.concat(v.modules);
|
||||||
}
|
}
|
||||||
searchInput.searchBox('count',loadedList.length);
|
|
||||||
} else {
|
} else {
|
||||||
catalogueLoadErrors = true;
|
catalogueLoadErrors = true;
|
||||||
}
|
}
|
||||||
@ -404,7 +406,7 @@ RED.palette.editor = (function() {
|
|||||||
}
|
}
|
||||||
if (catalogueLoadStatus.length === catalogueCount) {
|
if (catalogueLoadStatus.length === catalogueCount) {
|
||||||
if (catalogueLoadErrors) {
|
if (catalogueLoadErrors) {
|
||||||
RED.notify(RED._('palette.editor.errors.catalogLoadFailed',{url: catalog}),"error",false,8000);
|
RED.notify(RED._('palette.editor.errors.catalogLoadFailed',{url: url}),"error",false,8000);
|
||||||
}
|
}
|
||||||
var delta = 250-(Date.now() - catalogueLoadStart);
|
var delta = 250-(Date.now() - catalogueLoadStart);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
@ -416,12 +418,13 @@ RED.palette.editor = (function() {
|
|||||||
|
|
||||||
function initInstallTab() {
|
function initInstallTab() {
|
||||||
if (loadedList.length === 0) {
|
if (loadedList.length === 0) {
|
||||||
|
fullList = [];
|
||||||
loadedList = [];
|
loadedList = [];
|
||||||
loadedIndex = {};
|
loadedIndex = {};
|
||||||
packageList.editableList('empty');
|
packageList.editableList('empty');
|
||||||
|
|
||||||
$(".red-ui-palette-module-shade-status").text(RED._('palette.editor.loading'));
|
$(".red-ui-palette-module-shade-status").text(RED._('palette.editor.loading'));
|
||||||
var catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json'];
|
|
||||||
catalogueLoadStatus = [];
|
catalogueLoadStatus = [];
|
||||||
catalogueLoadErrors = false;
|
catalogueLoadErrors = false;
|
||||||
catalogueCount = catalogues.length;
|
catalogueCount = catalogues.length;
|
||||||
@ -431,27 +434,97 @@ RED.palette.editor = (function() {
|
|||||||
$("#red-ui-palette-module-install-shade").show();
|
$("#red-ui-palette-module-install-shade").show();
|
||||||
catalogueLoadStart = Date.now();
|
catalogueLoadStart = Date.now();
|
||||||
var handled = 0;
|
var handled = 0;
|
||||||
catalogues.forEach(function(catalog,index) {
|
loadedCatalogs.length = 0; // clear the loadedCatalogs array
|
||||||
$.getJSON(catalog, {_: new Date().getTime()},function(v) {
|
for (let index = 0; index < catalogues.length; index++) {
|
||||||
handleCatalogResponse(null,catalog,index,v);
|
const url = catalogues[index];
|
||||||
|
$.getJSON(url, {_: new Date().getTime()},function(v) {
|
||||||
|
loadedCatalogs.push({ index: index, url: url, name: v.name, updated_at: v.updated_at, modules_count: (v.modules || []).length })
|
||||||
|
handleCatalogResponse(null,{ url: url, name: v.name},index,v);
|
||||||
refreshNodeModuleList();
|
refreshNodeModuleList();
|
||||||
}).fail(function(jqxhr, textStatus, error) {
|
}).fail(function(jqxhr, textStatus, error) {
|
||||||
console.warn("Error loading catalog",catalog,":",error);
|
console.warn("Error loading catalog",url,":",error);
|
||||||
handleCatalogResponse(jqxhr,catalog,index);
|
handleCatalogResponse(jqxhr,url,index);
|
||||||
}).always(function() {
|
}).always(function() {
|
||||||
handled++;
|
handled++;
|
||||||
if (handled === catalogueCount) {
|
if (handled === catalogueCount) {
|
||||||
searchInput.searchBox('change');
|
//sort loadedCatalogs by e.index ascending
|
||||||
|
loadedCatalogs.sort((a, b) => a.index - b.index)
|
||||||
|
updateCatalogFilter(loadedCatalogs)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the catalog filter dropdown and updates local variables
|
||||||
|
* @param {[{url:String, name:String, updated_at:String, modules_count:Number}]} catalogEntries
|
||||||
|
*/
|
||||||
|
function updateCatalogFilter(catalogEntries, maxRetry = 3) {
|
||||||
|
// clean up existing filters
|
||||||
|
const catalogSelection = $('#red-catalogue-filter-select')
|
||||||
|
if (catalogSelection.length === 0) {
|
||||||
|
// sidebar not yet loaded (red-catalogue-filter-select is not in dom)
|
||||||
|
if (maxRetry > 0) {
|
||||||
|
// console.log("updateCatalogFilter: sidebar not yet loaded, retrying in 100ms")
|
||||||
|
// try again in 100ms
|
||||||
|
setTimeout(() => {
|
||||||
|
updateCatalogFilter(catalogEntries, maxRetry - 1)
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return; // give up
|
||||||
|
}
|
||||||
|
catalogSelection.off("change") // remove any existing event handlers
|
||||||
|
catalogSelection.attr('disabled', 'disabled')
|
||||||
|
catalogSelection.empty()
|
||||||
|
catalogSelection.append($('<option>', { value: "loading", text: RED._('palette.editor.loading'), disabled: true, selected: true }));
|
||||||
|
|
||||||
|
fullList = loadedList.slice()
|
||||||
|
catalogSelection.empty() // clear the select list
|
||||||
|
|
||||||
|
// loop through catalogTypes, and an option entry per catalog
|
||||||
|
for (let index = 0; index < catalogEntries.length; index++) {
|
||||||
|
const catalog = catalogEntries[index];
|
||||||
|
catalogSelection.append(`<option value="${catalog.name}">${catalog.name}</option>`)
|
||||||
|
}
|
||||||
|
// select the 1st option in the select list
|
||||||
|
catalogSelection.val(catalogSelection.find('option:first').val())
|
||||||
|
|
||||||
|
// if there is only 1 catalog, hide the select
|
||||||
|
if (catalogEntries.length > 1) {
|
||||||
|
catalogSelection.prepend(`<option value="all">${RED._('palette.editor.allCatalogs')}</option>`)
|
||||||
|
catalogSelection.val('all')
|
||||||
|
catalogSelection.removeAttr('disabled') // permit the user to select a catalog
|
||||||
|
}
|
||||||
|
// refresh the searchInput counter and trigger a change
|
||||||
|
filterByCatalog(catalogSelection.val())
|
||||||
|
searchInput.searchBox('change');
|
||||||
|
|
||||||
|
// hook up the change event handler
|
||||||
|
catalogSelection.on("change", function() {
|
||||||
|
const selectedCatalog = $(this).val();
|
||||||
|
filterByCatalog(selectedCatalog);
|
||||||
|
searchInput.searchBox('change');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterByCatalog(selectedCatalog) {
|
||||||
|
if (loadedCatalogs.length <= 1 || selectedCatalog === "all") {
|
||||||
|
loadedList = fullList.slice();
|
||||||
|
} else {
|
||||||
|
loadedList = fullList.filter(function(m) {
|
||||||
|
return (m.catalog.name === selectedCatalog);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
refreshFilteredItems();
|
||||||
|
searchInput.searchBox('count',filteredList.length+" / "+loadedList.length);
|
||||||
|
}
|
||||||
|
|
||||||
function refreshFilteredItems() {
|
function refreshFilteredItems() {
|
||||||
packageList.editableList('empty');
|
packageList.editableList('empty');
|
||||||
var currentFilter = searchInput.searchBox('value').trim();
|
var currentFilter = searchInput.searchBox('value').trim();
|
||||||
if (currentFilter === ""){
|
if (currentFilter === "" && loadedList.length > 20){
|
||||||
packageList.editableList('addItem',{count:loadedList.length})
|
packageList.editableList('addItem',{count:loadedList.length})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -462,7 +535,6 @@ RED.palette.editor = (function() {
|
|||||||
if (filteredList.length === 0) {
|
if (filteredList.length === 0) {
|
||||||
packageList.editableList('addItem',{});
|
packageList.editableList('addItem',{});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filteredList.length > 10) {
|
if (filteredList.length > 10) {
|
||||||
packageList.editableList('addItem',{start:10,more:filteredList.length-10})
|
packageList.editableList('addItem',{start:10,more:filteredList.length-10})
|
||||||
}
|
}
|
||||||
@ -492,6 +564,7 @@ RED.palette.editor = (function() {
|
|||||||
var updateDenyList = [];
|
var updateDenyList = [];
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json']
|
||||||
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
|
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -669,7 +742,8 @@ RED.palette.editor = (function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
nodeList = $('<ol>',{id:"red-ui-palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(modulesTab).editableList({
|
nodeList = $('<ol>',{id:"red-ui-palette-module-list"}).appendTo(modulesTab).editableList({
|
||||||
|
class: "scrollable",
|
||||||
addButton: false,
|
addButton: false,
|
||||||
scrollOnAdd: false,
|
scrollOnAdd: false,
|
||||||
sort: function(A,B) {
|
sort: function(A,B) {
|
||||||
@ -800,28 +874,27 @@ RED.palette.editor = (function() {
|
|||||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function createInstallTab(content) {
|
function createInstallTab(content) {
|
||||||
var installTab = $('<div>',{class:"red-ui-palette-editor-tab hide"}).appendTo(content);
|
const installTab = $('<div>',{class:"red-ui-palette-editor-tab", style: "display: none;"}).appendTo(content);
|
||||||
|
|
||||||
editorTabs.addTab({
|
editorTabs.addTab({
|
||||||
id: 'install',
|
id: 'install',
|
||||||
label: RED._('palette.editor.tab-install'),
|
label: RED._('palette.editor.tab-install'),
|
||||||
content: installTab
|
content: installTab
|
||||||
})
|
})
|
||||||
|
|
||||||
var toolBar = $('<div>',{class:"red-ui-palette-editor-toolbar"}).appendTo(installTab);
|
const toolBar = $('<div>',{class:"red-ui-palette-editor-toolbar"}).appendTo(installTab);
|
||||||
|
|
||||||
var searchDiv = $('<div>',{class:"red-ui-palette-search"}).appendTo(installTab);
|
const searchDiv = $('<div>',{class:"red-ui-palette-search"}).appendTo(installTab);
|
||||||
searchInput = $('<input type="text" data-i18n="[placeholder]palette.search"></input>')
|
searchInput = $('<input type="text" data-i18n="[placeholder]palette.search"></input>')
|
||||||
.appendTo(searchDiv)
|
.appendTo(searchDiv)
|
||||||
.searchBox({
|
.searchBox({
|
||||||
delay: 300,
|
delay: 300,
|
||||||
change: function() {
|
change: function() {
|
||||||
var searchTerm = $(this).val().trim().toLowerCase();
|
var searchTerm = $(this).val().trim().toLowerCase();
|
||||||
if (searchTerm.length > 0) {
|
if (searchTerm.length > 0 || loadedList.length < 20) {
|
||||||
filteredList = loadedList.filter(function(m) {
|
filteredList = loadedList.filter(function(m) {
|
||||||
return (m.index.indexOf(searchTerm) > -1);
|
return (m.index.indexOf(searchTerm) > -1);
|
||||||
}).map(function(f) { return {info:f}});
|
}).map(function(f) { return {info:f}});
|
||||||
@ -831,19 +904,26 @@ RED.palette.editor = (function() {
|
|||||||
searchInput.searchBox('count',loadedList.length);
|
searchInput.searchBox('count',loadedList.length);
|
||||||
packageList.editableList('empty');
|
packageList.editableList('empty');
|
||||||
packageList.editableList('addItem',{count:loadedList.length});
|
packageList.editableList('addItem',{count:loadedList.length});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('<span>').text(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
const catalogSelection = $('<select id="red-catalogue-filter-select">').appendTo(toolBar);
|
||||||
var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar);
|
catalogSelection.addClass('red-ui-palette-editor-catalogue-filter');
|
||||||
var sortRelevance = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle selected"><i class="fa fa-sort-amount-desc"></i></a>').appendTo(sortGroup);
|
|
||||||
var sortAZ = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup);
|
const toolBarActions = $('<div>',{class:"red-ui-palette-editor-toolbar-actions"}).appendTo(toolBar);
|
||||||
var sortRecent = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup);
|
|
||||||
|
$('<span>').text(RED._("palette.editor.sort")+' ').appendTo(toolBarActions);
|
||||||
|
const sortGroup = $('<span class="button-group"></span>').appendTo(toolBarActions);
|
||||||
|
const sortRelevance = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle selected"><i class="fa fa-sort-amount-desc"></i></a>').appendTo(sortGroup);
|
||||||
|
const sortAZ = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle"><i class="fa fa-sort-alpha-asc"></i></a>').appendTo(sortGroup);
|
||||||
|
const sortRecent = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle"><i class="fa fa-calendar"></i></a>').appendTo(sortGroup);
|
||||||
|
RED.popover.tooltip(sortRelevance,RED._("palette.editor.sortRelevance"));
|
||||||
|
RED.popover.tooltip(sortAZ,RED._("palette.editor.sortAZ"));
|
||||||
|
RED.popover.tooltip(sortRecent,RED._("palette.editor.sortRecent"));
|
||||||
|
|
||||||
|
|
||||||
var sortOpts = [
|
const sortOpts = [
|
||||||
{button: sortRelevance, func: sortModulesRelevance},
|
{button: sortRelevance, func: sortModulesRelevance},
|
||||||
{button: sortAZ, func: sortModulesAZ},
|
{button: sortAZ, func: sortModulesAZ},
|
||||||
{button: sortRecent, func: sortModulesRecent}
|
{button: sortRecent, func: sortModulesRecent}
|
||||||
@ -861,7 +941,7 @@ RED.palette.editor = (function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var refreshSpan = $('<span>').appendTo(toolBar);
|
var refreshSpan = $('<span>').appendTo(toolBarActions);
|
||||||
var refreshButton = $('<a href="#" class="red-ui-sidebar-header-button"><i class="fa fa-refresh"></i></a>').appendTo(refreshSpan);
|
var refreshButton = $('<a href="#" class="red-ui-sidebar-header-button"><i class="fa fa-refresh"></i></a>').appendTo(refreshSpan);
|
||||||
refreshButton.on("click", function(e) {
|
refreshButton.on("click", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -871,7 +951,8 @@ RED.palette.editor = (function() {
|
|||||||
})
|
})
|
||||||
RED.popover.tooltip(refreshButton,RED._("palette.editor.refresh"));
|
RED.popover.tooltip(refreshButton,RED._("palette.editor.refresh"));
|
||||||
|
|
||||||
packageList = $('<ol>',{style:"position: absolute;top: 79px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
|
packageList = $('<ol>').appendTo(installTab).editableList({
|
||||||
|
class: "scrollable",
|
||||||
addButton: false,
|
addButton: false,
|
||||||
scrollOnAdd: false,
|
scrollOnAdd: false,
|
||||||
addItem: function(container,i,object) {
|
addItem: function(container,i,object) {
|
||||||
@ -906,6 +987,9 @@ RED.palette.editor = (function() {
|
|||||||
var metaRow = $('<div class="red-ui-palette-module-meta"></div>').appendTo(headerRow);
|
var metaRow = $('<div class="red-ui-palette-module-meta"></div>').appendTo(headerRow);
|
||||||
$('<span class="red-ui-palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
|
$('<span class="red-ui-palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
|
||||||
$('<span class="red-ui-palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
|
$('<span class="red-ui-palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
|
||||||
|
if (loadedCatalogs.length > 1) {
|
||||||
|
$('<span class="red-ui-palette-module-updated"><i class="fa fa-cubes"></i>' + (entry.catalog.name || entry.catalog.url) + '</span>').appendTo(metaRow);
|
||||||
|
}
|
||||||
|
|
||||||
var duplicateType = false;
|
var duplicateType = false;
|
||||||
if (entry.types && entry.types.length > 0) {
|
if (entry.types && entry.types.length > 0) {
|
||||||
@ -953,8 +1037,9 @@ RED.palette.editor = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (RED.settings.get('externalModules.palette.allowUpload', true) !== false) {
|
if (RED.settings.get('externalModules.palette.allowUpload', true) !== false) {
|
||||||
var uploadSpan = $('<span class="button-group">').prependTo(toolBar);
|
var uploadSpan = $('<span class="button-group">').prependTo(toolBarActions);
|
||||||
var uploadButton = $('<button type="button" class="red-ui-sidebar-header-button red-ui-palette-editor-upload-button"><label><i class="fa fa-upload"></i><form id="red-ui-palette-editor-upload-form" enctype="multipart/form-data"><input name="tarball" type="file" accept=".tgz"></label></button>').appendTo(uploadSpan);
|
var uploadButton = $('<button type="button" class="red-ui-sidebar-header-button red-ui-palette-editor-upload-button"><label><i class="fa fa-upload"></i><form id="red-ui-palette-editor-upload-form" enctype="multipart/form-data"><input name="tarball" type="file" accept=".tgz"></label></button>').appendTo(uploadSpan);
|
||||||
|
|
||||||
var uploadInput = uploadButton.find('input[type="file"]');
|
var uploadInput = uploadButton.find('input[type="file"]');
|
||||||
|
@ -171,23 +171,15 @@ RED.palette = (function() {
|
|||||||
}
|
}
|
||||||
metaData += type;
|
metaData += type;
|
||||||
|
|
||||||
|
const safeType = type.replace(/'/g,"\\'");
|
||||||
|
const searchType = type.indexOf(' ') > -1 ? '"' + type + '"' : type
|
||||||
|
|
||||||
if (/^subflow:/.test(type)) {
|
if (/^subflow:/.test(type)) {
|
||||||
$('<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)
|
$('<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)
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeType = type.replace(/'/g,"\\'");
|
$('<button type="button" onclick="RED.search.show(\'type:'+searchType+'\'); 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)
|
||||||
const wrapStr = function (str) {
|
|
||||||
if(str.indexOf(' ') >= 0) {
|
|
||||||
return '"' + str + '"'
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
$('<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)
|
$('<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);
|
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
|
||||||
@ -292,6 +284,7 @@ RED.palette = (function() {
|
|||||||
var hoverGroup;
|
var hoverGroup;
|
||||||
var paletteWidth;
|
var paletteWidth;
|
||||||
var paletteTop;
|
var paletteTop;
|
||||||
|
var dropEnabled;
|
||||||
$(d).draggable({
|
$(d).draggable({
|
||||||
helper: 'clone',
|
helper: 'clone',
|
||||||
appendTo: '#red-ui-editor',
|
appendTo: '#red-ui-editor',
|
||||||
@ -299,6 +292,7 @@ RED.palette = (function() {
|
|||||||
revertDuration: 200,
|
revertDuration: 200,
|
||||||
containment:'#red-ui-main-container',
|
containment:'#red-ui-main-container',
|
||||||
start: function() {
|
start: function() {
|
||||||
|
dropEnabled = !(RED.nodes.workspace(RED.workspaces.active())?.locked);
|
||||||
paletteWidth = $("#red-ui-palette").width();
|
paletteWidth = $("#red-ui-palette").width();
|
||||||
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
|
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
|
||||||
hoverGroup = null;
|
hoverGroup = null;
|
||||||
@ -309,6 +303,7 @@ RED.palette = (function() {
|
|||||||
RED.view.focus();
|
RED.view.focus();
|
||||||
},
|
},
|
||||||
stop: function() {
|
stop: function() {
|
||||||
|
if (dropEnabled) {
|
||||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||||
if (hoverGroup) {
|
if (hoverGroup) {
|
||||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||||
@ -318,10 +313,12 @@ RED.palette = (function() {
|
|||||||
}
|
}
|
||||||
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
|
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
|
||||||
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
|
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
drag: function(e,ui) {
|
drag: function(e,ui) {
|
||||||
var paletteNode = getPaletteNode(nt);
|
var paletteNode = getPaletteNode(nt);
|
||||||
ui.originalPosition.left = paletteNode.offset().left;
|
ui.originalPosition.left = paletteNode.offset().left;
|
||||||
|
if (dropEnabled) {
|
||||||
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
||||||
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
|
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
|
||||||
if (!groupTimer) {
|
if (!groupTimer) {
|
||||||
@ -402,6 +399,7 @@ RED.palette = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var nodeInfo = null;
|
var nodeInfo = null;
|
||||||
|
@ -165,6 +165,9 @@ RED.projects.settings = (function() {
|
|||||||
}
|
}
|
||||||
var description = addTargetToExternalLinks($('<span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(desc)+'">'+desc+'</span>')).appendTo(container);
|
var description = addTargetToExternalLinks($('<span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(desc)+'">'+desc+'</span>')).appendTo(container);
|
||||||
description.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
description.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
||||||
|
setTimeout(function () {
|
||||||
|
mermaid.init();
|
||||||
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
function editSummary(activeProject, summary, container, version, versionContainer) {
|
function editSummary(activeProject, summary, container, version, versionContainer) {
|
||||||
|
@ -46,7 +46,9 @@ RED.subflow = (function() {
|
|||||||
'</script>';
|
'</script>';
|
||||||
|
|
||||||
function findAvailableSubflowIOPosition(subflow,isInput) {
|
function findAvailableSubflowIOPosition(subflow,isInput) {
|
||||||
var pos = {x:50,y:30};
|
const scrollPos = RED.view.scroll()
|
||||||
|
const scaleFactor = RED.view.scale()
|
||||||
|
var pos = { x: (scrollPos[0]/scaleFactor)+50, y: (scrollPos[1]/scaleFactor)+30 };
|
||||||
if (!isInput) {
|
if (!isInput) {
|
||||||
pos.x += 110;
|
pos.x += 110;
|
||||||
}
|
}
|
||||||
@ -273,6 +275,11 @@ RED.subflow = (function() {
|
|||||||
var subflowInstances = [];
|
var subflowInstances = [];
|
||||||
if (activeSubflow) {
|
if (activeSubflow) {
|
||||||
RED.nodes.filterNodes({type:"subflow:"+activeSubflow.id}).forEach(function(n) {
|
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({
|
subflowInstances.push({
|
||||||
id: n.id,
|
id: n.id,
|
||||||
changed: n.changed
|
changed: n.changed
|
||||||
@ -285,6 +292,9 @@ RED.subflow = (function() {
|
|||||||
n.resize = true;
|
n.resize = true;
|
||||||
n.dirty = true;
|
n.dirty = true;
|
||||||
RED.editor.updateNodeProperties(n);
|
RED.editor.updateNodeProperties(n);
|
||||||
|
if (wasLocked) {
|
||||||
|
parentFlow.locked = true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
RED.editor.validateNode(activeSubflow);
|
RED.editor.validateNode(activeSubflow);
|
||||||
return {
|
return {
|
||||||
@ -431,12 +441,32 @@ RED.subflow = (function() {
|
|||||||
|
|
||||||
$("#red-ui-subflow-delete").on("click", function(event) {
|
$("#red-ui-subflow-delete").on("click", function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
RED.subflow.delete(RED.workspaces.active())
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshToolbar(activeSubflow);
|
||||||
|
|
||||||
|
$("#red-ui-workspace-chart").css({"margin-top": "40px"});
|
||||||
|
$("#red-ui-workspace-toolbar").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideWorkspaceToolbar() {
|
||||||
|
$("#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.length > 0) {
|
||||||
var msg = $('<div>')
|
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.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
|
||||||
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
|
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
|
||||||
var confirmDeleteNotification = RED.notify(msg, {
|
const confirmDeleteNotification = RED.notify(msg, {
|
||||||
modal: true,
|
modal: true,
|
||||||
fixed: true,
|
fixed: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
@ -462,26 +492,13 @@ RED.subflow = (function() {
|
|||||||
completeDelete();
|
completeDelete();
|
||||||
}
|
}
|
||||||
function completeDelete() {
|
function completeDelete() {
|
||||||
var startDirty = RED.nodes.dirty();
|
const startDirty = RED.nodes.dirty();
|
||||||
var historyEvent = removeSubflow(RED.workspaces.active());
|
const historyEvent = removeSubflow(subflow.id);
|
||||||
historyEvent.t = 'delete';
|
historyEvent.t = 'delete';
|
||||||
historyEvent.dirty = startDirty;
|
historyEvent.dirty = startDirty;
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshToolbar(activeSubflow);
|
|
||||||
|
|
||||||
$("#red-ui-workspace-chart").css({"margin-top": "40px"});
|
|
||||||
$("#red-ui-workspace-toolbar").show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideWorkspaceToolbar() {
|
|
||||||
$("#red-ui-workspace-toolbar").hide().empty();
|
|
||||||
$("#red-ui-workspace-chart").css({"margin-top": "0"});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeSubflow(id, keepInstanceNodes) {
|
function removeSubflow(id, keepInstanceNodes) {
|
||||||
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
|
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
|
||||||
var removedNodes = [];
|
var removedNodes = [];
|
||||||
@ -558,7 +575,7 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
RED.events.on("view:selection-changed",function(selection) {
|
RED.events.on("view:selection-changed",function(selection) {
|
||||||
if (!selection.nodes) {
|
if (!selection.nodes || RED.workspaces.isLocked()) {
|
||||||
RED.menu.setDisabled("menu-item-subflow-convert",true);
|
RED.menu.setDisabled("menu-item-subflow-convert",true);
|
||||||
} else {
|
} else {
|
||||||
RED.menu.setDisabled("menu-item-subflow-convert",false);
|
RED.menu.setDisabled("menu-item-subflow-convert",false);
|
||||||
@ -621,6 +638,9 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function convertToSubflow() {
|
function convertToSubflow() {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (!selection.nodes) {
|
if (!selection.nodes) {
|
||||||
RED.notify(RED._("subflow.errors.noNodesSelected"),"error");
|
RED.notify(RED._("subflow.errors.noNodesSelected"),"error");
|
||||||
@ -775,7 +795,7 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
subflowInstance._def = RED.nodes.getType(subflowInstance.type);
|
subflowInstance._def = RED.nodes.getType(subflowInstance.type);
|
||||||
RED.editor.validateNode(subflowInstance);
|
RED.editor.validateNode(subflowInstance);
|
||||||
RED.nodes.add(subflowInstance);
|
subflowInstance = RED.nodes.add(subflowInstance);
|
||||||
|
|
||||||
if (containingGroup) {
|
if (containingGroup) {
|
||||||
RED.group.addToGroup(containingGroup, subflowInstance);
|
RED.group.addToGroup(containingGroup, subflowInstance);
|
||||||
@ -1329,7 +1349,10 @@ RED.subflow = (function() {
|
|||||||
init: init,
|
init: init,
|
||||||
createSubflow: createSubflow,
|
createSubflow: createSubflow,
|
||||||
convertToSubflow: convertToSubflow,
|
convertToSubflow: convertToSubflow,
|
||||||
|
// removeSubflow: Internal function to remove subflow
|
||||||
removeSubflow: removeSubflow,
|
removeSubflow: removeSubflow,
|
||||||
|
// delete: Prompt user for confirmation
|
||||||
|
delete: deleteSubflow,
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
removeInput: removeSubflowInput,
|
removeInput: removeSubflowInput,
|
||||||
removeOutput: removeSubflowOutput,
|
removeOutput: removeSubflowOutput,
|
||||||
|
@ -43,12 +43,15 @@ RED.sidebar.config = (function() {
|
|||||||
|
|
||||||
var categories = {};
|
var categories = {};
|
||||||
|
|
||||||
function getOrCreateCategory(name,parent,label) {
|
function getOrCreateCategory(name,parent,label,isLocked) {
|
||||||
name = name.replace(/\./i,"-");
|
name = name.replace(/\./i,"-");
|
||||||
if (!categories[name]) {
|
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 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);
|
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) {
|
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);
|
$('<span class="red-ui-palette-node-config-label"/>').text(label).appendTo(header);
|
||||||
} else {
|
} else {
|
||||||
$('<span class="red-ui-palette-node-config-label" data-i18n="sidebar.config.'+name+'">').appendTo(header);
|
$('<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 icon = header.find("i");
|
||||||
var result = {
|
var result = {
|
||||||
label: label,
|
label: label,
|
||||||
|
lockIcon,
|
||||||
list: category,
|
list: category,
|
||||||
size: function() {
|
size: function() {
|
||||||
return result.list.find("li:not(.red-ui-palette-node-config-none)").length
|
return result.list.find("li:not(.red-ui-palette-node-config-none)").length
|
||||||
@ -100,6 +104,9 @@ RED.sidebar.config = (function() {
|
|||||||
});
|
});
|
||||||
categories[name] = result;
|
categories[name] = result;
|
||||||
} else {
|
} else {
|
||||||
|
if (isLocked !== undefined && categories[name].lockIcon) {
|
||||||
|
categories[name].lockIcon.toggle(!!isLocked)
|
||||||
|
}
|
||||||
if (categories[name].label !== label) {
|
if (categories[name].label !== label) {
|
||||||
categories[name].list.parent().find('.red-ui-palette-node-config-label').text(label);
|
categories[name].list.parent().find('.red-ui-palette-node-config-label').text(label);
|
||||||
categories[name].label = label;
|
categories[name].label = label;
|
||||||
@ -138,17 +145,19 @@ RED.sidebar.config = (function() {
|
|||||||
} else {
|
} else {
|
||||||
var currentType = "";
|
var currentType = "";
|
||||||
nodes.forEach(function(node) {
|
nodes.forEach(function(node) {
|
||||||
var label = RED.utils.getNodeLabel(node,node.id);
|
var labelText = RED.utils.getNodeLabel(node,node.id);
|
||||||
if (node.type != currentType) {
|
if (node.type != currentType) {
|
||||||
$('<li class="red-ui-palette-node-config-type">'+node.type+'</li>').appendTo(list);
|
$('<li class="red-ui-palette-node-config-type">'+node.type+'</li>').appendTo(list);
|
||||||
currentType = node.type;
|
currentType = node.type;
|
||||||
}
|
}
|
||||||
|
if (node.changed) {
|
||||||
|
labelText += "!!"
|
||||||
|
}
|
||||||
var entry = $('<li class="red-ui-palette-node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
|
var entry = $('<li class="red-ui-palette-node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
|
||||||
var nodeDiv = $('<div class="red-ui-palette-node-config red-ui-palette-node"></div>').appendTo(entry);
|
var nodeDiv = $('<div class="red-ui-palette-node-config red-ui-palette-node"></div>').appendTo(entry);
|
||||||
entry.data('node',node.id);
|
entry.data('node',node.id);
|
||||||
nodeDiv.data('node',node.id);
|
nodeDiv.data('node',node.id);
|
||||||
var label = $('<div class="red-ui-palette-label"></div>').text(label).appendTo(nodeDiv);
|
var label = $('<div class="red-ui-palette-label"></div>').text(labelText).appendTo(nodeDiv);
|
||||||
if (node.d) {
|
if (node.d) {
|
||||||
nodeDiv.addClass("red-ui-palette-node-config-disabled");
|
nodeDiv.addClass("red-ui-palette-node-config-disabled");
|
||||||
$('<i class="fa fa-ban"></i>').prependTo(label);
|
$('<i class="fa fa-ban"></i>').prependTo(label);
|
||||||
@ -216,7 +225,7 @@ RED.sidebar.config = (function() {
|
|||||||
|
|
||||||
RED.nodes.eachWorkspace(function(ws) {
|
RED.nodes.eachWorkspace(function(ws) {
|
||||||
validList[ws.id.replace(/\./g,"-")] = true;
|
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) {
|
RED.nodes.eachSubflow(function(sf) {
|
||||||
validList[sf.id.replace(/\./g,"-")] = true;
|
validList[sf.id.replace(/\./g,"-")] = true;
|
||||||
@ -274,6 +283,15 @@ RED.sidebar.config = (function() {
|
|||||||
changes: {},
|
changes: {},
|
||||||
dirty: RED.nodes.dirty()
|
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) {
|
selectedNodes.forEach(function(id) {
|
||||||
var node = RED.nodes.node(id);
|
var node = RED.nodes.node(id);
|
||||||
try {
|
try {
|
||||||
|
@ -218,11 +218,11 @@ RED.sidebar.context = (function() {
|
|||||||
var obj = $(propRow.children()[0]);
|
var obj = $(propRow.children()[0]);
|
||||||
obj.text(k);
|
obj.text(k);
|
||||||
var tools = $('<span class="button-group"></span>');
|
var tools = $('<span class="button-group"></span>');
|
||||||
|
const urlSafeK = encodeURIComponent(k)
|
||||||
var refreshItem = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-refresh"></i></button>').appendTo(tools).on("click", function(e) {
|
var refreshItem = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-refresh"></i></button>').appendTo(tools).on("click", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
$.getJSON(baseUrl+"/"+k+"?store="+v.store, function(data) {
|
$.getJSON(baseUrl+"/"+urlSafeK+"?store="+v.store, function(data) {
|
||||||
if (data.msg !== payload || data.format !== format) {
|
if (data.msg !== payload || data.format !== format) {
|
||||||
payload = data.msg;
|
payload = data.msg;
|
||||||
format = data.format;
|
format = data.format;
|
||||||
@ -258,11 +258,12 @@ RED.sidebar.context = (function() {
|
|||||||
$('<button class="red-ui-button primary" data-i18n="common.label.delete"></button>').appendTo(bg).on("click", function(e) {
|
$('<button class="red-ui-button primary" data-i18n="common.label.delete"></button>').appendTo(bg).on("click", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
popover.close();
|
popover.close();
|
||||||
|
const urlSafeK = encodeURIComponent(k)
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: baseUrl+"/"+k+"?store="+v.store,
|
url: baseUrl+"/"+urlSafeK+"?store="+v.store,
|
||||||
type: "DELETE"
|
type: "DELETE"
|
||||||
}).done(function(data,textStatus,xhr) {
|
}).done(function(data,textStatus,xhr) {
|
||||||
$.getJSON(baseUrl+"/"+k+"?store="+v.store, function(data) {
|
$.getJSON(baseUrl+"/"+urlSafeK+"?store="+v.store, function(data) {
|
||||||
if (data.format === 'undefined') {
|
if (data.format === 'undefined') {
|
||||||
propRow.remove();
|
propRow.remove();
|
||||||
if (container.children().length === 0) {
|
if (container.children().length === 0) {
|
||||||
|
@ -142,6 +142,7 @@ RED.sidebar.help = (function() {
|
|||||||
RED.events.on('subflows:change', refreshSubflow);
|
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();
|
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
|
// TODO: DRY - projects.js
|
||||||
function addTargetToExternalLinks(el) {
|
function addTargetToExternalLinks(el) {
|
||||||
$(el).find("a").each(function(el) {
|
$(el).find("a").each(function(el) {
|
||||||
|
@ -225,6 +225,22 @@ RED.sidebar.info.outliner = (function() {
|
|||||||
} else {
|
} else {
|
||||||
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
|
$('<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) {
|
controls.find("button").on("dblclick", function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
@ -368,6 +384,8 @@ RED.sidebar.info.outliner = (function() {
|
|||||||
flowList.treeList.addChild(objects[ws.id])
|
flowList.treeList.addChild(objects[ws.id])
|
||||||
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
|
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].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();
|
updateSearch();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -382,6 +400,8 @@ RED.sidebar.info.outliner = (function() {
|
|||||||
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
|
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
|
||||||
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
|
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
|
||||||
existingObject.treeList.container.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();
|
updateSearch();
|
||||||
}
|
}
|
||||||
function onFlowsReorder(order) {
|
function onFlowsReorder(order) {
|
||||||
|
@ -25,6 +25,7 @@ RED.sidebar.info = (function() {
|
|||||||
var propertiesPanelHeaderLabel;
|
var propertiesPanelHeaderLabel;
|
||||||
var propertiesPanelHeaderReveal;
|
var propertiesPanelHeaderReveal;
|
||||||
var propertiesPanelHeaderHelp;
|
var propertiesPanelHeaderHelp;
|
||||||
|
var propertiesPanelHeaderCopyLink;
|
||||||
|
|
||||||
var selectedObject;
|
var selectedObject;
|
||||||
|
|
||||||
@ -67,10 +68,20 @@ RED.sidebar.info = (function() {
|
|||||||
|
|
||||||
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
|
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
|
||||||
propertiesPanelHeaderLabel = $("<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',
|
position: 'absolute',
|
||||||
top: '12px',
|
top: '12px',
|
||||||
right: '32px'
|
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) {
|
}).on("click", function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
@ -80,8 +91,7 @@ RED.sidebar.info = (function() {
|
|||||||
}).appendTo(propertiesPanelHeader);
|
}).appendTo(propertiesPanelHeader);
|
||||||
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
|
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
|
||||||
|
|
||||||
|
propertiesPanelHeaderReveal = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
|
||||||
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
|
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '12px',
|
top: '12px',
|
||||||
right: '8px'
|
right: '8px'
|
||||||
@ -185,6 +195,7 @@ RED.sidebar.info = (function() {
|
|||||||
propertiesPanelHeaderLabel.text("");
|
propertiesPanelHeaderLabel.text("");
|
||||||
propertiesPanelHeaderReveal.hide();
|
propertiesPanelHeaderReveal.hide();
|
||||||
propertiesPanelHeaderHelp.hide();
|
propertiesPanelHeaderHelp.hide();
|
||||||
|
propertiesPanelHeaderCopyLink.hide();
|
||||||
return;
|
return;
|
||||||
} else if (Array.isArray(node)) {
|
} else if (Array.isArray(node)) {
|
||||||
// Multiple things selected
|
// Multiple things selected
|
||||||
@ -196,6 +207,7 @@ RED.sidebar.info = (function() {
|
|||||||
propertiesPanelHeaderLabel.text("Selection");
|
propertiesPanelHeaderLabel.text("Selection");
|
||||||
propertiesPanelHeaderReveal.hide();
|
propertiesPanelHeaderReveal.hide();
|
||||||
propertiesPanelHeaderHelp.hide();
|
propertiesPanelHeaderHelp.hide();
|
||||||
|
propertiesPanelHeaderCopyLink.hide();
|
||||||
selectedObject = null;
|
selectedObject = null;
|
||||||
|
|
||||||
var types = {
|
var types = {
|
||||||
@ -277,9 +289,11 @@ RED.sidebar.info = (function() {
|
|||||||
if (node.type === "tab" || node.type === "subflow") {
|
if (node.type === "tab" || node.type === "subflow") {
|
||||||
// If nothing is selected, but we're on a flow or subflow tab.
|
// If nothing is selected, but we're on a flow or subflow tab.
|
||||||
propertiesPanelHeaderHelp.hide();
|
propertiesPanelHeaderHelp.hide();
|
||||||
|
propertiesPanelHeaderCopyLink.show();
|
||||||
|
|
||||||
} else if (node.type === "group") {
|
} else if (node.type === "group") {
|
||||||
propertiesPanelHeaderHelp.hide();
|
propertiesPanelHeaderHelp.hide();
|
||||||
|
propertiesPanelHeaderCopyLink.show();
|
||||||
|
|
||||||
propRow = $('<tr class="red-ui-help-info-row"><td> </td><td></td></tr>').appendTo(tableBody);
|
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') {
|
} else if (node.type === 'junction') {
|
||||||
propertiesPanelHeaderHelp.hide();
|
propertiesPanelHeaderHelp.hide();
|
||||||
|
propertiesPanelHeaderCopyLink.hide();
|
||||||
} else {
|
} else {
|
||||||
propertiesPanelHeaderHelp.show();
|
propertiesPanelHeaderHelp.show();
|
||||||
|
propertiesPanelHeaderCopyLink.show();
|
||||||
|
|
||||||
if (!subflowRegex) {
|
if (!subflowRegex) {
|
||||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+'</td><td></td></tr>').appendTo(tableBody);
|
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();
|
el = el.next();
|
||||||
}
|
}
|
||||||
$(this).toggleClass('expanded',!isExpanded);
|
$(this).toggleClass('expanded',!isExpanded);
|
||||||
})
|
});
|
||||||
|
mermaid.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
var tips = (function() {
|
var tips = (function() {
|
||||||
|
@ -435,10 +435,15 @@ RED.tourGuide = (function() {
|
|||||||
|
|
||||||
function listTour() {
|
function listTour() {
|
||||||
return [
|
return [
|
||||||
|
{
|
||||||
|
id: "3_1",
|
||||||
|
label: "3.1",
|
||||||
|
path: "./tours/welcome.js"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "3_0",
|
id: "3_0",
|
||||||
label: "3.0",
|
label: "3.0",
|
||||||
path: "./tours/welcome.js"
|
path: "./tours/3.0/welcome.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "2_2",
|
id: "2_2",
|
||||||
|
@ -362,6 +362,7 @@ RED.typeSearch = (function() {
|
|||||||
items.push({type:t,def: def, label:getTypeLabel(t,def)});
|
items.push({type:t,def: def, label:getTypeLabel(t,def)});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
items.push({ type: 'junction', def: { inputs:1, outputs: 1, label: 'junction', type: 'junction'}, label: 'junction' })
|
||||||
items.sort(sortTypeLabels);
|
items.sort(sortTypeLabels);
|
||||||
|
|
||||||
var commonCount = 0;
|
var commonCount = 0;
|
||||||
|
@ -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({
|
window._marked.setOptions({
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
gfm: true,
|
gfm: true,
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
RED.view.navigator = (function() {
|
RED.view.navigator = (function() {
|
||||||
|
|
||||||
var nav_scale = 25;
|
var nav_scale = 50;
|
||||||
var nav_width = 5000/nav_scale;
|
var nav_width = 8000/nav_scale;
|
||||||
var nav_height = 5000/nav_scale;
|
var nav_height = 8000/nav_scale;
|
||||||
|
|
||||||
var navContainer;
|
var navContainer;
|
||||||
var navBox;
|
var navBox;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
RED.view.tools = (function() {
|
RED.view.tools = (function() {
|
||||||
|
'use strict';
|
||||||
function selectConnected(type) {
|
function selectConnected(type) {
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
var visited = new Set();
|
var visited = new Set();
|
||||||
@ -39,6 +39,9 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function alignToGrid() {
|
function alignToGrid() {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var changedNodes = [];
|
var changedNodes = [];
|
||||||
@ -87,6 +90,9 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function moveSelection(dx,dy) {
|
function moveSelection(dx,dy) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (moving_set === null) {
|
if (moving_set === null) {
|
||||||
moving_set = [];
|
moving_set = [];
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
@ -153,6 +159,9 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setSelectedNodeLabelState(labelShown) {
|
function setSelectedNodeLabelState(labelShown) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
var historyEvents = [];
|
var historyEvents = [];
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
@ -439,6 +448,9 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function alignSelectionToEdge(direction) {
|
function alignSelectionToEdge(direction) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
|
|
||||||
if (selection.nodes && selection.nodes.length > 1) {
|
if (selection.nodes && selection.nodes.length > 1) {
|
||||||
@ -539,8 +551,10 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function distributeSelection(direction) {
|
function distributeSelection(direction) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
|
|
||||||
if (selection.nodes && selection.nodes.length > 2) {
|
if (selection.nodes && selection.nodes.length > 2) {
|
||||||
@ -699,14 +713,16 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reorderSelection(dir) {
|
function reorderSelection(dir) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var nodesToMove = [];
|
var nodesToMove = [];
|
||||||
selection.nodes.forEach(function(n) {
|
selection.nodes.forEach(function(n) {
|
||||||
if (n.type === "group") {
|
if (n.type === "group") {
|
||||||
nodesToMove = nodesToMove.concat(RED.group.getNodes(n, true).filter(function(n) {
|
nodesToMove.push(n)
|
||||||
return n.type !== "group";
|
nodesToMove = nodesToMove.concat(RED.group.getNodes(n, true))
|
||||||
}))
|
|
||||||
} else if (n.type !== "subflow"){
|
} else if (n.type !== "subflow"){
|
||||||
nodesToMove.push(n);
|
nodesToMove.push(n);
|
||||||
}
|
}
|
||||||
@ -734,8 +750,10 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function wireSeriesOfNodes() {
|
function wireSeriesOfNodes() {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
if (selection.nodes.length > 1) {
|
if (selection.nodes.length > 1) {
|
||||||
@ -776,6 +794,9 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function wireNodeToMultiple() {
|
function wireNodeToMultiple() {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
if (selection.nodes.length > 1) {
|
if (selection.nodes.length > 1) {
|
||||||
@ -818,11 +839,72 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wireMultipleToNode() {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var selection = RED.view.selection();
|
||||||
|
if (selection.nodes) {
|
||||||
|
if (selection.nodes.length > 1) {
|
||||||
|
var targetNode = selection.nodes[selection.nodes.length - 1];
|
||||||
|
if (targetNode.inputs === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var i = 0;
|
||||||
|
var newLinks = [];
|
||||||
|
for (i = 0; i < selection.nodes.length - 1; i++) {
|
||||||
|
var sourceNode = selection.nodes[i];
|
||||||
|
if (sourceNode.outputs > 0) {
|
||||||
|
|
||||||
|
// Wire the first output to the target that has no link to the target yet.
|
||||||
|
// This allows for connecting all combinations of inputs/outputs.
|
||||||
|
// The user may then delete links quickly that aren't needed.
|
||||||
|
var sourceConnectedOutports = RED.nodes.filterLinks({
|
||||||
|
source: sourceNode,
|
||||||
|
target: targetNode
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get outport indices that have no link yet
|
||||||
|
var sourceOutportIndices = Array.from({ length: sourceNode.outputs }, (_, i) => i);
|
||||||
|
var sourceConnectedOutportIndices = sourceConnectedOutports.map( x => x.sourcePort );
|
||||||
|
var sourceFreeOutportIndices = sourceOutportIndices.filter(x => !sourceConnectedOutportIndices.includes(x));
|
||||||
|
|
||||||
|
// Does an unconnected source port exist?
|
||||||
|
if (sourceFreeOutportIndices.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect the first free outport to the target
|
||||||
|
var newLink = {
|
||||||
|
source: sourceNode,
|
||||||
|
target: targetNode,
|
||||||
|
sourcePort: sourceFreeOutportIndices[0]
|
||||||
|
}
|
||||||
|
RED.nodes.addLink(newLink);
|
||||||
|
newLinks.push(newLink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newLinks.length > 0) {
|
||||||
|
RED.history.push({
|
||||||
|
t: 'add',
|
||||||
|
links: newLinks,
|
||||||
|
dirty: RED.nodes.dirty()
|
||||||
|
})
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
RED.view.redraw(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splits selected wires and re-joins them with link-out+link-in
|
* Splits selected wires and re-joins them with link-out+link-in
|
||||||
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
||||||
*/
|
*/
|
||||||
function splitWiresWithLinkNodes(wires) {
|
function splitWiresWithLinkNodes(wires) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||||
if (!wiresToSplit) {
|
if (!wiresToSplit) {
|
||||||
return
|
return
|
||||||
@ -877,7 +959,6 @@ RED.view.tools = (function() {
|
|||||||
if(!nnLinkOut) {
|
if(!nnLinkOut) {
|
||||||
const nLinkOut = RED.view.createNode("link out"); //create link node
|
const nLinkOut = RED.view.createNode("link out"); //create link node
|
||||||
nnLinkOut = nLinkOut.node;
|
nnLinkOut = nLinkOut.node;
|
||||||
nodeSrcMap[linkOutMapId] = nnLinkOut;
|
|
||||||
let yOffset = 0;
|
let yOffset = 0;
|
||||||
if(nSrc.outputs > 1) {
|
if(nSrc.outputs > 1) {
|
||||||
|
|
||||||
@ -892,7 +973,8 @@ RED.view.tools = (function() {
|
|||||||
updateNewNodePosXY(nSrc, nnLinkOut, false, RED.view.snapGrid, yOffset);
|
updateNewNodePosXY(nSrc, nnLinkOut, false, RED.view.snapGrid, yOffset);
|
||||||
}
|
}
|
||||||
//add created node
|
//add created node
|
||||||
RED.nodes.add(nnLinkOut);
|
nnLinkOut = RED.nodes.add(nnLinkOut);
|
||||||
|
nodeSrcMap[linkOutMapId] = nnLinkOut;
|
||||||
RED.editor.validateNode(nnLinkOut);
|
RED.editor.validateNode(nnLinkOut);
|
||||||
history.events.push(nLinkOut.historyEvent);
|
history.events.push(nLinkOut.historyEvent);
|
||||||
//connect node to link node
|
//connect node to link node
|
||||||
@ -913,10 +995,10 @@ RED.view.tools = (function() {
|
|||||||
if(!nnLinkIn) {
|
if(!nnLinkIn) {
|
||||||
const nLinkIn = RED.view.createNode("link in"); //create link node
|
const nLinkIn = RED.view.createNode("link in"); //create link node
|
||||||
nnLinkIn = nLinkIn.node;
|
nnLinkIn = nLinkIn.node;
|
||||||
nodeTrgMap[nTrg.id] = nnLinkIn;
|
|
||||||
updateNewNodePosXY(nTrg, nnLinkIn, true, RED.view.snapGrid, 0);
|
updateNewNodePosXY(nTrg, nnLinkIn, true, RED.view.snapGrid, 0);
|
||||||
//add created node
|
//add created node
|
||||||
RED.nodes.add(nnLinkIn);
|
nnLinkIn = RED.nodes.add(nnLinkIn);
|
||||||
|
nodeTrgMap[nTrg.id] = nnLinkIn;
|
||||||
RED.editor.validateNode(nnLinkIn);
|
RED.editor.validateNode(nnLinkIn);
|
||||||
history.events.push(nLinkIn.historyEvent);
|
history.events.push(nLinkIn.historyEvent);
|
||||||
//connect node to link node
|
//connect node to link node
|
||||||
@ -991,6 +1073,9 @@ RED.view.tools = (function() {
|
|||||||
* @param {{ renameBlank: boolean, renameClash: boolean, generateHistory: boolean }} options Possible options are `renameBlank`, `renameClash` and `generateHistory`
|
* @param {{ renameBlank: boolean, renameClash: boolean, generateHistory: boolean }} options Possible options are `renameBlank`, `renameClash` and `generateHistory`
|
||||||
*/
|
*/
|
||||||
function generateNodeNames(node, options) {
|
function generateNodeNames(node, options) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
options = Object.assign({
|
options = Object.assign({
|
||||||
renameBlank: true,
|
renameBlank: true,
|
||||||
renameClash: true,
|
renameClash: true,
|
||||||
@ -1061,6 +1146,9 @@ RED.view.tools = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addJunctionsToWires(wires) {
|
function addJunctionsToWires(wires) {
|
||||||
|
if (RED.workspaces.isLocked()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||||
if (!wiresToSplit) {
|
if (!wiresToSplit) {
|
||||||
return
|
return
|
||||||
@ -1102,7 +1190,8 @@ RED.view.tools = (function() {
|
|||||||
w: 0, h: 0,
|
w: 0, h: 0,
|
||||||
outputs: 1,
|
outputs: 1,
|
||||||
inputs: 1,
|
inputs: 1,
|
||||||
dirty: true
|
dirty: true,
|
||||||
|
moved: true
|
||||||
}
|
}
|
||||||
links = links.filter(function(l) { return !removedLinks.has(l) })
|
links = links.filter(function(l) { return !removedLinks.has(l) })
|
||||||
if (links.length === 0) {
|
if (links.length === 0) {
|
||||||
@ -1131,7 +1220,7 @@ RED.view.tools = (function() {
|
|||||||
|
|
||||||
var nodeGroups = new Set()
|
var nodeGroups = new Set()
|
||||||
|
|
||||||
RED.nodes.addJunction(junction)
|
junction = RED.nodes.addJunction(junction)
|
||||||
addedJunctions.push(junction)
|
addedJunctions.push(junction)
|
||||||
let newLink
|
let newLink
|
||||||
if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
||||||
@ -1192,6 +1281,63 @@ RED.view.tools = (function() {
|
|||||||
RED.view.redraw(true);
|
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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a point is within a node
|
||||||
|
* @param {*} node - A Node or Junction node
|
||||||
|
* @param {[Number,Number]} mouse_position The x,y position of the mouse
|
||||||
|
* @param {Number} [marginX=0] - A margin to add or deduct from the x position (to increase the hit area)
|
||||||
|
* @param {Number} [marginY=0] - A margin to add or deduct from the y position (to increase the hit area)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function isPointInNode (node, [x, y], marginX, marginY) {
|
||||||
|
marginX = marginX || 0
|
||||||
|
marginY = marginY || 0
|
||||||
|
|
||||||
|
let w = node.w || 10 // junctions dont have any w or h value
|
||||||
|
let h = node.h || 10
|
||||||
|
let x1, x2, y1, y2
|
||||||
|
|
||||||
|
if (node.type === "junction" || node.type === "group") {
|
||||||
|
// x/y is the top left of the node
|
||||||
|
x1 = node.x
|
||||||
|
y1 = node.y
|
||||||
|
x2 = node.x + w
|
||||||
|
y2 = node.y + h
|
||||||
|
} else {
|
||||||
|
// x/y is the center of the node
|
||||||
|
const [xMid, yMid] = [w/2, h/2]
|
||||||
|
x1 = node.x - xMid
|
||||||
|
y1 = node.y - yMid
|
||||||
|
x2 = node.x + xMid
|
||||||
|
y2 = node.y + yMid
|
||||||
|
}
|
||||||
|
return (x >= (x1 - marginX) && x <= (x2 + marginX) && y >= (y1 - marginY) && y <= (y2 + marginY))
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: function() {
|
init: function() {
|
||||||
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
||||||
@ -1252,12 +1398,16 @@ RED.view.tools = (function() {
|
|||||||
|
|
||||||
RED.actions.add("core:wire-series-of-nodes", function() { wireSeriesOfNodes() })
|
RED.actions.add("core:wire-series-of-nodes", function() { wireSeriesOfNodes() })
|
||||||
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
||||||
|
RED.actions.add("core:wire-multiple-to-node", function() { wireMultipleToNode() })
|
||||||
|
|
||||||
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
||||||
RED.actions.add("core:split-wires-with-junctions", function () { addJunctionsToWires() });
|
RED.actions.add("core:split-wires-with-junctions", function () { addJunctionsToWires() });
|
||||||
|
|
||||||
RED.actions.add("core:generate-node-names", generateNodeNames )
|
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() })
|
// RED.actions.add("core:add-node", function() { addNode() })
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -1270,7 +1420,8 @@ RED.view.tools = (function() {
|
|||||||
* @param {Number} dy
|
* @param {Number} dy
|
||||||
*/
|
*/
|
||||||
moveSelection: moveSelection,
|
moveSelection: moveSelection,
|
||||||
calculateGridSnapOffsets: calculateGridSnapOffsets
|
calculateGridSnapOffsets: calculateGridSnapOffsets,
|
||||||
|
isPointInNode: isPointInNode
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -58,6 +58,9 @@ RED.workspaces = (function() {
|
|||||||
if (!ws.closeable) {
|
if (!ws.closeable) {
|
||||||
ws.hideable = true;
|
ws.hideable = true;
|
||||||
}
|
}
|
||||||
|
if (!ws.hasOwnProperty('locked')) {
|
||||||
|
ws.locked = false
|
||||||
|
}
|
||||||
workspace_tabs.addTab(ws,targetIndex);
|
workspace_tabs.addTab(ws,targetIndex);
|
||||||
|
|
||||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||||
@ -75,11 +78,15 @@ RED.workspaces = (function() {
|
|||||||
type: "tab",
|
type: "tab",
|
||||||
id: tabId,
|
id: tabId,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
locked: false,
|
||||||
info: "",
|
info: "",
|
||||||
label: RED._('workspace.defaultName',{number:workspaceIndex}),
|
label: RED._('workspace.defaultName',{number:workspaceIndex}),
|
||||||
env: [],
|
env: [],
|
||||||
hideable: true
|
hideable: true,
|
||||||
};
|
};
|
||||||
|
if (!skipHistoryEntry) {
|
||||||
|
ws.added = true
|
||||||
|
}
|
||||||
RED.nodes.addWorkspace(ws,targetIndex);
|
RED.nodes.addWorkspace(ws,targetIndex);
|
||||||
workspace_tabs.addTab(ws,targetIndex);
|
workspace_tabs.addTab(ws,targetIndex);
|
||||||
|
|
||||||
@ -89,8 +96,7 @@ RED.workspaces = (function() {
|
|||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
|
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
|
||||||
|
|
||||||
RED.view.focus();
|
RED.view.focus();
|
||||||
return ws;
|
return ws;
|
||||||
}
|
}
|
||||||
@ -99,6 +105,9 @@ RED.workspaces = (function() {
|
|||||||
if (workspaceTabCount === 1) {
|
if (workspaceTabCount === 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ws.locked) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
||||||
ws._index = workspaceOrder.indexOf(ws.id);
|
ws._index = workspaceOrder.indexOf(ws.id);
|
||||||
removeWorkspace(ws);
|
removeWorkspace(ws);
|
||||||
@ -119,13 +128,206 @@ RED.workspaces = (function() {
|
|||||||
RED.editor.editSubflow(subflow);
|
RED.editor.editSubflow(subflow);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (!workspace.locked) {
|
||||||
RED.editor.editFlow(workspace);
|
RED.editor.editFlow(workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var workspace_tabs;
|
var workspace_tabs;
|
||||||
var workspaceTabCount = 0;
|
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.isLocked()
|
||||||
|
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() {
|
function createWorkspaceTabs() {
|
||||||
workspace_tabs = RED.tabs.create({
|
workspace_tabs = RED.tabs.create({
|
||||||
id: "red-ui-workspace-tabs",
|
id: "red-ui-workspace-tabs",
|
||||||
@ -138,6 +340,7 @@ RED.workspaces = (function() {
|
|||||||
activeWorkspace = tab.id;
|
activeWorkspace = tab.id;
|
||||||
window.location.hash = 'flow/'+tab.id;
|
window.location.hash = 'flow/'+tab.id;
|
||||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled);
|
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled);
|
||||||
|
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked", !!tab.locked);
|
||||||
} else {
|
} else {
|
||||||
$("#red-ui-workspace-chart").hide();
|
$("#red-ui-workspace-chart").hide();
|
||||||
activeWorkspace = 0;
|
activeWorkspace = 0;
|
||||||
@ -169,6 +372,18 @@ RED.workspaces = (function() {
|
|||||||
if (tab.disabled) {
|
if (tab.disabled) {
|
||||||
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-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');
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeBadgeContainer = $('<svg class="red-ui-flow-tab-changed red-ui-flow-node-changed" width="10" height="10" viewBox="-1 -1 12 12"></svg>').appendTo("#red-ui-tab-"+(tab.id.replace(".","-")))
|
||||||
|
const changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||||
|
changeBadge.setAttribute("cx",5);
|
||||||
|
changeBadge.setAttribute("cy",5);
|
||||||
|
changeBadge.setAttribute("r",5);
|
||||||
|
changeBadgeContainer.append(changeBadge)
|
||||||
|
|
||||||
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
|
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
|
||||||
if (workspaceTabCount === 1) {
|
if (workspaceTabCount === 1) {
|
||||||
showWorkspace();
|
showWorkspace();
|
||||||
@ -194,8 +409,14 @@ RED.workspaces = (function() {
|
|||||||
},
|
},
|
||||||
dirty:RED.nodes.dirty()
|
dirty:RED.nodes.dirty()
|
||||||
});
|
});
|
||||||
|
// 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);
|
RED.nodes.dirty(true);
|
||||||
setWorkspaceOrder(newOrder);
|
setWorkspaceOrder(newOrder);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onselect: function(selectedTabs) {
|
onselect: function(selectedTabs) {
|
||||||
RED.view.select(false)
|
RED.view.select(false)
|
||||||
@ -214,12 +435,12 @@ RED.workspaces = (function() {
|
|||||||
},
|
},
|
||||||
onhide: function(tab) {
|
onhide: function(tab) {
|
||||||
hideStack.push(tab.id);
|
hideStack.push(tab.id);
|
||||||
|
if (tab.type === "tab") {
|
||||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||||
hiddenTabs[tab.id] = true;
|
hiddenTabs[tab.id] = true;
|
||||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||||
|
|
||||||
RED.events.emit("workspace:hide",{workspace: tab.id})
|
RED.events.emit("workspace:hide",{workspace: tab.id})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onshow: function(tab) {
|
onshow: function(tab) {
|
||||||
removeFromHideStack(tab.id);
|
removeFromHideStack(tab.id);
|
||||||
@ -234,77 +455,8 @@ RED.workspaces = (function() {
|
|||||||
scrollable: true,
|
scrollable: true,
|
||||||
addButton: "core:add-flow",
|
addButton: "core:add-flow",
|
||||||
addButtonCaption: RED._("workspace.addFlow"),
|
addButtonCaption: RED._("workspace.addFlow"),
|
||||||
menu: function() {
|
menu: function() { return getMenuItems(true) },
|
||||||
var menuItems = [
|
contextmenu: function(tab) { return getMenuItems(false, tab) }
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
workspaceTabCount = 0;
|
workspaceTabCount = 0;
|
||||||
}
|
}
|
||||||
@ -355,17 +507,34 @@ RED.workspaces = (function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
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:edit-flow",editWorkspace);
|
||||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||||
RED.actions.add("core:enable-flow",enableWorkspace);
|
RED.actions.add("core:enable-flow",enableWorkspace);
|
||||||
RED.actions.add("core:disable-flow",disableWorkspace);
|
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() {
|
RED.actions.add("core:hide-flow", function(workspace) {
|
||||||
var selection = workspace_tabs.selection();
|
let selection
|
||||||
|
if (workspace) {
|
||||||
|
selection = [workspace]
|
||||||
|
} else {
|
||||||
|
selection = workspace_tabs.selection();
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0) {
|
||||||
selection = [{id:activeWorkspace}]
|
selection = [{id:activeWorkspace}]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var hiddenTabs = [];
|
var hiddenTabs = [];
|
||||||
selection.forEach(function(ws) {
|
selection.forEach(function(ws) {
|
||||||
RED.workspaces.hide(ws.id);
|
RED.workspaces.hide(ws.id);
|
||||||
@ -378,11 +547,16 @@ RED.workspaces = (function() {
|
|||||||
workspace_tabs.clearSelection();
|
workspace_tabs.clearSelection();
|
||||||
})
|
})
|
||||||
|
|
||||||
RED.actions.add("core:hide-other-flows", function() {
|
RED.actions.add("core:hide-other-flows", function(workspace) {
|
||||||
var selection = workspace_tabs.selection();
|
let selection
|
||||||
|
if (workspace) {
|
||||||
|
selection = [workspace]
|
||||||
|
} else {
|
||||||
|
selection = workspace_tabs.selection();
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0) {
|
||||||
selection = [{id:activeWorkspace}]
|
selection = [{id:activeWorkspace}]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var selected = new Set(selection.map(function(ws) { return ws.id }))
|
var selected = new Set(selection.map(function(ws) { return ws.id }))
|
||||||
|
|
||||||
var currentTabs = workspace_tabs.listTabs();
|
var currentTabs = workspace_tabs.listTabs();
|
||||||
@ -471,6 +645,11 @@ RED.workspaces = (function() {
|
|||||||
RED.workspaces.show(viewStack[++viewStackPos],true);
|
RED.workspaces.show(viewStack[++viewStackPos],true);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
RED.events.on("flows:change", (ws) => {
|
||||||
|
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
|
||||||
|
})
|
||||||
|
|
||||||
hideWorkspace();
|
hideWorkspace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,7 +665,7 @@ RED.workspaces = (function() {
|
|||||||
}
|
}
|
||||||
function setWorkspaceState(id,disabled) {
|
function setWorkspaceState(id,disabled) {
|
||||||
var workspace = RED.nodes.workspace(id||activeWorkspace);
|
var workspace = RED.nodes.workspace(id||activeWorkspace);
|
||||||
if (!workspace) {
|
if (!workspace || workspace.locked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (workspace.disabled !== disabled) {
|
if (workspace.disabled !== disabled) {
|
||||||
@ -521,11 +700,47 @@ 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.nodes.filterNodes({z:workspace.id}).forEach(n => n.dirty = true)
|
||||||
|
RED.view.redraw(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function removeWorkspace(ws) {
|
function removeWorkspace(ws) {
|
||||||
if (!ws) {
|
if (!ws) {
|
||||||
|
ws = RED.nodes.workspace(activeWorkspace)
|
||||||
|
if (ws && !ws.locked) {
|
||||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (ws.locked) { return }
|
||||||
if (workspace_tabs.contains(ws.id)) {
|
if (workspace_tabs.contains(ws.id)) {
|
||||||
workspace_tabs.removeTab(ws.id);
|
workspace_tabs.removeTab(ws.id);
|
||||||
}
|
}
|
||||||
@ -535,16 +750,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) {
|
function setWorkspaceOrder(order) {
|
||||||
var newOrder = order.filter(function(id) {
|
var newOrder = order.filter(id => !!RED.nodes.workspace(id))
|
||||||
return RED.nodes.workspace(id) !== undefined;
|
|
||||||
})
|
|
||||||
var currentOrder = RED.nodes.getWorkspaceOrder();
|
var currentOrder = RED.nodes.getWorkspaceOrder();
|
||||||
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
|
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
|
||||||
RED.nodes.setWorkspaceOrder(newOrder);
|
RED.nodes.setWorkspaceOrder(newOrder);
|
||||||
RED.events.emit("flows:reorder",newOrder);
|
RED.events.emit("flows:reorder",newOrder);
|
||||||
}
|
}
|
||||||
workspace_tabs.order(order);
|
workspace_tabs.order(order);
|
||||||
|
return newOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
function flashTab(tabId) {
|
function flashTab(tabId) {
|
||||||
@ -590,6 +835,11 @@ RED.workspaces = (function() {
|
|||||||
active: function() {
|
active: function() {
|
||||||
return activeWorkspace
|
return activeWorkspace
|
||||||
},
|
},
|
||||||
|
isLocked: function(id) {
|
||||||
|
id = id || activeWorkspace
|
||||||
|
var ws = RED.nodes.workspace(id) || RED.nodes.subflow(id)
|
||||||
|
return ws && ws.locked
|
||||||
|
},
|
||||||
selection: function() {
|
selection: function() {
|
||||||
return workspace_tabs.selection();
|
return workspace_tabs.selection();
|
||||||
},
|
},
|
||||||
@ -646,6 +896,8 @@ RED.workspaces = (function() {
|
|||||||
workspace_tabs.resize();
|
workspace_tabs.resize();
|
||||||
},
|
},
|
||||||
enable: enableWorkspace,
|
enable: enableWorkspace,
|
||||||
disable: disableWorkspace
|
disable: disableWorkspace,
|
||||||
|
lock: lockWorkspace,
|
||||||
|
unlock: unlockWorkspace
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -87,16 +87,18 @@
|
|||||||
padding: 0px 8px;
|
padding: 0px 8px;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
&.toggle:not(.selected) {
|
&.toggle.selected {
|
||||||
color: var(--red-ui-workspace-button-color-selected) !important;
|
color: var(--red-ui-workspace-button-color-selected) !important;
|
||||||
background: var(--red-ui-workspace-button-background-active);
|
background: var(--red-ui-workspace-button-background) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.red-ui-tray-footer-left {
|
.red-ui-tray-footer-left {
|
||||||
display:inline-block;
|
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
float:left;
|
float:left;
|
||||||
|
& :not(:first-child) {
|
||||||
|
margin-left: 5px
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.red-ui-tray-footer-right {
|
.red-ui-tray-footer-right {
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -68,6 +68,9 @@
|
|||||||
stroke: var(--red-ui-node-border);
|
stroke: var(--red-ui-node-border);
|
||||||
cursor: move;
|
cursor: move;
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
|
.red-ui-workspace-locked & {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.red-ui-workspace-select-mode {
|
.red-ui-workspace-select-mode {
|
||||||
g.red-ui-flow-node.red-ui-flow-node-hovered * {
|
g.red-ui-flow-node.red-ui-flow-node-hovered * {
|
||||||
@ -88,10 +91,13 @@
|
|||||||
|
|
||||||
.red-ui-flow-group {
|
.red-ui-flow-group {
|
||||||
&.red-ui-flow-group-hovered {
|
&.red-ui-flow-group-hovered {
|
||||||
.red-ui-flow-group-outline-select {
|
.red-ui-flow-group-outline-select-line {
|
||||||
stroke-opacity: 0.8 !important;
|
stroke-opacity: 0.8 !important;
|
||||||
stroke-dasharray: 10 4 !important;
|
stroke-dasharray: 10 4 !important;
|
||||||
}
|
}
|
||||||
|
.red-ui-flow-group-outline-select-outline {
|
||||||
|
stroke-opacity: 0.8 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.red-ui-flow-group-active-hovered:not(.red-ui-flow-group-hovered) {
|
&.red-ui-flow-group-active-hovered:not(.red-ui-flow-group-hovered) {
|
||||||
.red-ui-flow-group-outline-select {
|
.red-ui-flow-group-outline-select {
|
||||||
@ -110,15 +116,35 @@
|
|||||||
.red-ui-flow-group-outline-select {
|
.red-ui-flow-group-outline-select {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: var(--red-ui-node-selected-color);
|
stroke: var(--red-ui-node-selected-color);
|
||||||
pointer-events: stroke;
|
pointer-events: none;
|
||||||
stroke-opacity: 0;
|
stroke-opacity: 0;
|
||||||
stroke-width: 3;
|
stroke-width: 2;
|
||||||
|
|
||||||
&.red-ui-flow-group-outline-select-background {
|
&.red-ui-flow-group-outline-select-outline {
|
||||||
stroke: var(--red-ui-view-background);
|
stroke: var(--red-ui-view-background);
|
||||||
stroke-width: 6;
|
stroke-width: 4;
|
||||||
|
}
|
||||||
|
&.red-ui-flow-group-outline-select-background {
|
||||||
|
fill: white;
|
||||||
|
fill-opacity: 0;
|
||||||
|
pointer-events: stroke;
|
||||||
|
stroke-width: 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svg:not(.red-ui-workspace-lasso-active) {
|
||||||
|
.red-ui-flow-group:not(.red-ui-flow-group-selected) {
|
||||||
|
.red-ui-flow-group-outline-select.red-ui-flow-group-outline-select-background:hover {
|
||||||
|
~ .red-ui-flow-group-outline-select {
|
||||||
|
stroke-opacity: 0.4 !important;
|
||||||
|
}
|
||||||
|
~ .red-ui-flow-group-outline-select-line {
|
||||||
|
stroke-dasharray: 10 4 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.red-ui-flow-group-body {
|
.red-ui-flow-group-body {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
fill: var(--red-ui-group-default-fill);
|
fill: var(--red-ui-group-default-fill);
|
||||||
@ -278,7 +304,11 @@ g.red-ui-flow-node-selected {
|
|||||||
stroke: var(--red-ui-node-status-colors-#{"" + $current-color});
|
stroke: var(--red-ui-node-status-colors-#{"" + $current-color});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.red-ui-flow-node-status-background {
|
||||||
|
stroke: none;
|
||||||
|
fill: var(--red-ui-view-background);
|
||||||
|
fill-opacity: 0.9;
|
||||||
|
}
|
||||||
.red-ui-flow-node-status-label {
|
.red-ui-flow-node-status-label {
|
||||||
@include disable-selection;
|
@include disable-selection;
|
||||||
stroke-width: 0;
|
stroke-width: 0;
|
||||||
@ -287,10 +317,12 @@ g.red-ui-flow-node-selected {
|
|||||||
text-anchor:start;
|
text-anchor:start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#red-ui-workspace:not(.red-ui-workspace-locked) {
|
||||||
.red-ui-flow-port-hovered {
|
.red-ui-flow-port-hovered {
|
||||||
stroke: var(--red-ui-port-selected-color);
|
stroke: var(--red-ui-port-selected-color);
|
||||||
fill: var(--red-ui-port-selected-color);
|
fill: var(--red-ui-port-selected-color);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.red-ui-flow-subflow-port {
|
.red-ui-flow-subflow-port {
|
||||||
fill: var(--red-ui-node-background-placeholder);
|
fill: var(--red-ui-node-background-placeholder);
|
||||||
|
@ -28,7 +28,17 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing:border-box;
|
box-sizing:border-box;
|
||||||
background: var(--red-ui-secondary-background);
|
background: var(--red-ui-secondary-background);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.red-ui-tabs {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-ui-editableList.scrollable {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
.red-ui-editableList-container {
|
.red-ui-editableList-container {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
@ -72,11 +82,9 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
.red-ui-palette-editor-tab {
|
.red-ui-palette-editor-tab {
|
||||||
position:absolute;
|
display: flex;
|
||||||
top:35px;
|
flex-direction: column;
|
||||||
left:0;
|
min-height: 0;
|
||||||
right:0;
|
|
||||||
bottom:0
|
|
||||||
}
|
}
|
||||||
.red-ui-palette-editor-toolbar {
|
.red-ui-palette-editor-toolbar {
|
||||||
background: var(--red-ui-primary-background);
|
background: var(--red-ui-primary-background);
|
||||||
@ -84,6 +92,24 @@
|
|||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
border-bottom: 1px solid var(--red-ui-primary-border-color);
|
border-bottom: 1px solid var(--red-ui-primary-border-color);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 3px 12px;
|
||||||
|
.red-ui-palette-editor-toolbar-actions {
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.red-ui-palette-editor-catalogue-filter {
|
||||||
|
width: unset;
|
||||||
|
margin: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 26px;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.red-ui-palette-module-shade-status {
|
.red-ui-palette-module-shade-status {
|
||||||
color: var(--red-ui-secondary-text-color);
|
color: var(--red-ui-secondary-text-color);
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
}
|
}
|
||||||
.red-ui-palette-search {
|
.red-ui-palette-search {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
// overflow: hidden;
|
||||||
background: var(--red-ui-form-input-background);
|
background: var(--red-ui-form-input-background);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
|
@ -468,6 +468,9 @@ div.red-ui-info-table {
|
|||||||
.fa-eye {
|
.fa-eye {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.fa-unlock-alt {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.red-ui-info-outline-item-control-reveal,
|
.red-ui-info-outline-item-control-reveal,
|
||||||
.red-ui-info-outline-item-control-action {
|
.red-ui-info-outline-item-control-action {
|
||||||
@ -501,6 +504,25 @@ div.red-ui-info-table {
|
|||||||
display: none;
|
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 {
|
button {
|
||||||
margin-right: 3px
|
margin-right: 3px
|
||||||
}
|
}
|
||||||
@ -518,8 +540,6 @@ div.red-ui-info-table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.red-ui-icons {
|
.red-ui-icons {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
|
@ -105,7 +105,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.red-ui-tab:not(.red-ui-workspace-changed) .red-ui-flow-tab-changed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.red-ui-tab.red-ui-workspace-changed .red-ui-flow-tab-changed {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 {
|
#red-ui-navigator-canvas {
|
||||||
position: absolute;
|
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 |
197
packages/node_modules/@node-red/editor-client/src/tours/3.0/welcome.js
vendored
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
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へようこそ!",
|
||||||
|
"fr": "Bienvenue dans 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>",
|
||||||
|
"fr": "<p>Prenons un moment pour découvrir les nouvelles fonctionnalités de cette version.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Context Menu",
|
||||||
|
"ja": "コンテキストメニュー",
|
||||||
|
"fr": "Menu contextuel"
|
||||||
|
},
|
||||||
|
image: '3.0/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>`,
|
||||||
|
"fr": `<p>L'éditeur a maintenant son propre menu contextuel lorsque vous
|
||||||
|
faites un clic droit dans l'espace de travail.</p>
|
||||||
|
<p>Cela facilite l'accès à de nombreuses actions intégrées.</p>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Wire Junctions",
|
||||||
|
"ja": "分岐点をワイヤーに追加",
|
||||||
|
"fr": "Jonctions de fils"
|
||||||
|
},
|
||||||
|
image: '3.0/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>`,
|
||||||
|
"fr": `<p>Pour faciliter le routage des câbles autour de vos flux, il est désormais possible d'ajouter des noeuds
|
||||||
|
de jonction qui vous donnent plus de contrôle.</p>
|
||||||
|
<p>Les jonctions peuvent être ajoutées aux fils en maintenant les touches Alt et Maj enfoncées, puis en cliquant
|
||||||
|
et en faisant glisser la souris sur les fils.</p>`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Wire Junctions",
|
||||||
|
"ja": "分岐点をワイヤーに追加",
|
||||||
|
"fr": "Jonctions de fils"
|
||||||
|
},
|
||||||
|
image: '3.0/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>`,
|
||||||
|
"fr": `<p>Les jonctions peuvent également être ajoutées à l'aide de la boîte de dialogue d'ajout rapide.</p>
|
||||||
|
<p>La boîte de dialogue s'ouvre en maintenant la touche Ctrl (ou Cmd) enfoncée lors d'un clic dans l'espace de travail.</p>`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Debug Path Tooltip",
|
||||||
|
"ja": "デバッグパスのツールチップ",
|
||||||
|
"fr": "Info-bulle du chemin de débogage"
|
||||||
|
},
|
||||||
|
image: '3.0/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>`,
|
||||||
|
"fr": `<p>Lorsque vous passez la souris sur un nom de noeud dans la barre latérale de débogage, une nouvelle info-bulle affiche l'emplacement complet du noeud.</p>
|
||||||
|
<p>C'est utile lorsque vous travaillez avec des sous-flux, ce qui facilite l'identification exacte du noeud qui a généré le message.</p>
|
||||||
|
<p>Cliquer sur n'importe quel élément de la liste le révélera dans l'espace de travail.</p>`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Continuous Search",
|
||||||
|
"ja": "連続した検索",
|
||||||
|
"fr": "Recherche continue"
|
||||||
|
},
|
||||||
|
image: '3.0/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>`,
|
||||||
|
"fr": `<p>Lorsque vous recherchez des éléments dans l'éditeur, une nouvelle barre d'outils dans l'espace de travail fournit des options pour passer
|
||||||
|
rapidement d'un résultat de recherche à l'autre.</p>`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "New wiring actions",
|
||||||
|
"ja": "新しいワイヤー操作",
|
||||||
|
"fr": "Nouvelles actions de câblage"
|
||||||
|
},
|
||||||
|
image: "3.0/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>`,
|
||||||
|
"fr": `<p>Une nouvelle action a été ajoutée pour remplacer un fil par une paire de noeuds de lien connectés :</p>
|
||||||
|
<ul>
|
||||||
|
<li><b><code>Diviser le fil avec les noeuds de liaison</code></b></li>
|
||||||
|
</ul>
|
||||||
|
<p>Les actions sont accessibles à partir de la liste d'actions dans le menu principal.</p>`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Default node names",
|
||||||
|
"ja": "標準ノードの名前",
|
||||||
|
"fr": "Noms de noeud par défaut"
|
||||||
|
},
|
||||||
|
// 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>
|
||||||
|
`,
|
||||||
|
"fr": `<p>Certains noeuds ont été mis à jour pour générer un nom unique lorsque
|
||||||
|
de nouvelles instances sont ajoutées à l'espace de travail. Ceci s'applique aux
|
||||||
|
noeuds <code>Debug</code>, <code>Function</code> et <code>Link</code>.</p>
|
||||||
|
<p>Une nouvelle action a également été ajoutée pour générer des noms par défaut pour les noeuds sélectionnés :</p>
|
||||||
|
<ul>
|
||||||
|
<li><b><code>Générer des noms de noeud</code></b></li>
|
||||||
|
</ul>
|
||||||
|
<p>Les actions sont accessibles à partir de la liste d'actions dans le menu principal.</p>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Node Updates",
|
||||||
|
"ja": "ノードの更新",
|
||||||
|
"fr": "Mises à jour des noeuds"
|
||||||
|
},
|
||||||
|
// 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>`,
|
||||||
|
"fr": `<ul>
|
||||||
|
<li>Le noeud de débogage peut être configuré pour compter les messages qu'il reçoit</li>
|
||||||
|
<li>Le noeud Link Call peut utiliser une propriété de message pour cibler dynamiquement le lien qu'il doit appeler</li>
|
||||||
|
<li>Le noeud de requête HTTP peut être préconfiguré avec des en-têtes HTTP</li>
|
||||||
|
</ul>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -3,12 +3,14 @@ export default {
|
|||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
'en-US': 'Create your first flow',
|
'en-US': 'Create your first flow',
|
||||||
'ja': 'はじめてのフローを作成'
|
'ja': 'はじめてのフローを作成',
|
||||||
|
'fr': "Créer votre premier flux"
|
||||||
},
|
},
|
||||||
width: 400,
|
width: 400,
|
||||||
description: {
|
description: {
|
||||||
'en-US': 'This tutorial will guide you through creating your first flow',
|
'en-US': 'This tutorial will guide you through creating your first flow',
|
||||||
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
|
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。',
|
||||||
|
'fr': "Ce didacticiel vous guidera dans la création de votre premier flux"
|
||||||
},
|
},
|
||||||
nextButton: 'start'
|
nextButton: 'start'
|
||||||
},
|
},
|
||||||
@ -16,7 +18,8 @@ export default {
|
|||||||
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
|
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
|
||||||
description: {
|
description: {
|
||||||
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
|
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
|
||||||
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
|
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。',
|
||||||
|
'fr': 'Pour ajouter un nouvel onglet, cliquez sur le bouton <i class="fa fa-plus"></i>'
|
||||||
},
|
},
|
||||||
wait: {
|
wait: {
|
||||||
type: "dom-event",
|
type: "dom-event",
|
||||||
@ -29,7 +32,8 @@ export default {
|
|||||||
direction: 'right',
|
direction: 'right',
|
||||||
description: {
|
description: {
|
||||||
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
|
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
|
||||||
'ja': 'パレットには、利用できる全てのノードが一覧表示されます。injectノードをワークスペースにドラッグします。'
|
'ja': 'パレットには、利用できる全てのノードが一覧表示されます。injectノードをワークスペースにドラッグします。',
|
||||||
|
'fr': "La palette répertorie tous les noeuds disponibles à utiliser. Faites glisser un nouveau noeud Inject dans l'espace de travail."
|
||||||
},
|
},
|
||||||
fallback: 'inset-bottom-right',
|
fallback: 'inset-bottom-right',
|
||||||
wait: {
|
wait: {
|
||||||
@ -52,7 +56,8 @@ export default {
|
|||||||
direction: 'right',
|
direction: 'right',
|
||||||
description: {
|
description: {
|
||||||
'en-US': 'Next, drag a new Debug node into the workspace.',
|
'en-US': 'Next, drag a new Debug node into the workspace.',
|
||||||
'ja': '次に、debugノードをワークスペースにドラッグします。'
|
'ja': '次に、debugノードをワークスペースにドラッグします。',
|
||||||
|
'fr': "Ensuite, faites glisser un nouveau noeud Debug dans l'espace de travail."
|
||||||
},
|
},
|
||||||
fallback: 'inset-bottom-right',
|
fallback: 'inset-bottom-right',
|
||||||
wait: {
|
wait: {
|
||||||
@ -74,7 +79,8 @@ export default {
|
|||||||
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
|
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
|
||||||
description: {
|
description: {
|
||||||
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
|
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
|
||||||
'ja': 'injectノードの出力から、debugノードの入力へワイヤーで接続します。'
|
'ja': 'injectノードの出力から、debugノードの入力へワイヤーで接続します。',
|
||||||
|
'fr': "Ajoutez un fil de la sortie du noeud Inject à l'entrée du noeud Debug"
|
||||||
},
|
},
|
||||||
fallback: 'inset-bottom-right',
|
fallback: 'inset-bottom-right',
|
||||||
wait: {
|
wait: {
|
||||||
@ -89,7 +95,8 @@ export default {
|
|||||||
element: "#red-ui-header-button-deploy",
|
element: "#red-ui-header-button-deploy",
|
||||||
description: {
|
description: {
|
||||||
'en-US': 'Deploy your changes so the flow is active in the runtime',
|
'en-US': 'Deploy your changes so the flow is active in the runtime',
|
||||||
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
|
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。',
|
||||||
|
'fr': "Déployez vos modifications afin que le flux soit actif dans le runtime"
|
||||||
},
|
},
|
||||||
width: 200,
|
width: 200,
|
||||||
wait: {
|
wait: {
|
||||||
|
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 |
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/node-help.png
vendored
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
packages/node_modules/@node-red/editor-client/src/tours/images/tab-changes.png
vendored
Normal file
After Width: | Height: | Size: 3.9 KiB |
@ -1,154 +1,230 @@
|
|||||||
export default {
|
export default {
|
||||||
version: "3.0.0",
|
version: "3.1.0",
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
titleIcon: "fa fa-map-o",
|
titleIcon: "fa fa-map-o",
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Welcome to Node-RED 3.0!",
|
"en-US": "Welcome to Node-RED 3.1!",
|
||||||
"ja": "Node-RED 3.0へようこそ!"
|
"ja": "Node-RED 3.1へようこそ!",
|
||||||
|
"fr": "Bienvenue dans Node-RED 3.1!"
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
|
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
|
||||||
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>"
|
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>",
|
||||||
|
"fr": "<p>Prenons un moment pour découvrir les nouvelles fonctionnalités de cette version.</p>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Context Menu",
|
"en-US": "New ways to work with groups",
|
||||||
"ja": "コンテキストメニュー"
|
"ja": "グループの新たな操作方法",
|
||||||
|
"fr": "De nouvelles façons de travailler avec les groupes"
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
"en-US": `<p>We have changed how you interact with groups in the editor.</p>
|
||||||
|
<ul>
|
||||||
|
<li>They don't get in the way when clicking on a node</li>
|
||||||
|
<li>They can be reordered using the Moving Forwards and Move Backwards actions</li>
|
||||||
|
<li>Multiple nodes can be dragged into a group in one go</li>
|
||||||
|
<li>Holding <code>Alt</code> when dragging a node will *remove* it from its group</li>
|
||||||
|
</ul>`,
|
||||||
|
"ja": `<p>エディタ上のグループの操作が変更されました。</p>
|
||||||
|
<ul>
|
||||||
|
<li>グループ内のノードをクリックする時に、グループが邪魔をすることが無くなりました。</li>
|
||||||
|
<li>「前面へ移動」と「背面へ移動」の動作を用いて、複数のグループの表示順序を変えることができます。</li>
|
||||||
|
<li>グループ内へ一度に複数のノードをドラッグできるようになりました。</li>
|
||||||
|
<li><code>Alt</code> を押したまま、グループ内のノードをドラッグすると、そのグループから *除く* ことができます。</li>
|
||||||
|
</ul>`,
|
||||||
|
"fr": `<p>Nous avons modifié la façon dont vous interagissez avec les groupes dans l'éditeur.</p>
|
||||||
|
<ul>
|
||||||
|
<li>Ils ne gênent plus lorsque vous cliquez sur un noeud</li>
|
||||||
|
<li>Ils peuvent être réorganisés à l'aide des actions Avancer et Reculer</li>
|
||||||
|
<li>Plusieurs noeuds peuvent être glissés dans un groupe en une seule fois</li>
|
||||||
|
<li>Maintenir <code>Alt</code> lors du déplacement d'un noeud le *supprimera* de son groupe</li>
|
||||||
|
</ul>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Change notification on tabs",
|
||||||
|
"ja": "タブ上の変更通知",
|
||||||
|
"fr": "Notification de changement sur les onglets"
|
||||||
|
},
|
||||||
|
image: 'images/tab-changes.png',
|
||||||
|
description: {
|
||||||
|
"en-US": `<p>When a tab contains undeployed changes it now shows the
|
||||||
|
same style of change icon used by nodes.</p>
|
||||||
|
<p>This will make it much easier to track down changes when you're
|
||||||
|
working across multiple flows.</p>`,
|
||||||
|
"ja": `<p>タブ内にデプロイされていない変更が存在する時は、ノードと同じスタイルで変更の印が表示されるようになりました。</p>
|
||||||
|
<p>これによって複数のフローを編集している時に、変更を見つけるのが簡単になりました。</p>`,
|
||||||
|
"fr": `<p>Lorsqu'un onglet contient des modifications non déployées, il affiche désormais le
|
||||||
|
même style d'icône de changement utilisé par les noeuds.</p>
|
||||||
|
<p>Cela facilitera grandement le suivi des modifications lorsque vous
|
||||||
|
travaillez sur plusieurs flux.</p>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "A bigger canvas to work with",
|
||||||
|
"ja": "より広くなった作業キャンバス",
|
||||||
|
"fr": "Un canevas plus grand pour travailler"
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
"en-US": `<p>The default canvas size has been increased so you can fit more
|
||||||
|
into one flow.</p>
|
||||||
|
<p>We still recommend using tools such as subflows and Link Nodes to help
|
||||||
|
keep things organised, but now you have more room to work in.</p>`,
|
||||||
|
"ja": `<p>標準のキャンバスが広くなったため、1つのフローに沢山のものを含めることができるようになりました。</p>
|
||||||
|
<p>引き続き、サブフローやリンクノードなどの方法を用いて整理することをお勧めしますが、作業できる場所が増えました。</p>`,
|
||||||
|
"fr": `<p>La taille par défaut du canevas a été augmentée pour que vous puissiez en mettre plus
|
||||||
|
sur un seul flux.</p>
|
||||||
|
<p>Nous recommandons toujours d'utiliser des outils tels que les sous-flux et les noeuds de lien pour vous aider
|
||||||
|
à garder les choses organisées, mais vous avez maintenant plus d'espace pour travailler.</p>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Finding help",
|
||||||
|
"ja": "ヘルプを見つける",
|
||||||
|
"fr": "Trouver de l'aide"
|
||||||
|
},
|
||||||
|
image: 'images/node-help.png',
|
||||||
|
description: {
|
||||||
|
"en-US": `<p>All node edit dialogs now include a link to that node's help
|
||||||
|
in the footer.</p>
|
||||||
|
<p>Clicking it will open up the Help sidebar showing the help for that node.</p>`,
|
||||||
|
"ja": `<p>全てのノードの編集ダイアログの下に、ノードのヘルプへのリンクが追加されました。</p>
|
||||||
|
<p>これをクリックすると、ノードのヘルプサイドバーが表示されます。</p>`,
|
||||||
|
"fr": `<p>Toutes les boîtes de dialogue d'édition de noeud incluent désormais un lien vers l'aide de ce noeud
|
||||||
|
dans le pied de page.</p>
|
||||||
|
<p>Cliquer dessus ouvrira la barre latérale d'aide affichant l'aide pour ce noeud.</p>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
"en-US": "Improved Context Menu",
|
||||||
|
"ja": "コンテキストメニューの改善",
|
||||||
|
"fr": "Menu contextuel amélioré"
|
||||||
},
|
},
|
||||||
image: 'images/context-menu.png',
|
image: 'images/context-menu.png',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>The editor now has its own context menu when you
|
"en-US": `<p>The editor's context menu has been expanded to make lots more of
|
||||||
right-click in the workspace.</p>
|
the built-in actions available.</p>
|
||||||
<p>This makes many of the built-in actions much easier
|
<p>Adding nodes, working with groups and plenty
|
||||||
to access.</p>`,
|
of other useful tools are now just a click away.</p>
|
||||||
"ja": `<p>ワークスペースで右クリックすると、エディタに独自のコンテキストメニューが表示されるようになりました。</p>
|
<p>The flow tab bar also has its own context menu to make working
|
||||||
<p>これによって多くの組み込み動作を、より簡単に利用できます。</p>`
|
with your flows much easier.</p>`,
|
||||||
|
"ja": `<p>より多くの組み込み動作を利用できるように、エディタのコンテキストメニューが拡張されました。</p>
|
||||||
|
<p>ノードの追加、グループの操作、その他の便利なツールをクリックするだけで実行できるようになりました。</p>
|
||||||
|
<p>フローのタブバーには、フローの操作をより簡単にする独自のコンテキストメニューもあります。</p>`,
|
||||||
|
"fr": `<p>Le menu contextuel de l'éditeur a été étendu pour faire beaucoup plus d'actions intégrées disponibles.</p>
|
||||||
|
<p>Ajouter des noeuds, travailler avec des groupes et beaucoup d'autres outils utiles sont désormais à portée de clic.</p>
|
||||||
|
<p>La barre d'onglets de flux possède également son propre menu contextuel pour faciliter l'utilisation de vos flux.</p>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Wire Junctions",
|
"en-US": "Hiding Flows",
|
||||||
"ja": "分岐点をワイヤーに追加"
|
"ja": "フローを非表示",
|
||||||
|
"fr": "Masquage de flux"
|
||||||
},
|
},
|
||||||
image: 'images/junction-slice.gif',
|
image: 'images/hiding-flows.png',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>To make it easier to route wires around your flows,
|
"en-US": `<p>Hiding flows is now done through the flow context menu.</p>
|
||||||
it is now possible to add junction nodes that give
|
<p>The 'hide' button in previous releases has been removed from the tabs
|
||||||
you more control.</p>
|
as they were being clicked accidentally too often.</p>`,
|
||||||
<p>Junctions can be added to wires by holding both the Alt key and the Shift key
|
"ja": `<p>フローを非表示にする機能は、フローのコンテキストメニューから実行するようになりました。</p>
|
||||||
then click and drag the mouse across the wires.</p>`,
|
<p>これまでのリリースでタブに存在していた「非表示」ボタンは、よく誤ってクリックされていたため、削除されました。</p>`,
|
||||||
"ja": `<p>フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。</p>
|
"fr": `<p>Le masquage des flux s'effectue désormais via le menu contextuel du flux.</p>
|
||||||
<p>Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`
|
<p>Le bouton "Masquer" des versions précédentes a été supprimé des onglets
|
||||||
|
car il était cliqué accidentellement trop souvent.</p>`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Wire Junctions",
|
"en-US": "Locking Flows",
|
||||||
"ja": "分岐点をワイヤーに追加"
|
"ja": "フローを固定",
|
||||||
|
"fr": "Verrouillage de flux"
|
||||||
},
|
},
|
||||||
image: 'images/junction-quick-add.png',
|
image: 'images/locking-flows.png',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>Junctions can also be added using the quick-add dialog.</p>
|
"en-US": `<p>Flows can now be locked to prevent accidental changes being made.</p>
|
||||||
<p>The dialog is opened by holding the Ctrl (or Cmd) key when
|
<p>When locked you cannot modify the nodes in any way.</p>
|
||||||
clicking in the workspace.</p>`,
|
<p>The flow context menu provides the options to lock and unlock flows,
|
||||||
"ja": `<p>クイック追加ダイアログを用いて、分岐点を追加することもできます。</p>
|
as well as in the Info sidebar explorer.</p>`,
|
||||||
<p>本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。</p>`
|
"ja": `<p>誤ってフローに変更が加えられてしまうのを防ぐために、フローを固定できるようになりました。</p>
|
||||||
|
<p>固定されている時は、ノードを修正することはできません。</p>
|
||||||
|
<p>フローのコンテキストメニューと、情報サイドバーのエクスプローラには、フローの固定や解除をするためのオプションが用意されています。</p>`,
|
||||||
|
"fr": `<p>Les flux peuvent désormais être verrouillés pour éviter toute modification accidentelle.</p>
|
||||||
|
<p>Lorsqu'il est verrouillé, vous ne pouvez en aucun cas modifier les noeuds.</p>
|
||||||
|
<p>Le menu contextuel du flux fournit les options pour verrouiller et déverrouiller les flux,
|
||||||
|
ainsi que dans l'explorateur de la barre latérale d'informations.</p>`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Debug Path Tooltip",
|
"en-US": "Adding Images to node/flow descriptions",
|
||||||
"ja": "デバッグパスのツールチップ"
|
"ja": "ノードやフローの説明へ画像を追加",
|
||||||
|
"fr": "Ajout d'images aux descriptions de noeud/flux"
|
||||||
},
|
},
|
||||||
image: 'images/debug-path-tooltip.png',
|
// image: 'images/debug-path-tooltip.png',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>When hovering over a node name in the Debug sidebar, a
|
"en-US": `<p>You can now add images to a node's or flows's description.</p>
|
||||||
new tooltip shows the full location of the node.</p>
|
<p>Simply drag the image into the text editor and it will get added inline.</p>
|
||||||
<p>This is useful when working with subflows, making it
|
<p>When the description is shown in the Info sidebar, the image will be displayed.</p>`,
|
||||||
much easier to identify exactly which node generated
|
"ja": `<p>ノードまたはフローの説明に、画像を追加できるようになりました。</p>
|
||||||
the message.</p>
|
<p>画像をテキストエディタにドラッグするだけで、行内に埋め込まれます。</p>
|
||||||
<p>Clicking on any item in the list will reveal it in
|
<p>情報サイドバーの説明を開くと、その画像が表示されます。</p>`,
|
||||||
the workspace.</p>`,
|
"fr": `<p>Vous pouvez désormais ajouter des images à la description d'un noeud ou d'un flux.</p>
|
||||||
"ja": `<p>デバックサイドバー内のノード名の上にマウスカーソルを乗せると、新たにツールチップが表示され、ノードの場所が分かるようになっています。</p>
|
<p>Faites simplement glisser l'image dans l'éditeur de texte et elle sera ajoutée en ligne.</p>
|
||||||
<p>これは、サブフローを用いる時に役立つ機能であり、メッセージがどのノードから出力されたかを正確に特定することが遥かに簡単になります。</p>
|
<p>Lorsque la description s'affiche dans la barre latérale d'informations, l'image s'affiche.</p>`
|
||||||
<p>本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。</p>`
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
"en-US": "Continuous Search",
|
"en-US": "Adding Mermaid Diagrams",
|
||||||
"ja": "連続した検索"
|
"ja": "Mermaid図を追加",
|
||||||
|
"fr": "Ajout de diagrammes Mermaid"
|
||||||
},
|
},
|
||||||
image: 'images/continuous-search.png',
|
image: 'images/mermaid.png',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>When searching for things in the editor, a new toolbar in
|
"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>
|
||||||
the workspace provides options to quickly jump between
|
<p>This gives you much richer options for documenting your flows.</p>`,
|
||||||
the search results.</p>`,
|
"ja": `<p>ノードやフローの説明に、<a href="https://github.com/mermaid-js/mermaid">Mermaid</a>図を直接追加することもできます。</p>
|
||||||
"ja": `<p>ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。</p>`
|
<p>これによって、フローを説明する文書作成の選択肢がより多くなります。</p>`,
|
||||||
|
"fr": `<p>Vous pouvez également ajouter des diagrammes <a href="https://github.com/mermaid-js/mermaid">Mermaid</a> directement dans vos descriptions de noeud ou de flux.</p>
|
||||||
|
<p>Cela vous offre des options beaucoup plus riches pour documenter vos flux.</p>`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: {
|
title: {
|
||||||
"en-US": "New wiring actions",
|
"en-US": "Managing Global Environment Variables",
|
||||||
"ja": "新しいワイヤー操作"
|
"ja": "グローバル環境変数の管理",
|
||||||
|
"fr": "Gestion des variables d'environnement globales"
|
||||||
},
|
},
|
||||||
image: "images/split-wire-with-links.gif",
|
image: 'images/global-env-vars.png',
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<p>A new action has been added that will replace a wire with a pair of connected Link nodes:</p>
|
"en-US": `<p>You can set environment variables that apply to all nodes and flows in the new
|
||||||
<ul>
|
'Global Environment Variables' section of User Settings.</p>`,
|
||||||
<li><b><code>Split Wire With Link Nodes</code></b></li>
|
"ja": `<p>ユーザ設定に新しく追加された「大域環境変数」のセクションで、全てのノードとフローに適用される環境変数を登録できます。</p>`,
|
||||||
</ul>
|
"fr": `<p>Vous pouvez définir des variables d'environnement qui s'appliquent à tous les noeuds et flux dans la nouvelle
|
||||||
<p>Actions can be accessed from the Action List in the main menu.</p>`,
|
section "Global Environment Variables" des paramètres utilisateur.</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: {
|
title: {
|
||||||
"en-US": "Node Updates",
|
"en-US": "Node Updates",
|
||||||
"ja": "ノードの更新"
|
"ja": "ノードの更新",
|
||||||
|
"fr": "Mises à jour des noeuds"
|
||||||
},
|
},
|
||||||
// image: "images/",
|
// image: "images/",
|
||||||
description: {
|
description: {
|
||||||
"en-US": `<ul>
|
"en-US": `<p>The core nodes have received lots of minor fixes, documentation updates and
|
||||||
<li>The Debug node can be configured to count messages it receives</li>
|
small enhancements. Check the full changelog in the Help sidebar for a full list.</p>`,
|
||||||
<li>The Link Call node can use a message property to dynamically target the link it should call</li>
|
"ja": `<p>コアノードにマイナーな修正、ドキュメント更新、小規模な拡張が数多く追加されています。全ての一覧は、ヘルプサイドバーの全ての更新履歴を確認してください。</p>`,
|
||||||
<li>The HTTP Request node can be preconfigured with HTTP headers</li>
|
"fr": `<p>Les noeuds principaux ont reçu de nombreux correctifs mineurs, mises à jour de la documentation et
|
||||||
</ul>`,
|
petites améliorations. Consulter le journal des modifications complet dans la barre latérale d'aide.</p>`
|
||||||
"ja": `<ul>
|
|
||||||
<li>Debugノードは、受信したメッセージの数をカウントするよう設定できるようになりました。</li>
|
|
||||||
<li>Link Callノードは、メッセージのプロパティによって、呼び出し対象のlinkを動的に指定できるようになりました。</li>
|
|
||||||
<li>HTTP Requestノードは、HTTPヘッダを事前設定できるようになりました。</li>
|
|
||||||
</ul>`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/Steve-Mcl/monaco-editor-esm-i18n */
|
||||||
|
|
||||||
|
|
||||||
interface NodeMessage {
|
interface NodeMessage {
|
||||||
topic?: string;
|
topic?: string;
|
||||||
@ -281,5 +280,5 @@ declare class env {
|
|||||||
* @example
|
* @example
|
||||||
* ```const flowName = env.get("NR_FLOW_NAME");```
|
* ```const flowName = env.get("NR_FLOW_NAME");```
|
||||||
*/
|
*/
|
||||||
static get(name:string) :string;
|
static get(name:string) :any;
|
||||||
}
|
}
|
||||||
|
11
packages/node_modules/@node-red/editor-client/src/types/node/assert/strict.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/Steve-Mcl/monaco-editor-esm-i18n */
|
||||||
|
|
||||||
|
declare module 'assert/strict' {
|
||||||
|
import { strict } from 'node:assert';
|
||||||
|
export = strict;
|
||||||
|
}
|
||||||
|
declare module 'node:assert/strict' {
|
||||||
|
import { strict } from 'node:assert';
|
||||||
|
export = strict;
|
||||||
|
}
|
@ -2,18 +2,49 @@
|
|||||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/Steve-Mcl/monaco-editor-esm-i18n */
|
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/Steve-Mcl/monaco-editor-esm-i18n */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async Hooks module: https://nodejs.org/api/async_hooks.html
|
* The `async_hooks` module provides an API to track asynchronous resources. It
|
||||||
|
* can be accessed using:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import async_hooks from 'async_hooks';
|
||||||
|
* ```
|
||||||
|
* @experimental
|
||||||
|
* @see [source](https://github.com/nodejs/node/blob/v16.9.0/lib/async_hooks.js)
|
||||||
*/
|
*/
|
||||||
declare module 'async_hooks' {
|
declare module 'async_hooks' {
|
||||||
/**
|
/**
|
||||||
* Returns the asyncId of the current execution context.
|
* ```js
|
||||||
|
* import { executionAsyncId } from 'async_hooks';
|
||||||
|
*
|
||||||
|
* console.log(executionAsyncId()); // 1 - bootstrap
|
||||||
|
* fs.open(path, 'r', (err, fd) => {
|
||||||
|
* console.log(executionAsyncId()); // 6 - open()
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The ID returned from `executionAsyncId()` is related to execution timing, not
|
||||||
|
* causality (which is covered by `triggerAsyncId()`):
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const server = net.createServer((conn) => {
|
||||||
|
* // Returns the ID of the server, not of the new connection, because the
|
||||||
|
* // callback runs in the execution scope of the server's MakeCallback().
|
||||||
|
* async_hooks.executionAsyncId();
|
||||||
|
*
|
||||||
|
* }).listen(port, () => {
|
||||||
|
* // Returns the ID of a TickObject (process.nextTick()) because all
|
||||||
|
* // callbacks passed to .listen() are wrapped in a nextTick().
|
||||||
|
* async_hooks.executionAsyncId();
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Promise contexts may not get precise `executionAsyncIds` by default.
|
||||||
|
* See the section on `promise execution tracking`.
|
||||||
|
* @since v8.1.0
|
||||||
|
* @return The `asyncId` of the current execution context. Useful to track when something calls.
|
||||||
*/
|
*/
|
||||||
function executionAsyncId(): number;
|
function executionAsyncId(): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The resource representing the current execution.
|
|
||||||
* Useful to store data within the resource.
|
|
||||||
*
|
|
||||||
* Resource objects returned by `executionAsyncResource()` are most often internal
|
* Resource objects returned by `executionAsyncResource()` are most often internal
|
||||||
* Node.js handle objects with undocumented APIs. Using any functions or properties
|
* Node.js handle objects with undocumented APIs. Using any functions or properties
|
||||||
* on the object is likely to crash your application and should be avoided.
|
* on the object is likely to crash your application and should be avoided.
|
||||||
@ -21,14 +52,70 @@ declare module 'async_hooks' {
|
|||||||
* Using `executionAsyncResource()` in the top-level execution context will
|
* Using `executionAsyncResource()` in the top-level execution context will
|
||||||
* return an empty object as there is no handle or request object to use,
|
* return an empty object as there is no handle or request object to use,
|
||||||
* but having an object representing the top-level can be helpful.
|
* but having an object representing the top-level can be helpful.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { open } from 'fs';
|
||||||
|
* import { executionAsyncId, executionAsyncResource } from 'async_hooks';
|
||||||
|
*
|
||||||
|
* console.log(executionAsyncId(), executionAsyncResource()); // 1 {}
|
||||||
|
* open(new URL(import.meta.url), 'r', (err, fd) => {
|
||||||
|
* console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This can be used to implement continuation local storage without the
|
||||||
|
* use of a tracking `Map` to store the metadata:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { createServer } from 'http';
|
||||||
|
* import {
|
||||||
|
* executionAsyncId,
|
||||||
|
* executionAsyncResource,
|
||||||
|
* createHook
|
||||||
|
* } from 'async_hooks';
|
||||||
|
* const sym = Symbol('state'); // Private symbol to avoid pollution
|
||||||
|
*
|
||||||
|
* createHook({
|
||||||
|
* init(asyncId, type, triggerAsyncId, resource) {
|
||||||
|
* const cr = executionAsyncResource();
|
||||||
|
* if (cr) {
|
||||||
|
* resource[sym] = cr[sym];
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }).enable();
|
||||||
|
*
|
||||||
|
* const server = createServer((req, res) => {
|
||||||
|
* executionAsyncResource()[sym] = { state: req.url };
|
||||||
|
* setTimeout(function() {
|
||||||
|
* res.end(JSON.stringify(executionAsyncResource()[sym]));
|
||||||
|
* }, 100);
|
||||||
|
* }).listen(3000);
|
||||||
|
* ```
|
||||||
|
* @since v13.9.0, v12.17.0
|
||||||
|
* @return The resource representing the current execution. Useful to store data within the resource.
|
||||||
*/
|
*/
|
||||||
function executionAsyncResource(): object;
|
function executionAsyncResource(): object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ID of the resource responsible for calling the callback that is currently being executed.
|
* ```js
|
||||||
|
* const server = net.createServer((conn) => {
|
||||||
|
* // The resource that caused (or triggered) this callback to be called
|
||||||
|
* // was that of the new connection. Thus the return value of triggerAsyncId()
|
||||||
|
* // is the asyncId of "conn".
|
||||||
|
* async_hooks.triggerAsyncId();
|
||||||
|
*
|
||||||
|
* }).listen(port, () => {
|
||||||
|
* // Even though all callbacks passed to .listen() are wrapped in a nextTick()
|
||||||
|
* // the callback itself exists because the call to the server's .listen()
|
||||||
|
* // was made. So the return value would be the ID of the server.
|
||||||
|
* async_hooks.triggerAsyncId();
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Promise contexts may not get valid `triggerAsyncId`s by default. See
|
||||||
|
* the section on `promise execution tracking`.
|
||||||
|
* @return The ID of the resource responsible for calling the callback that is currently being executed.
|
||||||
*/
|
*/
|
||||||
function triggerAsyncId(): number;
|
function triggerAsyncId(): number;
|
||||||
|
|
||||||
interface HookCallbacks {
|
interface HookCallbacks {
|
||||||
/**
|
/**
|
||||||
* Called when a class is constructed that has the possibility to emit an asynchronous event.
|
* Called when a class is constructed that has the possibility to emit an asynchronous event.
|
||||||
@ -38,60 +125,88 @@ declare module 'async_hooks' {
|
|||||||
* @param resource reference to the resource representing the async operation, needs to be released during destroy
|
* @param resource reference to the resource representing the async operation, needs to be released during destroy
|
||||||
*/
|
*/
|
||||||
init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
|
init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When an asynchronous operation is initiated or completes a callback is called to notify the user.
|
* When an asynchronous operation is initiated or completes a callback is called to notify the user.
|
||||||
* The before callback is called just before said callback is executed.
|
* The before callback is called just before said callback is executed.
|
||||||
* @param asyncId the unique identifier assigned to the resource about to execute the callback.
|
* @param asyncId the unique identifier assigned to the resource about to execute the callback.
|
||||||
*/
|
*/
|
||||||
before?(asyncId: number): void;
|
before?(asyncId: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called immediately after the callback specified in before is completed.
|
* Called immediately after the callback specified in before is completed.
|
||||||
* @param asyncId the unique identifier assigned to the resource which has executed the callback.
|
* @param asyncId the unique identifier assigned to the resource which has executed the callback.
|
||||||
*/
|
*/
|
||||||
after?(asyncId: number): void;
|
after?(asyncId: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a promise has resolve() called. This may not be in the same execution id
|
* Called when a promise has resolve() called. This may not be in the same execution id
|
||||||
* as the promise itself.
|
* as the promise itself.
|
||||||
* @param asyncId the unique id for the promise that was resolve()d.
|
* @param asyncId the unique id for the promise that was resolve()d.
|
||||||
*/
|
*/
|
||||||
promiseResolve?(asyncId: number): void;
|
promiseResolve?(asyncId: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after the resource corresponding to asyncId is destroyed
|
* Called after the resource corresponding to asyncId is destroyed
|
||||||
* @param asyncId a unique ID for the async resource
|
* @param asyncId a unique ID for the async resource
|
||||||
*/
|
*/
|
||||||
destroy?(asyncId: number): void;
|
destroy?(asyncId: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AsyncHook {
|
interface AsyncHook {
|
||||||
/**
|
/**
|
||||||
* Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
|
* Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
|
||||||
*/
|
*/
|
||||||
enable(): this;
|
enable(): this;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.
|
* Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.
|
||||||
*/
|
*/
|
||||||
disable(): this;
|
disable(): this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers functions to be called for different lifetime events of each async operation.
|
* Registers functions to be called for different lifetime events of each async
|
||||||
* @param options the callbacks to register
|
* operation.
|
||||||
* @return an AsyncHooks instance used for disabling and enabling hooks
|
*
|
||||||
|
* The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the
|
||||||
|
* respective asynchronous event during a resource's lifetime.
|
||||||
|
*
|
||||||
|
* All callbacks are optional. For example, if only resource cleanup needs to
|
||||||
|
* be tracked, then only the `destroy` callback needs to be passed. The
|
||||||
|
* specifics of all functions that can be passed to `callbacks` is in the `Hook Callbacks` section.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { createHook } from 'async_hooks';
|
||||||
|
*
|
||||||
|
* const asyncHook = createHook({
|
||||||
|
* init(asyncId, type, triggerAsyncId, resource) { },
|
||||||
|
* destroy(asyncId) { }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The callbacks will be inherited via the prototype chain:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* class MyAsyncCallbacks {
|
||||||
|
* init(asyncId, type, triggerAsyncId, resource) { }
|
||||||
|
* destroy(asyncId) {}
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* class MyAddedCallbacks extends MyAsyncCallbacks {
|
||||||
|
* before(asyncId) { }
|
||||||
|
* after(asyncId) { }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Because promises are asynchronous resources whose lifecycle is tracked
|
||||||
|
* via the async hooks mechanism, the `init()`, `before()`, `after()`, and`destroy()` callbacks _must not_ be async functions that return promises.
|
||||||
|
* @since v8.1.0
|
||||||
|
* @param callbacks The `Hook Callbacks` to register
|
||||||
|
* @return Instance used for disabling and enabling hooks
|
||||||
*/
|
*/
|
||||||
function createHook(options: HookCallbacks): AsyncHook;
|
function createHook(callbacks: HookCallbacks): AsyncHook;
|
||||||
|
|
||||||
interface AsyncResourceOptions {
|
interface AsyncResourceOptions {
|
||||||
/**
|
/**
|
||||||
* The ID of the execution context that created this async event.
|
* The ID of the execution context that created this async event.
|
||||||
* @default executionAsyncId()
|
* @default executionAsyncId()
|
||||||
*/
|
*/
|
||||||
triggerAsyncId?: number | undefined;
|
triggerAsyncId?: number | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables automatic `emitDestroy` when the object is garbage collected.
|
* Disables automatic `emitDestroy` when the object is garbage collected.
|
||||||
* This usually does not need to be set (even if `emitDestroy` is called
|
* This usually does not need to be set (even if `emitDestroy` is called
|
||||||
@ -101,10 +216,42 @@ declare module 'async_hooks' {
|
|||||||
*/
|
*/
|
||||||
requireManualDestroy?: boolean | undefined;
|
requireManualDestroy?: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class AsyncResource was designed to be extended by the embedder's async resources.
|
* The class `AsyncResource` is designed to be extended by the embedder's async
|
||||||
* Using this users can easily trigger the lifetime events of their own resources.
|
* resources. Using this, users can easily trigger the lifetime events of their
|
||||||
|
* own resources.
|
||||||
|
*
|
||||||
|
* The `init` hook will trigger when an `AsyncResource` is instantiated.
|
||||||
|
*
|
||||||
|
* The following is an overview of the `AsyncResource` API.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { AsyncResource, executionAsyncId } from 'async_hooks';
|
||||||
|
*
|
||||||
|
* // AsyncResource() is meant to be extended. Instantiating a
|
||||||
|
* // new AsyncResource() also triggers init. If triggerAsyncId is omitted then
|
||||||
|
* // async_hook.executionAsyncId() is used.
|
||||||
|
* const asyncResource = new AsyncResource(
|
||||||
|
* type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false }
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* // Run a function in the execution context of the resource. This will
|
||||||
|
* // * establish the context of the resource
|
||||||
|
* // * trigger the AsyncHooks before callbacks
|
||||||
|
* // * call the provided function `fn` with the supplied arguments
|
||||||
|
* // * trigger the AsyncHooks after callbacks
|
||||||
|
* // * restore the original execution context
|
||||||
|
* asyncResource.runInAsyncScope(fn, thisArg, ...args);
|
||||||
|
*
|
||||||
|
* // Call AsyncHooks destroy callbacks.
|
||||||
|
* asyncResource.emitDestroy();
|
||||||
|
*
|
||||||
|
* // Return the unique ID assigned to the AsyncResource instance.
|
||||||
|
* asyncResource.asyncId();
|
||||||
|
*
|
||||||
|
* // Return the trigger ID for the AsyncResource instance.
|
||||||
|
* asyncResource.triggerAsyncId();
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
class AsyncResource {
|
class AsyncResource {
|
||||||
/**
|
/**
|
||||||
@ -114,115 +261,236 @@ declare module 'async_hooks' {
|
|||||||
* @param type The type of async event.
|
* @param type The type of async event.
|
||||||
* @param triggerAsyncId The ID of the execution context that created
|
* @param triggerAsyncId The ID of the execution context that created
|
||||||
* this async event (default: `executionAsyncId()`), or an
|
* this async event (default: `executionAsyncId()`), or an
|
||||||
* AsyncResourceOptions object (since 9.3)
|
* AsyncResourceOptions object (since v9.3.0)
|
||||||
*/
|
*/
|
||||||
constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions);
|
constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds the given function to the current execution context.
|
* Binds the given function to the current execution context.
|
||||||
|
*
|
||||||
|
* The returned function will have an `asyncResource` property referencing
|
||||||
|
* the `AsyncResource` to which the function is bound.
|
||||||
|
* @since v14.8.0, v12.19.0
|
||||||
* @param fn The function to bind to the current execution context.
|
* @param fn The function to bind to the current execution context.
|
||||||
* @param type An optional name to associate with the underlying `AsyncResource`.
|
* @param type An optional name to associate with the underlying `AsyncResource`.
|
||||||
*/
|
*/
|
||||||
static bind<Func extends (...args: any[]) => any>(fn: Func, type?: string): Func & { asyncResource: AsyncResource };
|
static bind<Func extends (this: ThisArg, ...args: any[]) => any, ThisArg>(
|
||||||
|
fn: Func,
|
||||||
|
type?: string,
|
||||||
|
thisArg?: ThisArg
|
||||||
|
): Func & {
|
||||||
|
asyncResource: AsyncResource;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Binds the given function to execute to this `AsyncResource`'s scope.
|
* Binds the given function to execute to this `AsyncResource`'s scope.
|
||||||
|
*
|
||||||
|
* The returned function will have an `asyncResource` property referencing
|
||||||
|
* the `AsyncResource` to which the function is bound.
|
||||||
|
* @since v14.8.0, v12.19.0
|
||||||
* @param fn The function to bind to the current `AsyncResource`.
|
* @param fn The function to bind to the current `AsyncResource`.
|
||||||
*/
|
*/
|
||||||
bind<Func extends (...args: any[]) => any>(fn: Func): Func & { asyncResource: AsyncResource };
|
bind<Func extends (...args: any[]) => any>(
|
||||||
|
fn: Func
|
||||||
|
): Func & {
|
||||||
|
asyncResource: AsyncResource;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Call the provided function with the provided arguments in the
|
* Call the provided function with the provided arguments in the execution context
|
||||||
* execution context of the async resource. This will establish the
|
* of the async resource. This will establish the context, trigger the AsyncHooks
|
||||||
* context, trigger the AsyncHooks before callbacks, call the function,
|
* before callbacks, call the function, trigger the AsyncHooks after callbacks, and
|
||||||
* trigger the AsyncHooks after callbacks, and then restore the original
|
* then restore the original execution context.
|
||||||
* execution context.
|
* @since v9.6.0
|
||||||
* @param fn The function to call in the execution context of this
|
* @param fn The function to call in the execution context of this async resource.
|
||||||
* async resource.
|
|
||||||
* @param thisArg The receiver to be used for the function call.
|
* @param thisArg The receiver to be used for the function call.
|
||||||
* @param args Optional arguments to pass to the function.
|
* @param args Optional arguments to pass to the function.
|
||||||
*/
|
*/
|
||||||
runInAsyncScope<This, Result>(fn: (this: This, ...args: any[]) => Result, thisArg?: This, ...args: any[]): Result;
|
runInAsyncScope<This, Result>(fn: (this: This, ...args: any[]) => Result, thisArg?: This, ...args: any[]): Result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call AsyncHooks destroy callbacks.
|
* Call all `destroy` hooks. This should only ever be called once. An error will
|
||||||
|
* be thrown if it is called more than once. This **must** be manually called. If
|
||||||
|
* the resource is left to be collected by the GC then the `destroy` hooks will
|
||||||
|
* never be called.
|
||||||
|
* @return A reference to `asyncResource`.
|
||||||
*/
|
*/
|
||||||
emitDestroy(): this;
|
emitDestroy(): this;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the unique ID assigned to this AsyncResource instance.
|
* @return The unique `asyncId` assigned to the resource.
|
||||||
*/
|
*/
|
||||||
asyncId(): number;
|
asyncId(): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the trigger ID for this AsyncResource instance.
|
*
|
||||||
|
* @return The same `triggerAsyncId` that is passed to the `AsyncResource` constructor.
|
||||||
*/
|
*/
|
||||||
triggerAsyncId(): number;
|
triggerAsyncId(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When having multiple instances of `AsyncLocalStorage`, they are independent
|
* This class creates stores that stay coherent through asynchronous operations.
|
||||||
* from each other. It is safe to instantiate this class multiple times.
|
*
|
||||||
|
* While you can create your own implementation on top of the `async_hooks` module,`AsyncLocalStorage` should be preferred as it is a performant and memory safe
|
||||||
|
* implementation that involves significant optimizations that are non-obvious to
|
||||||
|
* implement.
|
||||||
|
*
|
||||||
|
* The following example uses `AsyncLocalStorage` to build a simple logger
|
||||||
|
* that assigns IDs to incoming HTTP requests and includes them in messages
|
||||||
|
* logged within each request.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import http from 'http';
|
||||||
|
* import { AsyncLocalStorage } from 'async_hooks';
|
||||||
|
*
|
||||||
|
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||||
|
*
|
||||||
|
* function logWithId(msg) {
|
||||||
|
* const id = asyncLocalStorage.getStore();
|
||||||
|
* console.log(`${id !== undefined ? id : '-'}:`, msg);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* let idSeq = 0;
|
||||||
|
* http.createServer((req, res) => {
|
||||||
|
* asyncLocalStorage.run(idSeq++, () => {
|
||||||
|
* logWithId('start');
|
||||||
|
* // Imagine any chain of async operations here
|
||||||
|
* setImmediate(() => {
|
||||||
|
* logWithId('finish');
|
||||||
|
* res.end();
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
* }).listen(8080);
|
||||||
|
*
|
||||||
|
* http.get('http://localhost:8080');
|
||||||
|
* http.get('http://localhost:8080');
|
||||||
|
* // Prints:
|
||||||
|
* // 0: start
|
||||||
|
* // 1: start
|
||||||
|
* // 0: finish
|
||||||
|
* // 1: finish
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Each instance of `AsyncLocalStorage` maintains an independent storage context.
|
||||||
|
* Multiple instances can safely exist simultaneously without risk of interfering
|
||||||
|
* with each other data.
|
||||||
|
* @since v13.10.0, v12.17.0
|
||||||
*/
|
*/
|
||||||
class AsyncLocalStorage<T> {
|
class AsyncLocalStorage<T> {
|
||||||
/**
|
/**
|
||||||
* This method disables the instance of `AsyncLocalStorage`. All subsequent calls
|
* Disables the instance of `AsyncLocalStorage`. All subsequent calls
|
||||||
* to `asyncLocalStorage.getStore()` will return `undefined` until
|
* to `asyncLocalStorage.getStore()` will return `undefined` until`asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()` is called again.
|
||||||
* `asyncLocalStorage.run()` is called again.
|
|
||||||
*
|
*
|
||||||
* When calling `asyncLocalStorage.disable()`, all current contexts linked to the
|
* When calling `asyncLocalStorage.disable()`, all current contexts linked to the
|
||||||
* instance will be exited.
|
* instance will be exited.
|
||||||
*
|
*
|
||||||
* Calling `asyncLocalStorage.disable()` is required before the
|
* Calling `asyncLocalStorage.disable()` is required before the`asyncLocalStorage` can be garbage collected. This does not apply to stores
|
||||||
* `asyncLocalStorage` can be garbage collected. This does not apply to stores
|
|
||||||
* provided by the `asyncLocalStorage`, as those objects are garbage collected
|
* provided by the `asyncLocalStorage`, as those objects are garbage collected
|
||||||
* along with the corresponding async resources.
|
* along with the corresponding async resources.
|
||||||
*
|
*
|
||||||
* This method is to be used when the `asyncLocalStorage` is not in use anymore
|
* Use this method when the `asyncLocalStorage` is not in use anymore
|
||||||
* in the current process.
|
* in the current process.
|
||||||
|
* @since v13.10.0, v12.17.0
|
||||||
|
* @experimental
|
||||||
*/
|
*/
|
||||||
disable(): void;
|
disable(): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the current store. If this method is called outside of an
|
* Returns the current store.
|
||||||
* asynchronous context initialized by calling `asyncLocalStorage.run`, it will
|
* If called outside of an asynchronous context initialized by
|
||||||
* return `undefined`.
|
* calling `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()`, it
|
||||||
|
* returns `undefined`.
|
||||||
|
* @since v13.10.0, v12.17.0
|
||||||
*/
|
*/
|
||||||
getStore(): T | undefined;
|
getStore(): T | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This methods runs a function synchronously within a context and return its
|
* Runs a function synchronously within a context and returns its
|
||||||
* return value. The store is not accessible outside of the callback function or
|
* return value. The store is not accessible outside of the callback function or
|
||||||
* the asynchronous operations created within the callback.
|
* the asynchronous operations created within the callback.
|
||||||
*
|
*
|
||||||
* Optionally, arguments can be passed to the function. They will be passed to the
|
* The optional `args` are passed to the callback function.
|
||||||
* callback function.
|
|
||||||
*
|
*
|
||||||
* I the callback function throws an error, it will be thrown by `run` too. The
|
* If the callback function throws an error, the error is thrown by `run()` too.
|
||||||
* stacktrace will not be impacted by this call and the context will be exited.
|
* The stacktrace is not impacted by this call and the context is exited.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const store = { id: 2 };
|
||||||
|
* try {
|
||||||
|
* asyncLocalStorage.run(store, () => {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the store object
|
||||||
|
* throw new Error();
|
||||||
|
* });
|
||||||
|
* } catch (e) {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns undefined
|
||||||
|
* // The error will be caught here
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* @since v13.10.0, v12.17.0
|
||||||
*/
|
*/
|
||||||
// TODO: Apply generic vararg once available
|
run<R, TArgs extends any[]>(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R;
|
||||||
run<R>(store: T, callback: (...args: any[]) => R, ...args: any[]): R;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This methods runs a function synchronously outside of a context and return its
|
* Runs a function synchronously outside of a context and returns its
|
||||||
* return value. The store is not accessible within the callback function or the
|
* return value. The store is not accessible within the callback function or
|
||||||
* asynchronous operations created within the callback.
|
* the asynchronous operations created within the callback. Any `getStore()`call done within the callback function will always return `undefined`.
|
||||||
*
|
*
|
||||||
* Optionally, arguments can be passed to the function. They will be passed to the
|
* The optional `args` are passed to the callback function.
|
||||||
* callback function.
|
|
||||||
*
|
*
|
||||||
* If the callback function throws an error, it will be thrown by `exit` too. The
|
* If the callback function throws an error, the error is thrown by `exit()` too.
|
||||||
* stacktrace will not be impacted by this call and the context will be
|
* The stacktrace is not impacted by this call and the context is re-entered.
|
||||||
* re-entered.
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // Within a call to run
|
||||||
|
* try {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the store object or value
|
||||||
|
* asyncLocalStorage.exit(() => {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns undefined
|
||||||
|
* throw new Error();
|
||||||
|
* });
|
||||||
|
* } catch (e) {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the same object or value
|
||||||
|
* // The error will be caught here
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* @since v13.10.0, v12.17.0
|
||||||
|
* @experimental
|
||||||
*/
|
*/
|
||||||
// TODO: Apply generic vararg once available
|
exit<R, TArgs extends any[]>(callback: (...args: TArgs) => R, ...args: TArgs): R;
|
||||||
exit<R>(callback: (...args: any[]) => R, ...args: any[]): R;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calling `asyncLocalStorage.enterWith(store)` will transition into the context
|
* Transitions into the context for the remainder of the current
|
||||||
* for the remainder of the current synchronous execution and will persist
|
* synchronous execution and then persists the store through any following
|
||||||
* through any following asynchronous calls.
|
* asynchronous calls.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const store = { id: 1 };
|
||||||
|
* // Replaces previous store with the given store object
|
||||||
|
* asyncLocalStorage.enterWith(store);
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the store object
|
||||||
|
* someAsyncOperation(() => {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the same object
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This transition will continue for the _entire_ synchronous execution.
|
||||||
|
* This means that if, for example, the context is entered within an event
|
||||||
|
* handler subsequent event handlers will also run within that context unless
|
||||||
|
* specifically bound to another context with an `AsyncResource`. That is why`run()` should be preferred over `enterWith()` unless there are strong reasons
|
||||||
|
* to use the latter method.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const store = { id: 1 };
|
||||||
|
*
|
||||||
|
* emitter.on('my-event', () => {
|
||||||
|
* asyncLocalStorage.enterWith(store);
|
||||||
|
* });
|
||||||
|
* emitter.on('my-event', () => {
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the same object
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* asyncLocalStorage.getStore(); // Returns undefined
|
||||||
|
* emitter.emit('my-event');
|
||||||
|
* asyncLocalStorage.getStore(); // Returns the same object
|
||||||
|
* ```
|
||||||
|
* @since v13.11.0, v12.17.0
|
||||||
|
* @experimental
|
||||||
*/
|
*/
|
||||||
enterWith(store: T): void;
|
enterWith(store: T): void;
|
||||||
}
|
}
|
||||||
|