mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
158 Commits
0.20.0-bet
...
0.20.2
Author | SHA1 | Date | |
---|---|---|---|
|
d59bf84470 | ||
|
161ee17f45 | ||
|
8aa00b0cfc | ||
|
afe89c3621 | ||
|
bdf68311b4 | ||
|
afa69f4c0e | ||
|
6fe2b24592 | ||
|
7442b356e3 | ||
|
1d7be6457f | ||
|
c9ff05ba80 | ||
|
faae184f1c | ||
|
515a8a9bbb | ||
|
58914e5c5f | ||
|
c944eaab5c | ||
|
d3d9533493 | ||
|
9c474cc089 | ||
|
3f1b0b986f | ||
|
28e08ebaf5 | ||
|
3213c03754 | ||
|
4447288a4c | ||
|
eee4e83a1e | ||
|
a67b492620 | ||
|
6062ff2748 | ||
|
3b11195caa | ||
|
9946ea111c | ||
|
7074d66f8e | ||
|
008b26f329 | ||
|
b246f0779f | ||
|
dc89218702 | ||
|
3c013b3533 | ||
|
fe0d0f08e4 | ||
|
38b5063038 | ||
|
e55481a454 | ||
|
7063a88513 | ||
|
a9bf3d0226 | ||
|
781b3aff1b | ||
|
b011b9203b | ||
|
39344fcae5 | ||
|
a046b357da | ||
|
d8e4020cec | ||
|
f80b172022 | ||
|
66fc4b536c | ||
|
1f97ccdddb | ||
|
308d6889a7 | ||
|
c3b9982c44 | ||
|
fab796e4e4 | ||
|
749db6ba82 | ||
|
12d6c4ddf5 | ||
|
430a03bb14 | ||
|
43f21fc7aa | ||
|
b27da3d1a0 | ||
|
4463a8e3b2 | ||
|
9e74ddac48 | ||
|
5f62e41d62 | ||
|
19a103d3a0 | ||
|
8fb6bc059e | ||
|
8f61a0d258 | ||
|
7fa589e430 | ||
|
6d8d826764 | ||
|
a40e84e1f6 | ||
|
4844c2123f | ||
|
236d437430 | ||
|
ae726c199b | ||
|
e7f54f005c | ||
|
e7b1ec6904 | ||
|
f4f664a4a2 | ||
|
fec52a8151 | ||
|
d8b4c1e209 | ||
|
eac853c7dd | ||
|
a04337a270 | ||
|
50d7e16365 | ||
|
ef7bc931b7 | ||
|
41de771074 | ||
|
2ebdd6c5cb | ||
|
b51cfcc753 | ||
|
91cc03dd80 | ||
|
9d673a213e | ||
|
97e789538e | ||
|
e05ff01d57 | ||
|
0748dff355 | ||
|
28d4084aa0 | ||
|
afd2ccfb4f | ||
|
057127f4de | ||
|
2937b25d6d | ||
|
419f26db87 | ||
|
be1b9c0e43 | ||
|
894d28c60b | ||
|
06cc08d9f7 | ||
|
75393c0b28 | ||
|
bdc1da70c1 | ||
|
7cef990ba6 | ||
|
fb0f12bb20 | ||
|
e94b8d3e84 | ||
|
8c00e1fdf4 | ||
|
a31fa82284 | ||
|
5d0af45d8f | ||
|
e9f248020e | ||
|
a8e1058af6 | ||
|
1a087fd799 | ||
|
50c81533e0 | ||
|
5eab9aa4b1 | ||
|
1970cbfe37 | ||
|
6d736201f9 | ||
|
51ec52b573 | ||
|
d099387186 | ||
|
3f91e4da66 | ||
|
4124159378 | ||
|
18f3789e29 | ||
|
a713c92530 | ||
|
7828af591e | ||
|
d432dba726 | ||
|
72ae87857f | ||
|
724acff591 | ||
|
482b432e2c | ||
|
351c0cb0a8 | ||
|
314a0fb5d6 | ||
|
a301bf8bf5 | ||
|
37b3601c47 | ||
|
6e944485f0 | ||
|
431266069e | ||
|
d48a09e68b | ||
|
1db1ec7b5e | ||
|
2a8f0a4eab | ||
|
79f3669fac | ||
|
aab0f2dcd5 | ||
|
a47831e278 | ||
|
f1a5e8a42c | ||
|
723e9b3cba | ||
|
ff759a8074 | ||
|
4de1056d82 | ||
|
884b8da8bf | ||
|
044ad77a4b | ||
|
1fe8b388a3 | ||
|
79fe7d684c | ||
|
c409af0ea8 | ||
|
5110eaff96 | ||
|
db3eee72b5 | ||
|
3bcff91328 | ||
|
e843f192ec | ||
|
f3d2053878 | ||
|
efe8fbbd11 | ||
|
ce507b3b52 | ||
|
85de227003 | ||
|
7c6eb7c794 | ||
|
2037741b54 | ||
|
d534a8952d | ||
|
0b05b883cb | ||
|
6937aa5ddd | ||
|
8f6b24e0aa | ||
|
ba3b64a6c6 | ||
|
0881c6a20b | ||
|
f88a4b1791 | ||
|
2b43e3ee23 | ||
|
a413f3cded | ||
|
596fbfb517 | ||
|
86bb5503ab | ||
|
21ce23d27d | ||
|
6c75baecb2 |
39
.github/ISSUE_TEMPLATE/--bug_report.md
vendored
Normal file
39
.github/ISSUE_TEMPLATE/--bug_report.md
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Reproducable software issues in the core of Node-RED
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
|
||||
|
||||
If your issue is:
|
||||
- a general 'how-to' type question,
|
||||
- a feature request or suggestion for a change,
|
||||
- or problems with 3rd party (`node-red-contrib-`) nodes
|
||||
|
||||
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
|
||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
||||
|
||||
To help us understand the issue, please fill-in as much of the following information as you can:
|
||||
-->
|
||||
|
||||
### What are the steps to reproduce?
|
||||
|
||||
### What happens?
|
||||
|
||||
### What do you expect to happen?
|
||||
|
||||
### Please tell us about your environment:
|
||||
|
||||
- [ ] Node-RED version:
|
||||
- [ ] node.js version:
|
||||
- [ ] npm version:
|
||||
- [ ] Platform/OS:
|
||||
- [ ] Browser:
|
14
.github/ISSUE_TEMPLATE/-anything-else.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/-anything-else.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Anything Else
|
||||
about: Something that is not a bug report
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
|
||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
15
API.md
Normal file
15
API.md
Normal file
@@ -0,0 +1,15 @@
|
||||
Node-RED Modules
|
||||
---
|
||||
|
||||
Node-RED provides a set of node modules that implement different parts of the
|
||||
application.
|
||||
|
||||
Module | Description
|
||||
-------|-------
|
||||
[node-red](node-red.html) | the main module that pulls together all of the internal modules and provides the executable version of Node-RED
|
||||
[@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API
|
||||
[@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED
|
||||
[@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules
|
||||
@node-red/registry | the internal node registry
|
||||
@node-red/nodes | the default set of core nodes
|
||||
@node-red/editor-client | the client-side resources of the Node-RED editor application
|
87
CHANGELOG.md
87
CHANGELOG.md
@@ -1,3 +1,87 @@
|
||||
#### 0.20.2: Maintenance Release
|
||||
|
||||
- Filter out duplicate nodes when importing a flow
|
||||
- Handle node configs with multiple external scripts properly
|
||||
|
||||
#### 0.20.1: Maintenance Release
|
||||
|
||||
- Ensure all subflow instances are stopped when flow stopping Fixes #2095
|
||||
- modify name of korean locale forders #2091
|
||||
- Ensure node names are sanitized before being presented
|
||||
- Subflow status node must pass status to parent flow Fixes #2087
|
||||
- fix problem on displaying option label on Firefox #2090
|
||||
|
||||
#### 0.20.0: Milestone Release
|
||||
|
||||
Runtime
|
||||
- Pass complete status to Status node and filter to editor
|
||||
- Ensure flows wait for all nodes to close before restarting Fixes #2067
|
||||
- Fix git clone with password protected key
|
||||
- Allow a project to be located below the root of repo
|
||||
- Detect the cloning of an empty git repo properly
|
||||
- Fix use of custom auth strategy plugins
|
||||
- Remove remnants of when library in git/index Fixes #2057
|
||||
- Clear subflow status on close
|
||||
- Add exportGlobalContextKeys to prevent exposing functionGlobalContext keys
|
||||
- Add --no-audit and --no-update-notifier flags to npm commands to reduce workload
|
||||
- Add envVarExcludes setting to block named env vars
|
||||
- Update settings.js docs on userDir to match reality Fixes #2082
|
||||
- Add Korean Language
|
||||
|
||||
|
||||
Editor
|
||||
- Automatic placing of node icon according to input/output counts
|
||||
- Transfer placeholder and type to generated TypedInput field
|
||||
- Hitting enter in Comment node name field clicks markdown button
|
||||
- Shift status text left if no shape specified
|
||||
- Better align node status text to status dot
|
||||
- Handle treeList labels as text not html
|
||||
- Change subflow edit dialog titles
|
||||
- Resize subflow edit dialog properly
|
||||
- Add flow list button to tab bar
|
||||
- Handle node name as unsanitized text in debug sidebar
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request: Add Digest and Bearer Auth modes to http request node (#2061)
|
||||
- HTTP Request: Add multipart/form-data support to http request node (#2076)
|
||||
- TCP: include session/event info in status events
|
||||
- WebSocket: include session/event info in status events
|
||||
- Add i18n support for port label of inject/exec/httprequest/file nodes
|
||||
- Join node: handle merged objects with repeated properties and honour parts
|
||||
- JSON node: handle single booleans and numbers
|
||||
- File node: add encoding support to file in/out node (#2066)
|
||||
|
||||
#### 0.20.0-beta.5: Beta Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Bump dependencies
|
||||
- Allow `$parent` access of flow context
|
||||
- Make Node.\_flow a writeable property
|
||||
- Do not propagate Flow.getNode to parent when called from outside flow
|
||||
- Add support of subflow env var
|
||||
|
||||
Editor
|
||||
|
||||
- Properly sanitize node names in deploy warning dialogs
|
||||
- Fix XSS issues in library ui code
|
||||
- Add env type to subflow env var types
|
||||
- Display parent subflow properties in edit dialog
|
||||
- Fix direction value of subflow output
|
||||
- Add Status Node to Subflow to allow subflow-specific status Closes #597
|
||||
- Better handling of multiple flow merges Fixes #2039
|
||||
|
||||
Nodes
|
||||
|
||||
- Various translation updates
|
||||
- Catch: Add 'catch uncaught only' mode. Closes #1747
|
||||
- Link: scroll to current flow in node list
|
||||
- HTTPRequest: add option to urlencode cookies
|
||||
- HTTPRequest: option to use msg.payload as query params on GET. #1981
|
||||
- Debug: Add local time display option to numerics in debug window
|
||||
- MQTT: Add parsed JSON output option
|
||||
|
||||
#### 0.20.0-beta.4: Beta Release
|
||||
|
||||
Runtime
|
||||
@@ -164,6 +248,9 @@ Nodes
|
||||
- Watch: add msg.filename so can feed direct to file in node
|
||||
- WebSocket: preserve \_session on msg but don't send as part of wholemsg
|
||||
|
||||
#### 0.19.6: Maintenance Release
|
||||
|
||||
- Fix encoding of file node from binary to utf8 - #2051
|
||||
|
||||
#### 0.19.5: Maintenance Release
|
||||
|
||||
|
@@ -438,6 +438,7 @@ module.exports = function(grunt) {
|
||||
jsdoc : {
|
||||
modules: {
|
||||
src: [
|
||||
'API.md',
|
||||
'packages/node_modules/node-red/lib/red.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
@@ -451,7 +452,7 @@ module.exports = function(grunt) {
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
},
|
||||
editor: {
|
||||
_editor: {
|
||||
src: [
|
||||
'packages/node_modules/@node-red/editor-client/src/js'
|
||||
],
|
||||
@@ -612,5 +613,5 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('docs',
|
||||
'Generates API documentation',
|
||||
['jsdoc','jsdoc2md']);
|
||||
['jsdoc']);
|
||||
};
|
||||
|
23
package.json
23
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -24,16 +24,16 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.7.0",
|
||||
"ajv": "6.10.0",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"cheerio": "0.22.0",
|
||||
"clone": "2.1.2",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cookie-parser": "1.4.4",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.6.0",
|
||||
"cron": "1.7.0",
|
||||
"denque": "1.4.0",
|
||||
"express": "4.16.4",
|
||||
"express-session": "1.15.6",
|
||||
@@ -41,18 +41,18 @@
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"i18next": "13.1.0",
|
||||
"i18next": "14.1.1",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.1",
|
||||
"js-yaml": "3.12.2",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.6.4",
|
||||
"media-typer": "1.0.1",
|
||||
"memorystore": "1.6.0",
|
||||
"memorystore": "1.6.1",
|
||||
"mime": "2.4.0",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.1",
|
||||
"mustache": "3.0.1",
|
||||
"node-red-node-email": "1.0.*",
|
||||
"node-red-node-email": "1.*",
|
||||
"node-red-node-feedparser": "^0.1.14",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-sentiment": "^0.1.0",
|
||||
@@ -60,7 +60,7 @@
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
@@ -69,8 +69,9 @@
|
||||
"semver": "5.6.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.1.3",
|
||||
"xml2js": "0.4.19"
|
||||
"ws": "6.2.0",
|
||||
"xml2js": "0.4.19",
|
||||
"iconv-lite": "0.4.24"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~2.0.0"
|
||||
|
@@ -199,7 +199,7 @@ function genericStrategy(adminApp,strategy) {
|
||||
if (/^post$/i.test(options.callbackMethod)) {
|
||||
callbackMethodFunc = adminApp.post;
|
||||
}
|
||||
callbackMethodFunc('/auth/strategy/callback',
|
||||
callbackMethodFunc.call(adminApp,'/auth/strategy/callback',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,15 +16,15 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "0.20.0-beta.4",
|
||||
"@node-red/editor-client": "0.20.0-beta.4",
|
||||
"@node-red/util": "0.20.2",
|
||||
"@node-red/editor-client": "0.20.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"clone": "2.1.2",
|
||||
"cors": "2.8.5",
|
||||
"express-session": "1.15.6",
|
||||
"express": "4.16.4",
|
||||
"memorystore": "1.6.0",
|
||||
"memorystore": "1.6.1",
|
||||
"mime": "2.4.0",
|
||||
"mustache": "3.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
@@ -32,6 +32,6 @@
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.4.0",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.1.3"
|
||||
"ws": "6.2.0"
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"delete": "Are you sure you want to delete '__label__'?",
|
||||
"dropFlowHere": "Drop the flow here",
|
||||
"addFlow": "Add Flow",
|
||||
"listFlows": "List Flows",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
"disabled":"Disabled",
|
||||
@@ -135,7 +136,12 @@
|
||||
"updated": "Project '__project__' updated",
|
||||
"pull": "Project '__project__' reloaded",
|
||||
"revert": "Project '__project__' reverted",
|
||||
"merge-complete": "Git merge completed"
|
||||
"merge-complete": "Git merge completed",
|
||||
"setupCredentials": "Setup credentials",
|
||||
"setupProjectFiles": "Setup project files",
|
||||
"no": "No thanks",
|
||||
"createDefault": "Create default project files",
|
||||
"mergeConflict": "Show merge conflicts"
|
||||
},
|
||||
"label": {
|
||||
"manage-project-dep": "Manage project dependencies",
|
||||
@@ -266,16 +272,22 @@
|
||||
"newVersionError": "New Version doesn't contain valid JSON:"
|
||||
},
|
||||
"subflow": {
|
||||
"editSubflow": "Edit flow template: __name__",
|
||||
"edit": "Edit flow template",
|
||||
"editSubflowInstance": "Edit subflow instance: __name__",
|
||||
"editSubflow": "Edit subflow template: __name__",
|
||||
"edit": "Edit subflow template",
|
||||
"subflowInstances": "There is __count__ instance of this subflow template",
|
||||
"subflowInstances_plural": "There are __count__ instances of this subflow template",
|
||||
"editSubflowProperties": "edit properties",
|
||||
"input": "inputs:",
|
||||
"output": "outputs:",
|
||||
"status": "status node",
|
||||
"deleteSubflow": "delete subflow",
|
||||
"info": "Description",
|
||||
"category": "Category",
|
||||
"env": {
|
||||
"restore": "Restore to subflow default",
|
||||
"remove": "Remove environment variable"
|
||||
},
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
|
||||
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
|
||||
@@ -375,7 +387,7 @@
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "Node added to palette:",
|
||||
"nodeAdded_plural": "Nodes added to palette",
|
||||
"nodeAdded_plural": "Nodes added to palette:",
|
||||
"nodeRemoved": "Node removed from palette:",
|
||||
"nodeRemoved_plural": "Nodes removed from palette:",
|
||||
"nodeEnabled": "Node enabled:",
|
||||
@@ -538,14 +550,19 @@
|
||||
"removeFromProject": "remove from project",
|
||||
"addToProject": "add to project",
|
||||
"files": "Files",
|
||||
"package": "Package",
|
||||
"flow": "Flow",
|
||||
"credentials": "Credentials",
|
||||
"package":"Package",
|
||||
"packageCreate":"File will be created when changes are saved",
|
||||
"fileNotExist":"File does not exist",
|
||||
"selectFile": "Select File",
|
||||
"invalidEncryptionKey": "Invalid encryption key",
|
||||
"encryptionEnabled": "Encryption enabled",
|
||||
"encryptionDisabled": "Encryption disabled",
|
||||
"setTheEncryptionKey": "Set the encryption key:",
|
||||
"resetTheEncryptionKey": "Reset the encryption key:",
|
||||
"changeTheEncryptionKey": "Change the encryption key:",
|
||||
"setTheEncryptionKey": "Set the encryption key",
|
||||
"resetTheEncryptionKey": "Reset the encryption key",
|
||||
"changeTheEncryptionKey": "Change the encryption key",
|
||||
"currentKey": "Current key",
|
||||
"newKey": "New key",
|
||||
"credentialsAlert": "This will delete all existing credentials",
|
||||
@@ -744,6 +761,7 @@
|
||||
"desc2": "If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.",
|
||||
"create": "Create Project",
|
||||
"clone": "Clone Repository",
|
||||
"openExistingProject": "Open existing project",
|
||||
"not-right-now": "Not right now"
|
||||
},
|
||||
"git-config": {
|
||||
@@ -901,6 +919,7 @@
|
||||
"editor-tab": {
|
||||
"properties": "Properties",
|
||||
"description": "Description",
|
||||
"appearance": "Appearance"
|
||||
"appearance": "Appearance",
|
||||
"env": "Environment Variables"
|
||||
}
|
||||
}
|
||||
|
2
packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json
vendored
Normal file → Executable file
2
packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json
vendored
Normal file → Executable file
@@ -4,7 +4,7 @@
|
||||
"tip1" : "Search for nodes using {{core:search}}",
|
||||
"tip2" : "{{core:toggle-sidebar}} will toggle the view of this sidebar",
|
||||
"tip3" : "You can manage your palette of nodes with {{core:manage-palette}}",
|
||||
"tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can been accessed from the menu or with {{core:show-config-tab}}",
|
||||
"tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}",
|
||||
"tip5" : "Enable or disable these tips from the option in the settings",
|
||||
"tip6" : "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further",
|
||||
"tip7" : "Dragging a node onto a wire will splice it into the link",
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"listFlows": "フロー一覧",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
@@ -107,7 +108,7 @@
|
||||
"undeployedChanges": "ノードの変更をデプロイしていません",
|
||||
"nodeActionDisabled": "ノードのアクションは無効になっています",
|
||||
"nodeActionDisabledSubflow": "ノードのアクションは、サブフロー内で無効になっています",
|
||||
"missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください。",
|
||||
"missing-types": "<p>不明なノードが存在するため、フローを停止しました。</p>",
|
||||
"safe-mode": "<p>セーフモードでフローを停止しました</p><p>フローを変更し、再起動するために変更をデプロイできます</p>",
|
||||
"restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります",
|
||||
"credentials_load_failed": "<p>認証情報を復号できないため、フローを停止しました</p><p>フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です</p>",
|
||||
@@ -125,7 +126,7 @@
|
||||
"lostConnectionTry": "すぐに接続",
|
||||
"cannotAddSubflowToItself": "サブフロー自身を追加できません",
|
||||
"cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません",
|
||||
"unsupportedVersion": "<p>サポートされていないバージョンのNode.jsを使用しています。</p><p><br/>最新のNode.js LTSに更新してください。</p>",
|
||||
"unsupportedVersion": "<p>サポートされていないバージョンのNode.jsを使用しています。</p><p>最新のNode.js LTSに更新してください。</p>",
|
||||
"failedToAppendNode": "<p>'__module__'がロードできませんでした。</p><p>__error__</p>"
|
||||
},
|
||||
"project": {
|
||||
@@ -135,7 +136,12 @@
|
||||
"updated": "プロジェクト'__project__'を更新しました",
|
||||
"pull": "プロジェクト'__project__'を再ロードしました",
|
||||
"revert": "プロジェクト'__project__'を取り消しました",
|
||||
"merge-complete": "Gitマージが完了しました"
|
||||
"merge-complete": "Gitマージが完了しました",
|
||||
"setupCredentials": "認証情報を設定",
|
||||
"setupProjectFiles": "プロジェクトファイルの設定",
|
||||
"no": "結構です",
|
||||
"createDefault": "デフォルトのプロジェクトファイルを作成",
|
||||
"mergeConflict": "マージの衝突を表示"
|
||||
},
|
||||
"label": {
|
||||
"manage-project-dep": "プロジェクトの依存関係の管理",
|
||||
@@ -266,16 +272,22 @@
|
||||
"newVersionError": "新しいバージョンは正しいJSON形式ではありません:"
|
||||
},
|
||||
"subflow": {
|
||||
"editSubflow": "フローのテンプレートを編集: __name__",
|
||||
"edit": "フローのテンプレートを編集",
|
||||
"editSubflowInstance": "サブフローインスタンスを編集: __name__",
|
||||
"editSubflow": "サブフローのテンプレートを編集: __name__",
|
||||
"edit": "サブフローのテンプレートを編集",
|
||||
"subflowInstances": "このサブフローのテンプレートのインスタンスが __count__ 個存在します",
|
||||
"subflowInstances_plural": "このサブフローのテンプレートのインスタンスが __count__ 個存在します",
|
||||
"editSubflowProperties": "プロパティを編集",
|
||||
"input": "入力:",
|
||||
"output": "出力:",
|
||||
"status": "ステータスノード",
|
||||
"deleteSubflow": "サブフローを削除",
|
||||
"info": "詳細",
|
||||
"category": "カテゴリ",
|
||||
"env": {
|
||||
"restore": "デフォルト値に戻す",
|
||||
"remove": "環境変数を削除"
|
||||
},
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません",
|
||||
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
|
||||
@@ -375,7 +387,7 @@
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "ノードをパレットへ追加しました:",
|
||||
"nodeAdded_plural": "ノードをパレットへ追加しました",
|
||||
"nodeAdded_plural": "ノードをパレットへ追加しました:",
|
||||
"nodeRemoved": "ノードをパレットから削除しました:",
|
||||
"nodeRemoved_plural": "ノードをパレットから削除しました:",
|
||||
"nodeEnabled": "ノードを有効化しました:",
|
||||
@@ -431,7 +443,7 @@
|
||||
"more": "+ さらに __count__ 個",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
|
||||
"installFailed": "<p.追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"removeFailed": "<p>削除処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"updateFailed": "<p>更新処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
"enableFailed": "<p>有効化処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
|
||||
@@ -538,14 +550,18 @@
|
||||
"removeFromProject": "プロジェクトから削除",
|
||||
"addToProject": "プロジェクトへ追加",
|
||||
"files": "ファイル",
|
||||
"package": "パッケージ",
|
||||
"flow": "フロー",
|
||||
"credentials": "認証情報",
|
||||
"packageCreate": "変更が保存された時にファイルが作成されます",
|
||||
"fileNotExist": "ファイルが存在しません",
|
||||
"selectFile": "ファイルを選択",
|
||||
"invalidEncryptionKey": "不正な暗号化キー",
|
||||
"encryptionEnabled": "暗号化が有効になっています",
|
||||
"encryptionDisabled": "暗号化が無効になっています",
|
||||
"setTheEncryptionKey": "暗号化キーを設定:",
|
||||
"resetTheEncryptionKey": "暗号化キーを初期化:",
|
||||
"changeTheEncryptionKey": "暗号化キーを変更:",
|
||||
"setTheEncryptionKey": "暗号化キーを設定",
|
||||
"resetTheEncryptionKey": "暗号化キーを初期化",
|
||||
"changeTheEncryptionKey": "暗号化キーを変更",
|
||||
"currentKey": "現在のキー",
|
||||
"newKey": "新規のキー",
|
||||
"credentialsAlert": "既存の認証情報は全て削除されます",
|
||||
@@ -744,6 +760,7 @@
|
||||
"desc2": "とりあえずこの処理をスキップしてもかまいません。「プロジェクト」メニューから、いつでもプロジェクトの作成を開始できます。",
|
||||
"create": "プロジェクトの作成",
|
||||
"clone": "プロジェクトのクローン",
|
||||
"openExistingProject": "既存のプロジェクトを開く",
|
||||
"not-right-now": "後にする"
|
||||
},
|
||||
"git-config": {
|
||||
@@ -901,6 +918,7 @@
|
||||
"editor-tab": {
|
||||
"properties": "プロパティ",
|
||||
"description": "説明",
|
||||
"appearance": "外観"
|
||||
"appearance": "外観",
|
||||
"env": "環境変数"
|
||||
}
|
||||
}
|
||||
|
12
packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json
vendored
Normal file → Executable file
12
packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json
vendored
Normal file → Executable file
@@ -218,5 +218,17 @@
|
||||
"$env": {
|
||||
"args": "arg",
|
||||
"desc": "環境変数の値を返します。\n\n本関数はNode-REDの定義関数です。"
|
||||
},
|
||||
"$eval": {
|
||||
"args": "expr [, context]",
|
||||
"desc": "JSONリテラルもしくはJSONata式を表す`expr`を評価します。評価の際には現在のコンテキストをコンテキストとして用います。"
|
||||
},
|
||||
"$formatInteger": {
|
||||
"args": "number, picture",
|
||||
"desc": "`number`を`picture`指定に従って文字列に変換します。`picture`文字列は数値の変換方法をXPath F&O 3.1仕様の`fn:format-integer`に従って定義します。"
|
||||
},
|
||||
"$parseInteger": {
|
||||
"args": "string, picture",
|
||||
"desc": "`picture`文字列の指定に従って、`string`パラメータを整数(JSON数値)に変換します。`picture`文字列は`$formatInteger`と同じ形式です。"
|
||||
}
|
||||
}
|
||||
|
907
packages/node_modules/@node-red/editor-client/locales/ko/editor.json
vendored
Executable file
907
packages/node_modules/@node-red/editor-client/locales/ko/editor.json
vendored
Executable file
@@ -0,0 +1,907 @@
|
||||
{
|
||||
"common": {
|
||||
"label": {
|
||||
"name": "이름",
|
||||
"ok": "확인",
|
||||
"done": "완료",
|
||||
"cancel": "취소",
|
||||
"delete": "삭제",
|
||||
"close": "닫기",
|
||||
"load": "열기",
|
||||
"save": "저장",
|
||||
"import": "가져오기",
|
||||
"export": "내보내기",
|
||||
"back": "뒤로",
|
||||
"next": "앞으로",
|
||||
"clone": "프로젝트 복제",
|
||||
"cont": "계속하기"
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"defaultName": "플로우 __number__",
|
||||
"editFlow": "플로우 수정 : __name__",
|
||||
"confirmDelete": "삭제 확인",
|
||||
"delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?",
|
||||
"dropFlowHere": "플로우를 이곳에 가져오세요",
|
||||
"addFlow": "플로우 추가",
|
||||
"status": "상태",
|
||||
"enabled": "사용가능",
|
||||
"disabled": "사용불가능",
|
||||
"info": "상세내역"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
"view": {
|
||||
"view": "창",
|
||||
"grid": "눈금선",
|
||||
"showGrid": "눈금선 보이기",
|
||||
"snapGrid": "노드 배치 보조 켜기",
|
||||
"gridSize": "눈금선 크기",
|
||||
"textDir": "텍스트 방향",
|
||||
"defaultDir": "기본",
|
||||
"ltr": "왼쪽 -> 오른쪽",
|
||||
"rtl": "오른쪽 -> 왼쪽",
|
||||
"auto": "자동배분"
|
||||
},
|
||||
"sidebar": {
|
||||
"show": "우측사이드바 보이기"
|
||||
},
|
||||
"palette": {
|
||||
"show": "팔렛트 보이기"
|
||||
},
|
||||
"settings": "설정",
|
||||
"userSettings": "사용자 설정",
|
||||
"nodes": "노드설정",
|
||||
"displayStatus": "노드상태 보이기",
|
||||
"displayConfig": "설정노드 보기",
|
||||
"import": "가져오기",
|
||||
"export": "내보내기",
|
||||
"search": "플로우 겅색",
|
||||
"searchInput": "플로우 검색",
|
||||
"clipboard": "클립보드",
|
||||
"library": "라이브러리",
|
||||
"examples": "예시",
|
||||
"subflows": "보조 플로우",
|
||||
"createSubflow": "보조 플로우 생성",
|
||||
"selectionToSubflow": "보조 플로우 선택",
|
||||
"flows": "플로우",
|
||||
"add": "추가",
|
||||
"rename": "이름변경",
|
||||
"delete": "삭제",
|
||||
"keyboardShortcuts": "단축키",
|
||||
"login": "로그인",
|
||||
"logout": "로그아웃",
|
||||
"editPalette": "팔렛트 관리",
|
||||
"other": "기타",
|
||||
"showTips": "Tip 보기",
|
||||
"help": "Node-RED 웹사이트",
|
||||
"projects": "프로젝트",
|
||||
"projects-new": "신규",
|
||||
"projects-open": "열기",
|
||||
"projects-settings": "프로젝트 설정",
|
||||
"showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "네비게이터 표시/비표시",
|
||||
"zoom-out": "축소하기",
|
||||
"zoom-reset": "확대/축소 초기화",
|
||||
"zoom-in": "확대하기"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "__name__ 에 로그인됨",
|
||||
"username": "사용자명",
|
||||
"password": "비밀번호",
|
||||
"login": "로그인",
|
||||
"loginFailed": "로그인 실패",
|
||||
"notAuthorized": "권한이 없습니다",
|
||||
"errors": {
|
||||
"settings": "로그인 후 설정이 가능합니다",
|
||||
"deploy": "로그인 후 배포가 가능합니다",
|
||||
"notAuthorized": "이 기능은 로그인 후 사용가능합니다"
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"warning": "<strong>경고</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "변경사항 배포가 취소되었습니다",
|
||||
"nodeActionDisabled": "노드 실행이 비활성화 되었습니다",
|
||||
"nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다",
|
||||
"missing-types": "<p>타입이 없는 노드로인해 플로우가 중지되었습니다</p>",
|
||||
"safe-mode": "<p>[안전모드] 플로우가 정지되었습니다.</p><p>플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.</p>",
|
||||
"restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ",
|
||||
"credentials_load_failed": "<p>인증정보 복호화에 실패하여 플로우가 멈췄습니다. </p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p>",
|
||||
"credentials_load_failed_reset": "<p>인증정보를 복호화할 수 없습니다</p><p>인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.</p><p>다음 배포시 플로우의 인증정보는 초기화 될것입니다. 기존 모든 플로우의 인증정보가 지워집니다.</p>",
|
||||
"missing_flow_file": "<p>프로젝트 플로우 파일을 찾을 수 없습니다</p><p>프로젝트의 플로우 파일이 설정되지 않았습니다</p>",
|
||||
"missing_package_file": "<p>프로젝트 패키지 파일을 찾을 수 없습니다</p><p>프로젝트의 package.json 파일이 없습니다</p>",
|
||||
"project_empty": "<p>프로젝트가 누락되어 있습니다.</p><p>기본 프로젝트 파일을 만드시겠습니까?<br/>그렇지 않으면 수동으로 편집가 외부에 프로젝트 파일을 만드셔야 합니다.</p>",
|
||||
"project_not_found": "<p>'__project__' 가 없습니다.</p>",
|
||||
"git_merge_conflict": "<p>변경사항 자동병합에 실패했습니다.</p><p>병합되지 않은 충돌을 수정 후 재등록 하세요.</p>"
|
||||
},
|
||||
"error": "<strong>에러</strong>: __message__",
|
||||
"errors": {
|
||||
"lostConnection": "서버와 연결이 끊어졌습니다. 재접속을 시도합니다 ...",
|
||||
"lostConnectionReconnect": "서버와 연결이 끊어졌습니다. __time__ 초 안에 재접속을 시도합니다.",
|
||||
"lostConnectionTry": "지금 재접속",
|
||||
"cannotAddSubflowToItself": "서브플로우 자기자신을 추가할 수 없습니다",
|
||||
"cannotAddCircularReference": "순환참조가 발견되었습니다. 서브플로우를 추가할 수 없습니다",
|
||||
"unsupportedVersion": "<p>지원하지 않는 Node.js를 사용하고 있습니다</p><p>Node.js LTS 버전을 사용해 주세요</p>",
|
||||
"failedToAppendNode": "<p>'__module__' 읽어오기 실패</p><p>__error__</p>"
|
||||
},
|
||||
"project": {
|
||||
"change-branch": "로컬지점으로 '__project__' 변경",
|
||||
"merge-abort": "Git 병합을 중지했습니다.",
|
||||
"loaded": "'__project__' 프로젝트를 열었습니다",
|
||||
"updated": "'__project__'가 변경 되었습니다",
|
||||
"pull": "'__project__'를 다시 가져왔습니다",
|
||||
"revert": "'__project__'를 취소했습니다",
|
||||
"merge-complete": "Git 병합이 완료되었습니다"
|
||||
},
|
||||
"label": {
|
||||
"manage-project-dep": "프로젝트 의존성 관리",
|
||||
"setup-cred": "인증정보 설정",
|
||||
"setup-project": "프로젝트 파일 설정",
|
||||
"create-default-package": "기본 패키지 파일 생성",
|
||||
"no-thanks": "괜찮습니다",
|
||||
"create-default-project": "기본 프로젝트 파일 생성",
|
||||
"show-merge-conflicts": "병합 충돌 보여주기"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"nodes": "노드",
|
||||
"node": "__count__ 개의 노드",
|
||||
"node_plural": "__count__ 개의 노드",
|
||||
"configNode": "__count__ 개의 설정 노드",
|
||||
"configNode_plural": "__count__ 개의 설정 노드",
|
||||
"flow": "__count__ 개의 플로우",
|
||||
"flow_plural": "__count__ 개의 플로우",
|
||||
"subflow": "__count__ 개의 서브 플로우",
|
||||
"subflow_plural": "__count__ 개의 서브 플로우",
|
||||
"selectNodes": "텍스트를 선택하고 클립보드에 복사하세요",
|
||||
"pasteNodes": "여기에 노드를 붙여넣기 하세요",
|
||||
"selectFile": "불러올 파일을 선택하세요",
|
||||
"importNodes": "노드 불러오기",
|
||||
"exportNodes": "클립보드에 노드 내보내기",
|
||||
"download": "다운로드",
|
||||
"importUnrecognised": "알 수 없는 형식 :",
|
||||
"importUnrecognised_plural": "알 수 없는 형식 :",
|
||||
"nodesExported": "클립보드에 노드 내보내기",
|
||||
"nodesImported": "불러오기 : ",
|
||||
"nodeCopied": "__count__개의 노드가 복사 되었습니다",
|
||||
"nodeCopied_plural": "__count__개의 노드가 복사 되었습니다",
|
||||
"invalidFlow": "정상적지 않은 플로우 : __message__",
|
||||
"export": {
|
||||
"selected": "선택된 노드",
|
||||
"current": "현재 플로우",
|
||||
"all": "모든 플로우",
|
||||
"compact": "압축형식",
|
||||
"formatted": "서식유지",
|
||||
"copy": "클립보드로 내보내기"
|
||||
},
|
||||
"import": {
|
||||
"import": "가져올 위치 : ",
|
||||
"newFlow": "새로운 플로우",
|
||||
"errors": {
|
||||
"notArray": "입력이 JSON 배열이 아닙니다",
|
||||
"itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다",
|
||||
"missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다",
|
||||
"missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다"
|
||||
}
|
||||
},
|
||||
"copyMessagePath": "Path가 복사 되었습니다",
|
||||
"copyMessageValue": "Value가 복사 되었습니다",
|
||||
"copyMessageValue_truncated": "Truncated value가 복사 되었습니다"
|
||||
},
|
||||
"deploy": {
|
||||
"deploy": "배포하기",
|
||||
"full": "전체",
|
||||
"fullDesc": "작업공간 내 모든 플로우를 배포합니다",
|
||||
"modifiedFlows": "변경된 플로우",
|
||||
"modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다",
|
||||
"modifiedNodes": "변경된 노드",
|
||||
"modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다",
|
||||
"restartFlows": "플로우 재시작",
|
||||
"restartFlowsDesc": "현재 배포된 플로우를 재시작합니다",
|
||||
"successfulDeploy": "배포가 성공했습니다",
|
||||
"successfulRestart": "플로우 재시작을 성공했습니다",
|
||||
"deployFailed": "배포 실패 : __message__",
|
||||
"unusedConfigNodes": "사용되지 않는 설정노드가 있습니다",
|
||||
"unusedConfigNodesLink": "여기를 클릭하면 볼 수 있습니다",
|
||||
"errors": {
|
||||
"noResponse": "서버의 응답이 없습니다"
|
||||
},
|
||||
"confirm": {
|
||||
"button": {
|
||||
"ignore": "무시",
|
||||
"confirm": "배포 확인",
|
||||
"review": "변경사항 보기",
|
||||
"cancel": "취소",
|
||||
"merge": "병합",
|
||||
"overwrite": "무시하고 배포하기"
|
||||
},
|
||||
"undeployedChanges": "배포되지 않은 변경사항이 있습니다.\n\n이 페이지를 떠나면 변경사항이 사라집니다",
|
||||
"improperlyConfigured": "작업공간에 올바르게 구성되지 않은 노드가 있습니다 :",
|
||||
"unknown": "작업공간에 알려지지 않는 노드타입이 있습니다 :",
|
||||
"confirm": "배포하시겠습니까?",
|
||||
"doNotWarn": "이 경고를 무시",
|
||||
"conflict": "서버가 최신 플로우를 사용중입니다",
|
||||
"backgroundUpdate": "플로우가 변경되었습니다",
|
||||
"conflictChecking": "변경사항이 자동으로 병합될 수 있는지 확인",
|
||||
"conflictAutoMerge": "변경사항에 충돌이 없습니다. 자동병합이 가능합니다",
|
||||
"conflictManualMerge": "변경사항에 충돌이 있습니다. 배포하기 전에 충돌을 해결하세요",
|
||||
"plusNMore": "+ __count__ 개 더보기"
|
||||
}
|
||||
},
|
||||
"eventLog": {
|
||||
"title": "이벤트 로그",
|
||||
"view": "로그 보기"
|
||||
},
|
||||
"diff": {
|
||||
"unresolvedCount": "__count__개의 충돌이 해결되지 않음",
|
||||
"unresolvedCount_plural": "__count__개의 충돌이 해결되지 않음",
|
||||
"globalNodes": "Global 노드",
|
||||
"flowProperties": "플로우 속성",
|
||||
"type": {
|
||||
"added": "추가됨",
|
||||
"changed": "변경됨",
|
||||
"unchanged": "변경없음",
|
||||
"deleted": "삭제됨",
|
||||
"flowDeleted": "플로우 삭제됨",
|
||||
"flowAdded": "플로우 추가됨",
|
||||
"movedTo": "__id__로 이동됨",
|
||||
"movedFrom": "__id__로 부터 이동됨"
|
||||
},
|
||||
"nodeCount": "__count__ 개의 노드",
|
||||
"nodeCount_plural": "__count__ 개의 노드",
|
||||
"local": "로컬 변경사항",
|
||||
"remote": "원격 변경사항",
|
||||
"reviewChanges": "변경사항 살펴보기",
|
||||
"noBinaryFileShowed": "바이너리파일 내용을 볼수 없습니다",
|
||||
"viewCommitDiff": "변경사항 보기",
|
||||
"compareChanges": "변경사항 비교",
|
||||
"saveConflict": "충돌 해결내용 저장",
|
||||
"conflictHeader": "<span>__unresolved__</span> 개 중 <span>__resolved__</span> 충돌이 해결됨",
|
||||
"commonVersionError": "Common Version의 JSON 형식이 올바르지 않습니다 :",
|
||||
"oldVersionError": "Old Version의 JSON 형식이 올바르지 않습니다 :",
|
||||
"newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :"
|
||||
},
|
||||
"subflow": {
|
||||
"editSubflow": "플로우 템플릿 수정 : __name__",
|
||||
"edit": "플로우 템플릿 수정",
|
||||
"subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다",
|
||||
"subflowInstances_plural": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다",
|
||||
"editSubflowProperties": "속성 수정",
|
||||
"input": "입력:",
|
||||
"output": "출력:",
|
||||
"deleteSubflow": "서브 플로우 삭제",
|
||||
"info": "상세내역",
|
||||
"category": "카테고리",
|
||||
"format": "Markdown 형식",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다",
|
||||
"multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"configEdit": "수정",
|
||||
"configAdd": "추가",
|
||||
"configUpdate": "변경",
|
||||
"configDelete": "삭제",
|
||||
"nodesUse": "__count__개의 노드가 이 설정을 사용중입니다",
|
||||
"nodesUse_plural": "__count__개의 노드가 이 설정을 사용중입니다",
|
||||
"addNewConfig": "__type__의 설정노드 추가",
|
||||
"editNode": "__type__의 노드 수정",
|
||||
"editConfig": "__type__의 설정노드 수정",
|
||||
"addNewType": "__type__의 노드타입 추가 ...",
|
||||
"nodeProperties": "노드 속성",
|
||||
"label": "명칭",
|
||||
"portLabels": "포트 설정",
|
||||
"labelInputs": "입력",
|
||||
"labelOutputs": "출력",
|
||||
"settingIcon": "아이콘",
|
||||
"noDefaultLabel": "없음",
|
||||
"defaultLabel": "기본 명칭",
|
||||
"searchIcons": "아이콘 조회",
|
||||
"useDefault": "기본설정 사용",
|
||||
"description": "상세 내역",
|
||||
"show": "보이기",
|
||||
"hide": "숨기기",
|
||||
"errors": {
|
||||
"scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다."
|
||||
}
|
||||
},
|
||||
"keyboard": {
|
||||
"title": "키보드 단축키",
|
||||
"keyboard": "키보드",
|
||||
"filterActions": "필터",
|
||||
"shortcut": "단축키",
|
||||
"scope": "범위",
|
||||
"unassigned": "미할당",
|
||||
"global": "글로벌",
|
||||
"workspace": "작업공간",
|
||||
"selectAll": "모든 노드 선택",
|
||||
"selectAllConnected": "모든 연결된 노드 선택",
|
||||
"addRemoveNode": "노드 추가/삭제",
|
||||
"editSelected": "선택된 노드 수정",
|
||||
"deleteSelected": "선택된 노드나 링크를 삭제",
|
||||
"importNode": "노드 불러오기",
|
||||
"exportNode": "노드 내보내기",
|
||||
"nudgeNode": "선택된 노드 이동 (1px)",
|
||||
"moveNode": "선택된 노드 이동 (20px)",
|
||||
"toggleSidebar": "사이드바 표시/비표시",
|
||||
"togglePalette": "팔렛트 표시/비표시",
|
||||
"copyNode": "선택된 노드 복사",
|
||||
"cutNode": "선택된 노드 잘라내기",
|
||||
"pasteNode": "노드 붙여넣기",
|
||||
"undoChange": "마지막 변경 되돌리기",
|
||||
"searchBox": "검색창 열기",
|
||||
"managePalette": "팔렛트 관리"
|
||||
},
|
||||
"library": {
|
||||
"openLibrary": "라이브러리 열기...",
|
||||
"saveToLibrary": "라이브러리로 저장...",
|
||||
"typeLibrary": "__type__ 라이브러리",
|
||||
"unnamedType": "이름없는 __type__",
|
||||
"exportToLibrary": "라이브러리로 노드 내보내기",
|
||||
"dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?",
|
||||
"invalidFilename": "파일명이 올바르지 않습니다",
|
||||
"savedNodes": "저장된 노드",
|
||||
"savedType": "저장된 __type__",
|
||||
"saveFailed": "저장 실패 : __message__",
|
||||
"filename": "파일명",
|
||||
"folder": "폴더명",
|
||||
"filenamePlaceholder": "파일",
|
||||
"fullFilenamePlaceholder": "a/b/file",
|
||||
"folderPlaceholder": "a/b",
|
||||
"breadcrumb": "라이브러리"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "정보 없음",
|
||||
"filter": "필터",
|
||||
"search": "모듈 검색",
|
||||
"addCategory": "추가 ...",
|
||||
"label": {
|
||||
"subflows": "서브 플로우",
|
||||
"input": "입력",
|
||||
"output": "출력",
|
||||
"function": "기능",
|
||||
"social": "소셜",
|
||||
"storage": "저장",
|
||||
"analysis": "분석",
|
||||
"advanced": "그 외"
|
||||
},
|
||||
"actions": {
|
||||
"collapse-all": "모든 카테고리 접기",
|
||||
"expand-all": "모든 카테고리 펼치기"
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "팔렛트에 노드가 추가되었습니다:",
|
||||
"nodeAdded_plural": "팔렛트에 노드가 추가되었습니다:",
|
||||
"nodeRemoved": "팔렛트에서 노드가 삭제되었습니다:",
|
||||
"nodeRemoved_plural": "팔렛트에서 노드가 삭제되었습니다:",
|
||||
"nodeEnabled": "노드가 활성화 되었습니다:",
|
||||
"nodeEnabled_plural": "노드가 활성화 되었습니다:",
|
||||
"nodeDisabled": "노드가 비활성화 되었습니다:",
|
||||
"nodeDisabled_plural": "노드가 비활성화 되었습니다:",
|
||||
"nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다"
|
||||
},
|
||||
"editor": {
|
||||
"title": "팔렛트 관리",
|
||||
"palette": "팔렛트",
|
||||
"times": {
|
||||
"seconds": "몇초 전",
|
||||
"minutes": "몇분 전",
|
||||
"minutesV": "__count__분 전",
|
||||
"hoursV": "__count__시간 전",
|
||||
"hoursV_plural": "__count__시간 전",
|
||||
"daysV": "__count__일 전",
|
||||
"daysV_plural": "__count__일 전",
|
||||
"weeksV": "__count__주 전",
|
||||
"weeksV_plural": "__count__주 전",
|
||||
"monthsV": "__count__달 전",
|
||||
"monthsV_plural": "__count__달 전",
|
||||
"yearsV": "__count__년 전",
|
||||
"yearsV_plural": "__count__년 전",
|
||||
"yearMonthsV": "__y__년, __count__월 전",
|
||||
"yearMonthsV_plural": "__y__년, __count__월 전",
|
||||
"yearsMonthsV": "__y__년, __count__월 전",
|
||||
"yearsMonthsV_plural": "__y__년, __count__월 전"
|
||||
},
|
||||
"nodeCount": "__label__ 개의 노드",
|
||||
"nodeCount_plural": "__label__ 개의 노드",
|
||||
"moduleCount": "__count__ 개의 모듈 사용가능",
|
||||
"moduleCount_plural": "__count__ 개의 모듈 사용가능",
|
||||
"inuse": "사용중",
|
||||
"enableall": "모두 활성화",
|
||||
"disableall": "모두 비활성화",
|
||||
"enable": "활성화",
|
||||
"disable": "비활성화",
|
||||
"remove": "삭제",
|
||||
"update": "__version__으로 업데이트",
|
||||
"updated": "업데이트 됨",
|
||||
"install": "설치",
|
||||
"installed": "설치됨",
|
||||
"conflict": "충돌",
|
||||
"conflictTip": "<p>노드타입이 이미 설치 되어 있습니다.<br/>/p><p>충돌모듈 : <code>__module__</code></p>",
|
||||
"loading": "카탈로그 여는중...",
|
||||
"tab-nodes": "설치된 노드",
|
||||
"tab-install": "설치가능한 노드",
|
||||
"sort": "정렬:",
|
||||
"sortAZ": "a-z",
|
||||
"sortRecent": "최근",
|
||||
"more": "+ __count__ 개 더 보기",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>노드 카탈로그를 설치하지 못했습니다.</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||
"installFailed": "<p>설치 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||
"removeFailed": "<p>삭제 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||
"updateFailed": "<p>업데이트 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||
"enableFailed": "<p>활성화 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>",
|
||||
"disableFailed": "<p>비활성화 실패 : __module__</p><p>__message__</p><p>브라우저 콘솔로그를 참고하세요.</p>"
|
||||
},
|
||||
"confirm": {
|
||||
"install": {
|
||||
"body": "<p>'__module__' 설치중</p><p>설치하기 전 노드 설명서를 읽으세요. 어떤 노드은 의존성이 자동으로 해결되지 않거나, Node-RED의 재시작이 필요할 수 있습니다.</p>",
|
||||
"title": "노드 설치"
|
||||
},
|
||||
"remove": {
|
||||
"body": "<p>'__module__' 삭제중</p><p>Node-RED에서 노드를 제거합니다. Node-RED가 재시작되기까지 리소스가 계속 사용될 수도 있습니다.</p>",
|
||||
"title": "노드 삭제"
|
||||
},
|
||||
"update": {
|
||||
"body": "<p>'__module__' 업데이트중</p><p>업데이트 반영을 위해 Node-RED를 수동으로 재시작해야 할 경우도 있습니다.</p>",
|
||||
"title": "노드 변경"
|
||||
},
|
||||
"cannotUpdate": {
|
||||
"body": "이 노드에 대한 업데이트가 있지만, 팔레트 관리자가 변경할 수 있는 위치에 설치되지 않았습니다.<br/><br/>이 노드를 변경하는 방법은 설명서를 참조하세요"
|
||||
},
|
||||
"button": {
|
||||
"review": "노드정보 열기",
|
||||
"install": "설치",
|
||||
"remove": "삭제",
|
||||
"update": "업데이트"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"info": {
|
||||
"name": "노드정보",
|
||||
"tabName": "이름",
|
||||
"label": "정보",
|
||||
"node": "노드",
|
||||
"type": "타입",
|
||||
"module": "모듈",
|
||||
"id": "ID",
|
||||
"status": "상태",
|
||||
"enabled": "활성화",
|
||||
"disabled": "비활성화",
|
||||
"subflow": "서브 플로우",
|
||||
"instances": "인스턴스",
|
||||
"properties": "속성",
|
||||
"info": "정보",
|
||||
"desc": "상세 내역",
|
||||
"blank": "공백",
|
||||
"null": "null",
|
||||
"showMore": "더 보기",
|
||||
"showLess": "간단히",
|
||||
"flow": "플로우",
|
||||
"selection": "선택",
|
||||
"nodes": "__count__ 개의 노드",
|
||||
"flowDesc": "플로우 상세내역",
|
||||
"subflowDesc": "서브 플로우 상세내역",
|
||||
"nodeHelp": "노드 도움말",
|
||||
"none": "없음",
|
||||
"arrayItems": "__count__ 개의 항목",
|
||||
"showTips": "설정에서 도움말을 열 수 있습니다. "
|
||||
},
|
||||
"config": {
|
||||
"name": "노드 설정",
|
||||
"label": "설정",
|
||||
"global": "모든 플로우",
|
||||
"none": "없음",
|
||||
"subflows": "보조 플로우",
|
||||
"flows": "플로우",
|
||||
"filterUnused": "미사용",
|
||||
"filterAll": "전체",
|
||||
"filtered": "__count__ 개 숨김"
|
||||
},
|
||||
"context": {
|
||||
"name": "Context 데이터",
|
||||
"label": "context",
|
||||
"none": "선택 없음",
|
||||
"refresh": "새로고침",
|
||||
"empty": "공백",
|
||||
"node": "노드",
|
||||
"flow": "플로우",
|
||||
"global": "Global",
|
||||
"deleteConfirm": "정말로 이 아이템을 지우시겠습니까?"
|
||||
},
|
||||
"palette": {
|
||||
"name": "팔레트 관리",
|
||||
"label": "팔레트"
|
||||
},
|
||||
"project": {
|
||||
"label": "프로젝트",
|
||||
"name": "프로젝트",
|
||||
"description": "상세내역",
|
||||
"dependencies": "의존성",
|
||||
"settings": "설정",
|
||||
"noSummaryAvailable": "요약 없음",
|
||||
"editDescription": "프로젝트 상세내역 수정",
|
||||
"editDependencies": "프로젝트 의존성 수정",
|
||||
"editReadme": "README.md 수정",
|
||||
"showProjectSettings": "프로젝트 설정 보이기",
|
||||
"projectSettings": {
|
||||
"title": "프로젝트 설정",
|
||||
"edit": "수정",
|
||||
"none": "없음",
|
||||
"install": "설치",
|
||||
"removeFromProject": "프로젝트에서 삭제",
|
||||
"addToProject": "프로젝트에 추가",
|
||||
"files": "파일",
|
||||
"flow": "플로우",
|
||||
"credentials": "인증정보",
|
||||
"invalidEncryptionKey": "잘못된 암호화 키",
|
||||
"encryptionEnabled": "암호화 활성화",
|
||||
"encryptionDisabled": "암호화 비활성화",
|
||||
"setTheEncryptionKey": "암호화 키 설정 :",
|
||||
"resetTheEncryptionKey": "암호화 키 초기화 :",
|
||||
"changeTheEncryptionKey": "암호화 키 변경:",
|
||||
"currentKey": "현재 키",
|
||||
"newKey": "새로운 키",
|
||||
"credentialsAlert": "모든 인증정보를 삭제합니다",
|
||||
"versionControl": "버전 관리",
|
||||
"branches": "브랜치",
|
||||
"noBranches": "브랜치 없음",
|
||||
"deleteConfirm": "다시 되돌릴 수 없습니다. '__name__'의 로컬 브랜치를 삭제 히시겠습니까?",
|
||||
"unmergedConfirm": "'__name__'의 병합되지 않은 수정사항을 잃어버릴 수 있습니다. 그래도 삭제 하시겠습니까?",
|
||||
"deleteUnmergedBranch": "미병합 브랜치 삭제",
|
||||
"gitRemotes": "Git 원격",
|
||||
"addRemote": "원격 추가",
|
||||
"addRemote2": "원격 추가",
|
||||
"remoteName": "원격 이름",
|
||||
"nameRule": "A-Z 0-9 _ -의 문자만 사용이 가능합니다",
|
||||
"url": "URL",
|
||||
"urlRule": "https://, ssh:// or file://",
|
||||
"urlRule2": "URL안에 사용자아이디/비밀번호를 사용하지 마세요",
|
||||
"noRemotes": "원격 없음",
|
||||
"deleteRemoteConfrim": "원격 '__name__'를 정말로 삭제하시겠습니까?",
|
||||
"deleteRemote": "원격 삭제"
|
||||
},
|
||||
"userSettings": {
|
||||
"committerDetail": "Committer 상세내역",
|
||||
"committerTip": "시스템 기본값을 사용하려면 비워두세요",
|
||||
"userName": "사용자명",
|
||||
"email": "이메일",
|
||||
"sshKeys": "SSH키",
|
||||
"sshKeysTip": "원격저장소에 대한 보안연결을 허용합니다",
|
||||
"add": "키 추가",
|
||||
"addSshKey": "SSH키 추가",
|
||||
"addSshKeyTip": "public/private 키쌍을 추가합니다",
|
||||
"name": "이름",
|
||||
"nameRule": "A-Z 0-9 _ -의 문자만 사용이 가능합니다",
|
||||
"passphrase": "암호",
|
||||
"passphraseShort": "암호가 너무 짧습니다",
|
||||
"optional": "선택항목",
|
||||
"cancel": "취소",
|
||||
"generate": "Key 생성",
|
||||
"noSshKeys": "SSH키 없음",
|
||||
"copyPublicKey": "클립보드로 public key 복사",
|
||||
"delete": "키 삭제",
|
||||
"gitConfig": "Git 설정",
|
||||
"deleteConfirm": "다시 되돌릴 수 없습니다. __name__의 SSH키를 삭제하시겠습니까?"
|
||||
},
|
||||
"versionControl": {
|
||||
"unstagedChanges": "변경사항을 언스테이징",
|
||||
"stagedChanges": "스테이징된 변경사항",
|
||||
"unstageChange": "스테이징 되지않은 변경사항",
|
||||
"stageChange": "변경사항을 스테이징",
|
||||
"unstageAllChange": "모든 변경사항 언스테이징",
|
||||
"stageAllChange": "모든 변경사항 스테이징",
|
||||
"commitChanges": "변경사항 커밋",
|
||||
"resolveConflicts": "충돌 해결",
|
||||
"head": "HEAD",
|
||||
"staged": "스테이징 됨",
|
||||
"unstaged": "스테이징 안됨",
|
||||
"local": "로컬",
|
||||
"remote": "리모트",
|
||||
"revert": "다시 복원할 수 없습니다. '__file__'을 되돌리시겠습니까?",
|
||||
"revertChanges": "변경사항 되돌리기",
|
||||
"localChanges": "로컬 변경사항",
|
||||
"none": "없음",
|
||||
"conflictResolve": "모든 충돌이 해결되었습니다. 변경사항을 적용하여 병합을 완료하세요",
|
||||
"localFiles": "로컬 파일",
|
||||
"all": "전체",
|
||||
"unmergedChanges": "병합되지 않은 변경사항",
|
||||
"abortMerge": "병합 중단",
|
||||
"commit": "커밋",
|
||||
"changeToCommit": "커밋 변경사항",
|
||||
"commitPlaceholder": "커밋 메시지를 입력하세요",
|
||||
"cancelCapital": "취소",
|
||||
"commitCapital": "커밋",
|
||||
"commitHistory": "커밋 이력",
|
||||
"branch": "브랜치 :",
|
||||
"moreCommits": "커밋 더보기",
|
||||
"changeLocalBranch": "로컬 브랜치 변경",
|
||||
"createBranchPlaceholder": "브렌치 찾기/생성",
|
||||
"upstream": "업스트림",
|
||||
"localOverwrite": "브랜치에 반영할 변경사항이 있습니다. 변경사항을 커밋하거나, 변경내역을 취소해야 합니다",
|
||||
"manageRemoteBranch": "원격 브랜치 관리",
|
||||
"unableToAccess": "원격저장소에 접근할 수 없습니다",
|
||||
"retry": "재시도",
|
||||
"setUpstreamBranch": "업스트림 브랜치로 설정",
|
||||
"createRemoteBranchPlaceholder": "리모드 브랜치 찾기/생성",
|
||||
"trackedUpstreamBranch": "생성된 브랜치는 트래킹된 업스트림 브랜치로 설정됩니다",
|
||||
"selectUpstreamBranch": "브랜치가 생성될 것입니다. 트래킹된 업스트림 브랜치로 설정하세요",
|
||||
"pushFailed": "리모트에 최신 커밋이 있기 때문에 push할 수 없습니다. 먼저 pull과 병합을 하신 후 push하세요",
|
||||
"push": "push",
|
||||
"pull": "pull",
|
||||
"unablePull": "<p>원격저장소의 변경사항을 가져올 수 없습니다, 당신의 unstaged 로컬 변경사항을 덮어씁니다.</p><p>변경사항을 적용하고 다시 시도하세요</p>",
|
||||
"showUnstagedChanges": "unstaged 변경사항 보여주기",
|
||||
"connectionFailed": "원격저장소 연결 불가 : ",
|
||||
"pullUnrelatedHistory": "<p>원격저장소에 연관없는 커밋 기록이 있습니다.</p><p>모든 변경사항을 로컬 저장소로 가져 오시겠습니까?</p>",
|
||||
"pullChanges": "Pull 변경사항",
|
||||
"history": "이력",
|
||||
"projectHistory": "프로젝트 이력",
|
||||
"daysAgo": "__count__일 전",
|
||||
"daysAgo_plural": "__count__일 전",
|
||||
"hoursAgo": "__count__시간 전",
|
||||
"hoursAgo_plural": "__count__시간 전",
|
||||
"minsAgo": "__count__분 전",
|
||||
"minsAgo_plural": "__count__분 전",
|
||||
"secondsAgo": "몇초 전",
|
||||
"notTracking": "당신의 로컬 브랜치는 원격브랜치를 트래킹하고 있지 않습니다",
|
||||
"statusUnmergedChanged": "당신의 저장소는 병합되지 않은 변경사항을 가지고 있습니다. 충돌을 수정하고 결과를 커밋하세요",
|
||||
"repositoryUpToDate": "당신의 저장소는 최신상태 입니다",
|
||||
"commitsAhead": "당신의 저장소가 원격지보다 __count__ 커밋을 앞서 있습니다. 이제 커밋 할 수 있습니다.",
|
||||
"commitsAhead_plural": "당신의 저장소가 원격지보다 __count__ 커밋을 앞서 있습니다. 지금 커밋할 수 있습니다.",
|
||||
"commitsBehind": "당신의 저장소가 원격지보다 __count__ 커밋이 늦습니다. 이제 pull 할 수 있습니다.",
|
||||
"commitsBehind_plural": "당신의 저장소가 원격지보다 __count__ 커밋이 늦습니다. 이제 pull 할 수 있습니다.",
|
||||
"commitsAheadAndBehind1": "당신의 저장소가 __count__ 커밋이 늦고, ",
|
||||
"commitsAheadAndBehind1_plural": "당신의 저장소가 __count__ 커밋이 늦고 ",
|
||||
"commitsAheadAndBehind2": "__count__ 커밋이 원격지보다 앞서 있습니다. ",
|
||||
"commitsAheadAndBehind2_plural": "__count__ 커밋이 원격지보다 앞서 있습니다.",
|
||||
"commitsAheadAndBehind3": "push하기전에 리모트 저장소에서 pull을 먼저 수행하세요.",
|
||||
"commitsAheadAndBehind3_plural": "push하기전에 리모트 저장소에서 pull을 먼저 수행하세요.",
|
||||
"refreshCommitHistory": "커밋 기록 새로고침",
|
||||
"refreshChanges": "변경사항 새로고침"
|
||||
}
|
||||
}
|
||||
},
|
||||
"typedInput": {
|
||||
"type": {
|
||||
"str": "string",
|
||||
"num": "number",
|
||||
"re": "regular expression",
|
||||
"bool": "boolean",
|
||||
"json": "JSON",
|
||||
"bin": "buffer",
|
||||
"date": "timestamp",
|
||||
"jsonata": "expression",
|
||||
"env": "env variable"
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
"add": "추가"
|
||||
},
|
||||
"search": {
|
||||
"empty": "결과 없음",
|
||||
"addNode": "노드 추가 ..."
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "기능",
|
||||
"functionReference": "기능 참조",
|
||||
"insert": "삽입",
|
||||
"title": "JSONata 형식 에디터",
|
||||
"test": "테스트",
|
||||
"data": "예제 메세지",
|
||||
"result": "결과",
|
||||
"format": "형식",
|
||||
"compatMode": "호환모드 사용",
|
||||
"compatModeDesc": "<h3>JSONata호환 모드</h3><p> 입력된 형식은 <code>msg</code> 를 참조하고 있어, 호환모드로 평가합니다. 이 모드는 후에 폐지될 예정이니, <code>msg</code> 를 사용하지 않도록 해 주시길 바랍니다. </p><p> JSONata를 Node-RED에서 처음 지원했을 때에는 <code>msg</code> 오브젝트의 참조가 필요했습니다. 예를 들어 <code>msg.payload</code> 는 payload를 참고하기 위해 사용되었습니다. </p><p> 직접 메시지에 대하여 식을 평가하도록 되었기에, 이 형식은 사용할 수 없게 됩니다. payload를 참조하려면 단순히 <code>payload</code> 로 지정해 주십시오. </p>",
|
||||
"noMatch": "결과 없음",
|
||||
"errors": {
|
||||
"invalid-expr": "유효하지 않은 JSONata 형식 :\n __message__",
|
||||
"invalid-msg": "유효하지 않은 예시 JSON 메세지 :\n __message__",
|
||||
"context-unsupported": "컨텍스트 기능을 테스트 할 수 없습니다.\n $flowContext 또는 $globalContext",
|
||||
"eval": "형식 오류 :\n __message__"
|
||||
}
|
||||
},
|
||||
"jsEditor": {
|
||||
"title": "자바스크립트 에디터"
|
||||
},
|
||||
"jsonEditor": {
|
||||
"title": "JSON 에디터",
|
||||
"format": "JSON 형식"
|
||||
},
|
||||
"markdownEditor": {
|
||||
"title": "Markdown 에디터",
|
||||
"format": "Markdown 형식",
|
||||
"heading1": "제목 레벨1",
|
||||
"heading2": "제목 레벨2",
|
||||
"heading3": "제목 레벨3",
|
||||
"bold": "강조",
|
||||
"italic": "이탤릭",
|
||||
"code": "코드",
|
||||
"ordered-list": "번호 목차",
|
||||
"unordered-list": "목차",
|
||||
"quote": "인용",
|
||||
"link": "링크",
|
||||
"horizontal-rule": "나눔줄",
|
||||
"toggle-preview": "미리보기 전환"
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "Buffer 에디터",
|
||||
"modeString": "UTF-8 문자열로 처리",
|
||||
"modeArray": "JSON 배열로 처리",
|
||||
"modeDesc": "<h3>Buffer 에디터</h3><p>버퍼타입은 byet값의 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": {
|
||||
"config-git": "Git client 설정",
|
||||
"welcome": {
|
||||
"hello": "안녕하세요. Node-RED에서 프로젝트 기능을 이용할 수 있게 되었습니다.",
|
||||
"desc0": "플로우 파일을 관리하는 새로운 방법이며, 버전을 관리할 수 도 있습니다.",
|
||||
"desc1": "무선 프로젝트를 작성하거나 기존의 Git저장소에서 프로젝트를 복제할 수 있습니다.",
|
||||
"desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.",
|
||||
"create": "프로젝트 생성",
|
||||
"clone": "프로젝트 복제",
|
||||
"not-right-now": "나중에"
|
||||
},
|
||||
"git-config": {
|
||||
"setup": "버전관리 클라이언트를 설정합니다",
|
||||
"desc0": "Node-RED는 오픈소스 Git로 버전관리를 할 수 있습니다. 프로젝트 파일의 변경사항을 추적하고 원격저장소로 push할 수 있습니다.",
|
||||
"desc1": "당신이 변경사항을 커밋하면 git은 누가 변경사항을 만들었는지 사용자명과 이메일 정보를 기록합니다. 사용자명은 꼭 당신의 실명일 필요는 없습니다.",
|
||||
"desc2": "당신의 Git 클라이언트는 아래와 같이 이미 설정되었습니다.",
|
||||
"desc3": "당신은 git config의 설정탭에서 설정을 변경할 수 있습니다.",
|
||||
"username": "사용자명",
|
||||
"email": "이메일"
|
||||
},
|
||||
"project-details": {
|
||||
"create": "프로젝트 생성",
|
||||
"desc0": "프로젝트는 Git 저장소로 관리되어집니다. 다른 사람과 협업하거나 공유하기 쉬워집니다.",
|
||||
"desc1": "당신은 여러 개의 프로젝트를 생성할 수 있고 에디터에서 프로젝트를 선택할 수 있습니다.",
|
||||
"desc2": "시작하려면 프로젝트 이름과 프로젝트의 상세설명이 필요합니다.",
|
||||
"already-exists": "프로젝트가 이미 존재합니다",
|
||||
"must-contain": "A-Z 0-9 _ -의 문자만 사용이 가능합니다",
|
||||
"project-name": "프로젝트명",
|
||||
"desc": "상세설명",
|
||||
"opt": "옵션"
|
||||
},
|
||||
"clone-project": {
|
||||
"clone": "프로젝트 복제",
|
||||
"desc0": "프로젝트가 있는 저장소를 가지고 있다면, 즉시 복제하여 사용할 수 있습니다.",
|
||||
"already-exists": "프로젝트가 이미 존재합니다",
|
||||
"must-contain": "A-Z 0-9 _ -의 문자만 사용이 가능합니다",
|
||||
"project-name": "프로젝트명",
|
||||
"no-info-in-url": "URL안에 사용자아이디/비밀번호를 사용하지 마세요",
|
||||
"git-url": "Git 저장소 URL",
|
||||
"protocols": "https://, ssh:// 혹은 file://",
|
||||
"auth-failed": "인증 실패",
|
||||
"username": "사용자명",
|
||||
"passwd": "패스워드",
|
||||
"ssh-key": "SSH키",
|
||||
"passphrase": "패스워드",
|
||||
"ssh-key-desc": "저장소를 복제하기 전에 접속을 위해 SSH키를 먼저 추가하세요.",
|
||||
"ssh-key-add": "ssh키 추가",
|
||||
"credential-key": "인증 암호화 키",
|
||||
"cant-get-ssh-key": "에러! 선택한 SSH키 경로를 가져올 수 없습니다",
|
||||
"already-exists2": "이미 존재합니다",
|
||||
"git-error": "git 에러",
|
||||
"connection-failed": "접속 실패",
|
||||
"not-git-repo": "Git저장소가 아닙니다",
|
||||
"repo-not-found": "저장소가 없습니다"
|
||||
},
|
||||
"default-files": {
|
||||
"create": "프로젝트 파일 생성",
|
||||
"desc0": "프로젝트는 당신의 플로우, README, package.json 파일을 포함합니다.",
|
||||
"desc1": "Git 저장소에서 관리하고 싶은 다른 파일들을 포함할 수 있습니다.",
|
||||
"desc2": "당신이 이미 가지고 있는 flow, 자격증명파일이 프로젝트로 복사될 것입니다.",
|
||||
"flow-file": "플로우 파일",
|
||||
"credentials-file": "자격증명 파일"
|
||||
},
|
||||
"encryption-config": {
|
||||
"setup": "자격인증 파일의 암호화 설정",
|
||||
"desc0": "플로우의 자격인증 파일 암호화를 통해 내용을 안전하게 유지할 수 있습니다.",
|
||||
"desc1": "자격증명을 공용 Git저장소에 저장하려면 비밀키 구문을 제공하여 암호화 해야 합니다",
|
||||
"desc2": "당신의 플로우 자격인증 파일은 암호화 되어 있지 않습니다.",
|
||||
"desc3": "즉, 암호 및 액세스 토큰과 같은 내용을 파일에 액세스 할 수있는 모든 사람이 열람할 수 있습니다.",
|
||||
"desc4": "자격증명을 공용 Git저장소에 저장하려면 비밀키 구문을 제공하여 암호화 해야 합니다",
|
||||
"desc5": "당신의 플로우 자격증명파일은 setting파일의 credentialSecret속성으로 암호화되어 있습니다.",
|
||||
"desc6": "당신의 플로우 자격증명파일은 시스템이 생성된 키에 의해 암호화 되어있습니다. 이 프로젝트용 새로운 비밀키를 지정해 주세요.",
|
||||
"desc7": "키는 프로젝트파일과는 별개로 보존됩니다. 다른 Node-RED에서 이 프로젝트를 이용하려면 이 프로젝트의 키가 필요합니다.",
|
||||
"credentials": "자격인증",
|
||||
"enable": "암호화 활성화",
|
||||
"disable": "암호화 비활성화",
|
||||
"disabled": "비활성화됨",
|
||||
"copy": "기존 키를 복사",
|
||||
"use-custom": "커스텀키 사용",
|
||||
"desc8": "자격증명 파일이 암호화되어 있지 않아, 간단히 해당내용이 열람될 수 있습니다.",
|
||||
"create-project-files": "프로젝트 생성",
|
||||
"create-project": "프로젝트 생성",
|
||||
"already-exists": "이미 존재합니다.",
|
||||
"git-error": "git 에러",
|
||||
"git-auth-error": "git 인증 에러"
|
||||
},
|
||||
"create-success": {
|
||||
"success": "당신의 첫번째 프로젝트 생성이 성공하였습니다.",
|
||||
"desc0": "앞으로 이와 같이 Node-RED를 사용할 수 있습니다.",
|
||||
"desc1": "사이드바의 '정보'탭은 현재 활성화된 프로젝트를 보여줍니다. 이름 옆에 있는 버틀을 사용하여 프로젝트 설정화면을 불러올 수 있습니다.",
|
||||
"desc2": "사이드바의 '이력'탭은 프로젝트의 변경된 파일을 확인하고 커밋할 수 있습니다. 커밋의 전체 기록을 보여주고 변경사항을 원격 저장소에 push할 수 있습니다."
|
||||
},
|
||||
"create": {
|
||||
"projects": "프로젝트",
|
||||
"already-exists": "프로젝트가 이미 존재합니다",
|
||||
"must-contain": "A-Z 0-9 _ -의 문자만 사용이 가능합니다",
|
||||
"no-info-in-url": "URL안에 사용자아이디/비밀번호를 사용하지 마세요",
|
||||
"open": "프로젝트 열기",
|
||||
"create": "프로젝트 생성",
|
||||
"clone": "프로젝트 복제",
|
||||
"project-name": "프로젝트명",
|
||||
"desc": "상세내역",
|
||||
"opt": "옵션",
|
||||
"flow-file": "플로우 파일",
|
||||
"credentials": "자격증명",
|
||||
"enable-encryption": "암호화 활성화",
|
||||
"disable-encryption": "암호화 비활성화",
|
||||
"encryption-key": "암호화 키",
|
||||
"desc0": "자격증명 정보를 안전하게 하는 문구",
|
||||
"desc1": "자격증명 파일이 암호화되어 있지 않아, 간단히 해당내용이 열람될 수 있습니다.",
|
||||
"git-url": "Git 저장소 URL",
|
||||
"protocols": "https://, ssh:// 혹은 file://",
|
||||
"auth-failed": "인증 실패",
|
||||
"username": "사용자명",
|
||||
"password": "패스워드",
|
||||
"ssh-key": "SSH키",
|
||||
"passphrase": "패스워드",
|
||||
"desc2": "저장소를 복제하기 전에 접속을 위해 SSH키를 먼저 추가하세요.",
|
||||
"add-ssh-key": "ssh키 추가",
|
||||
"credentials-encryption-key": "자격인증 암호화 키",
|
||||
"already-exists-2": "이미 존재합니다",
|
||||
"git-error": "git 에러",
|
||||
"con-failed": "접속 실패",
|
||||
"not-git": "git 저장소가 아닙니다",
|
||||
"no-resource": "저장소아 없습니다",
|
||||
"cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.",
|
||||
"unexpected_error": "예기치 않은 에러"
|
||||
},
|
||||
"delete": {
|
||||
"confirm": "프로젝트를 정말 지우시겠습니까?"
|
||||
},
|
||||
"create-project-list": {
|
||||
"search": "프로젝트 검색",
|
||||
"current": "현재"
|
||||
},
|
||||
"require-clean": {
|
||||
"confirm": "<p>변경사항을 배포하지 않아 내용이 손실될 수 있습니다.</p><p>계속 할까요?</p>"
|
||||
},
|
||||
"send-req": {
|
||||
"auth-req": "저장소에 대한 인증이 필요합니다.",
|
||||
"username": "사용자명",
|
||||
"password": "패스워드",
|
||||
"passphrase": "패스워드",
|
||||
"retry": "재시도",
|
||||
"update-failed": "인증 변경 실패",
|
||||
"unhandled": "오류 응답 미처리"
|
||||
},
|
||||
"create-branch-list": {
|
||||
"invalid": "올바르지 않은 브랜치",
|
||||
"create": "브랜치 생성",
|
||||
"current": "현재"
|
||||
},
|
||||
"create-default-file-set": {
|
||||
"no-active": "활성화된 프로젝트 없이 기본 파일을 만들 수 없습니다.",
|
||||
"no-empty": "비어있지 않은 프로젝트에 기본 파일을 만들 수 없습니다.",
|
||||
"git-error": "git 에러"
|
||||
},
|
||||
"errors": {
|
||||
"no-username-email": "당신의 Git 클라이언트에 사용자명/이메일이 설정되지 않았습니다.",
|
||||
"unexpected": "예기치 않은 에러가 발생했습니다.",
|
||||
"code": "코드"
|
||||
}
|
||||
},
|
||||
"editor-tab": {
|
||||
"properties": "속성",
|
||||
"description": "상세 내역",
|
||||
"appearance": "모양"
|
||||
}
|
||||
}
|
23
packages/node_modules/@node-red/editor-client/locales/ko/infotips.json
vendored
Executable file
23
packages/node_modules/@node-red/editor-client/locales/ko/infotips.json
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"info": {
|
||||
"tip0": "{{core:delete-selection}}를 사용하여 선택된 노드나 링크를 삭제할 수 있습니다.",
|
||||
"tip1": "{{core:search}}를 활용하여 노드를 검색할 수 있습니다.",
|
||||
"tip2": "{{core:toggle-sidebar}}를 사용하여 사이드바를 표시/비표시 전환 할 수 있습니다.",
|
||||
"tip3": "{{core:manage-palette}}를 사용하여 노드 팔레트를 관리 할 수 있습니다.",
|
||||
"tip4": "플로우 안의 설정노드가 사이드바에 표시됩니다. 메뉴 혹은 {{core:show-config-tab}}를 사용하여 엑세스 할 수 있습니다.",
|
||||
"tip5": "설정에서 이 팁을 활성화/비활성화 할 수 있습니다.",
|
||||
"tip6": "[left] [up] [down] [right] 키를 사용하여 선택된 노드를 움직일 수 있습니다. [shift]키를 누른 채로 움직이면 이동폭이 늘어납니다.",
|
||||
"tip7": "노드를 와이어 사이로 드래그 하여 연결할 수도 있습니다.",
|
||||
"tip8": "{{core:show-export-dialog}}를 사용하여 선택한 노드 또는 현재탭을 내보낼 수 있습니다.",
|
||||
"tip9": "JSON파일을 에디터로 드래그하거나 {{core:show-import-dialog}}를 사용하여 플로우 가져올 수 있습니다.",
|
||||
"tip10": "[shift] [click] 하고서 드래그하여 선택한 와이어를 이동할 수 있습니다.",
|
||||
"tip11": "{{core:show-info-tab}}를 사용하여 정보탭을 표시하거나 {{core:show-debug-tab}}를 사용하여 디버그탭을 표시할 수 있습니다.",
|
||||
"tip12": "작업공간에서 [ctrl] [click]을 사용하여 빠른추가 대회상자를 열 수 있습니다.",
|
||||
"tip13": "[ctrl]을 누른 상태로 노드의 포트를 클릭하여 빠르게 연결할 수 있습니다.",
|
||||
"tip14": "[shift]를 누른 상태로 노드를 클릭하여 연결된 모든 노드를 선택할 수 있습니다.",
|
||||
"tip15": "[ctrl]을 누른 상태로 노드를 클릭하여 현재 선택영역에 노드를 추가/제거 할 수 있습니다.",
|
||||
"tip16": "{{core:show-previous-tab}}와 {{core:show-next-tab}}를 사용하여 탭을 전환할 수 있습니다.",
|
||||
"tip17": "노드 편집 창에서 {{core : confirm-edit-tray}}로 변경 사항을 확인하거나 {{core : cancel-edit-tray}}로 취소 할 수 있습니다.",
|
||||
"tip18": "{{core : edit-selected-node}}를 누르면 현재 선택 영역의 첫 번째 노드가 편집됩니다."
|
||||
}
|
||||
}
|
222
packages/node_modules/@node-red/editor-client/locales/ko/jsonata.json
vendored
Executable file
222
packages/node_modules/@node-red/editor-client/locales/ko/jsonata.json
vendored
Executable file
@@ -0,0 +1,222 @@
|
||||
{
|
||||
"$string": {
|
||||
"args": "arg",
|
||||
"desc": "다음과 같은 규칙을 사용하여 인수 *arg*를 문자열로 변환합니다. \n\n - 문자열은 변경되지 않습니다. \n - 함수는 빈 문자열로 변환됩니다. \n - 무한대와 NaN은 JSON수치로 표현할 수 없기 때문에 오류처리 됩니다. \n - 다른 모든 값은 `JSON.stringify` 함수를 사용하여 JSON 문자열로 변환됩니다."
|
||||
},
|
||||
"$length": {
|
||||
"args": "str",
|
||||
"desc": "문자열 `str`의 문자 수를 반환합니다. `str`가 문자열이 아닌 경우 에러를 반환합니다."
|
||||
},
|
||||
"$substring": {
|
||||
"args": "str, start[, length]",
|
||||
"desc": "(zero-offset)의 `start`에서 시작하는 첫번째 인수 `str`의 문자열을 반환합니다. 만약 `length`가 지정된 경우, 부분 문자열은 최대 `length`의 크기를 갖습니다. 만약 `start` 인수가 음수이면 `str`의 끝에서부터의 문자수를 나타냅니다."
|
||||
},
|
||||
"$substringBefore": {
|
||||
"args": "str, chars",
|
||||
"desc": "`str`에 `chars`문자가 처음으로 나오기 전까지의 부분문자열을 반환합니다. 만약 `chars`가 없으면 `str`을 반환합니다."
|
||||
},
|
||||
"$substringAfter": {
|
||||
"args": "str, chars",
|
||||
"desc": "`str`에 `chars`문자가 처음으로 나온 이후의 부분문자열을 반환합니다. 만약 `chars`가 없으면 `str`을 반환합니다."
|
||||
},
|
||||
"$uppercase": {
|
||||
"args": "str",
|
||||
"desc": "`str`의 문자를 대문자로 반환합니다."
|
||||
},
|
||||
"$lowercase": {
|
||||
"args": "str",
|
||||
"desc": "`str`의 문자를 소문자로 반환합니다."
|
||||
},
|
||||
"$trim": {
|
||||
"args": "str",
|
||||
"desc": "다음의 순서대로 `str`의 모든 공백을 자르고 정규화 합니다:\n\n - 모든 탭, 캐리지 리턴 및 줄 바꿈은 공백으로 대체됩니다. \n- 연속된 공백은 하나로 줄입니다.\n- 후행 및 선행 공백은 삭제됩니다.\n\n 만일 `str`이 지정되지 않으면 (예: 이 함수를 인수없이 호출), context값을 `str`의 값으로 사용합니다. `str`이 문자열이 아니면 에러가 발생합니다."
|
||||
},
|
||||
"$contains": {
|
||||
"args": "str, pattern",
|
||||
"desc": "`str`이 `pattern`과 일치하면 `true`를, 일치하지 않으면 `false`를 반환합니다. 만약 `str`이 지정되지 않으면 (예: 이 함수를 인수없이 호출), context값을 `str`의 값으로 사용합니다. `pattern` 인수는 문자열이나 정규표현으로 할 수 있습니다."
|
||||
},
|
||||
"$split": {
|
||||
"args": "str[, separator][, limit]",
|
||||
"desc": "`str`인수를 분할하여 부분문자열로 배열합니다. `str`이 문자열이 아니면 에러가 발생합니다. 생략가능한 인수 `separator`는 `str`을 분할하는 문자를 문자열 또는 정규표현으로 지정합니다. `separator`를 지정하지 않은 경우, 공백의 문자열로 간주하여 `str`은 단일 문자의 배열로 분리됩니다. `separator`가 문자열이 아니면 에러가 발생합니다. 생략가능한 인수 'limit`는 결과의 배열이 갖는 부분문자열의 최대수를 지정합니다. 이 수를 넘는 부분문자열은 파기됩니다. `limit`가 지정되지 않으면`str`은 결과 배열의 크기의 제한없이 완전히 분리됩니다. `limit`이 음수인 경우 에러가 발생합니다."
|
||||
},
|
||||
"$join": {
|
||||
"args": "array[, separator]",
|
||||
"desc": "문자열의 배열을 생략가능한 인수 `separator`로 구분한 하나의 문자열로 연결합니다. 배열 `array`가 문자열이 아닌 요소를 포함하는 경우, 에러가 발생합니다. `separator`를 지정하지 않은 경우, 공백의 문자열로 간주합니다(예: 문자열간의 `separator`없음). `separator`가 문자열이 아닌 경우, 에러가 발생합니다."
|
||||
},
|
||||
"$match": {
|
||||
"args": "str, pattern [, limit]",
|
||||
"desc": "`str`문자열에 `pattern`를 적용하여, 오브젝트 배열을 반환합니다. 배열요소의 오브젝트는 `str`중 일치하는 부분의 정보를 보유합니다."
|
||||
},
|
||||
"$replace": {
|
||||
"args": "str, pattern, replacement [, limit]",
|
||||
"desc": "`str`문자열에서 `pattern` 패턴을 검색하여, `replacement`로 대체합니다.\n\n임의이ㅡ 인수 `limit`는 대체 횟수의 상한값을 지정합니다."
|
||||
},
|
||||
"$now": {
|
||||
"args": "",
|
||||
"desc": "ISO 8601 호환 형식으로 타임 스탬프를 생성하고 이를 문자열로 반환합니다."
|
||||
},
|
||||
"$base64encode": {
|
||||
"args": "string",
|
||||
"desc": "ASCII 문자열을 base 64 표현으로 변환합니다. 문자열의 각 문자는 이진 데이터의 바이트로 처리됩니다. 이렇게 하려면 문자열의 모든 문자가 URI로 인코딩 된 문자열을 포함하고, 0x00에서 0xFF 범위에 있어야합니다. 해당 범위를 벗어난 유니 코드 문자는 지원되지 않습니다"
|
||||
},
|
||||
"$base64decode": {
|
||||
"args": "string",
|
||||
"desc": "UTF-8코드페이지를 이용하여, Base 64형식의 바이트값을 문자열로 변환합니다."
|
||||
},
|
||||
"$number": {
|
||||
"args": "arg",
|
||||
"desc": "`arg`를 다음과 같은 규칙을 사요하여 숫자로 변환합니다. :\n\n - 숫자는 변경되지 않습니다.\n – 올바른 JSON의 숫자는 숫자 그대로 변환됩니다.\n – 그 외의 형식은 에러를 발생합니다."
|
||||
},
|
||||
"$abs": {
|
||||
"args": "number",
|
||||
"desc": "`number`의 절대값을 반환합니다."
|
||||
},
|
||||
"$floor": {
|
||||
"args": "number",
|
||||
"desc": "`number`를 `number`보다 같거나 작은 정수로 내림하여 반환합니다."
|
||||
},
|
||||
"$ceil": {
|
||||
"args": "number",
|
||||
"desc": "`number`를 `number`와 같거나 큰 정수로 올림하여 반환합니다."
|
||||
},
|
||||
"$round": {
|
||||
"args": "number [, precision]",
|
||||
"desc": "인수 `number`를 반올림한 값을 반환합니다. 임의의 인수 `precision`에는 반올립에서 사용할 소수점이하의 자릿수를 지정합니다."
|
||||
},
|
||||
"$power": {
|
||||
"args": "base, exponent",
|
||||
"desc": "기수 `base`의 값을 지수 `exponent`만큼의 거듭 제곱으로 반환합니다."
|
||||
},
|
||||
"$sqrt": {
|
||||
"args": "number",
|
||||
"desc": "인수 `number`의 제곱근을 반환합니다."
|
||||
},
|
||||
"$random": {
|
||||
"args": "",
|
||||
"desc": "0이상 1미만의 의사난수를 반환합니다."
|
||||
},
|
||||
"$millis": {
|
||||
"args": "",
|
||||
"desc": "Unix Epoch (1970 년 1 월 1 일 UTC)부터 경과된 밀리 초 수를 숫자로 반환합니다. 평가대상식에 포함되는 $millis()의 모든 호출은 모두 같은 값을 반환합니다."
|
||||
},
|
||||
"$sum": {
|
||||
"args": "array",
|
||||
"desc": "숫자 배열 `array`의 합계를 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다."
|
||||
},
|
||||
"$max": {
|
||||
"args": "array",
|
||||
"desc": "숫자 배열 `array`에서 최대값을 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다."
|
||||
},
|
||||
"$min": {
|
||||
"args": "array",
|
||||
"desc": "숫자 배열 `array`에서 최소값을 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다."
|
||||
},
|
||||
"$average": {
|
||||
"args": "array",
|
||||
"desc": "숫자 배열 `array`에서 평균값을 반환합니다. `array`에 숫자가 아닌 요소가 있는 경우, 에러가 발생합니다."
|
||||
},
|
||||
"$boolean": {
|
||||
"args": "arg",
|
||||
"desc": "`arg` 값을 다음의 규칙에 의해 Boolean으로 변환합니다::\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": {
|
||||
"args": "arg",
|
||||
"desc": "인수의 부정을 Boolean으로 변환합니다. `arg`는 가장먼저boolean으로 변환됩니다."
|
||||
},
|
||||
"$exists": {
|
||||
"args": "arg",
|
||||
"desc": "`arg` 식의 평가값이 존재하는 경우 `true`, 식의 평가결과가 미정의인 경우 (예: 존재하지 않는 참조필드로의 경로)는 `false`를 반환합니다."
|
||||
},
|
||||
"$count": {
|
||||
"args": "array",
|
||||
"desc": "`array`의 요소 갯수를 반환합니다."
|
||||
},
|
||||
"$append": {
|
||||
"args": "array, array",
|
||||
"desc": "두개의 `array`를 병합합니다."
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다. \n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다. \n\n `function(left,right)` \n\n 비교함수는 left와 right의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 right값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 ``true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다."
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
"desc": "`array`에 포함된 모든 값의 순서를 역순으로 변환하여 반환합니다."
|
||||
},
|
||||
"$shuffle": {
|
||||
"args": "array",
|
||||
"desc": "`array`에 포함된 모든 값의 순서를 랜덤으로 반환합니다."
|
||||
},
|
||||
"$zip": {
|
||||
"args": "array, ...",
|
||||
"desc": "배열 `array1` ... arrayN`의 위치 0, 1, 2…. 의 값으로 구성된 convolved (zipped) 배열을 반환합니다."
|
||||
},
|
||||
"$keys": {
|
||||
"args": "object",
|
||||
"desc": "`object` 키를 포함하는 배열을 반환합니다. 인수가 오브젝트의 배열이면 반환되는 배열은 모든 오브젝트에있는 모든 키의 중복되지 않은 목록이 됩니다."
|
||||
},
|
||||
"$lookup": {
|
||||
"args": "object, key",
|
||||
"desc": "`object` 내의 `key`가 갖는 값을 반환합니다. 최초의 인수가 객체의 배열 인 경우, 배열 내의 모든 오브젝트를 검색하여, 존재하는 모든 키가 갖는 값을 반환합니다."
|
||||
},
|
||||
"$spread": {
|
||||
"args": "object",
|
||||
"desc": "`object`의 키/값 쌍별로 각 요소가 하나인 오브젝트 배열로 분할합니다. 만일 오브젝트 배열인 경우, 배열의 결과는 각 오브젝트에서 얻은 키/값 쌍의 오브젝트를 갖습니다."
|
||||
},
|
||||
"$merge": {
|
||||
"args": "array<object>",
|
||||
"desc": "`object`배열을 하나의 `object`로 병합합니다. 병합결과의 오브젝트는 입력배열내의 각 오브젝트의 키/값 쌍을 포함합니다. 입력 오브젝트가 같은 키를 가질경우, 반환 된 `object`에는 배열 마지막의 오브젝트의 키/값이 격납됩니다. 입력 배열이 오브젝트가 아닌 요소를 포함하는 경우, 에러가 발생합니다."
|
||||
},
|
||||
"$sift": {
|
||||
"args": "object, function",
|
||||
"desc": "함수 `function`을 충족시키는 `object` 인수 키/값 쌍만 포함하는 오브젝트를 반환합니다. \n\n 함수 `function` 다음과 같은 인수를 가져야 합니다 : \n\n `function(value [, key [, object]])`"
|
||||
},
|
||||
"$each": {
|
||||
"args": "object, function",
|
||||
"desc": "`object`의 각 키/값 쌍에, 함수`function`을 적용한 값의 배열을 반환합니다."
|
||||
},
|
||||
"$map": {
|
||||
"args": "array, function",
|
||||
"desc": "`array`의 각 값에 `function`을 적용한 결과로 이루어진 배열을 반환합니다. \n\n 함수 `function`은 다음과 같은 인수를 가져야 합니다. \n\n `function(value[, index[, array]])`"
|
||||
},
|
||||
"$filter": {
|
||||
"args": "array, function",
|
||||
"desc": "`array`의 값중, 함수 `function`의 조건을 만족하는 값으로 이루어진 배열을 반환합니다. \n\n 함수 `function`은 다음과 같은 형식을 가져야 합니다. \n\n `function(value[, index[, array]])`"
|
||||
},
|
||||
"$reduce": {
|
||||
"args": "array, function [, init]",
|
||||
"desc": "배열의 각 요소값에 함수 `function`을 연속적으로 적용하여 얻어지는 집계값을 반환합니다. `function`의 적용에는 직전의 `function`의 적용결과와 요소값이 인수로 주어집니다. \n\n 함수 `function`은 인수를 두개 뽑아, 배열의 각 요소 사이에 배치하는 중치연산자처럼 작용해야 합니다. \n\n 임의의 인수 `init`에는 집약시의 초기값을 설정합니다."
|
||||
},
|
||||
"$flowContext": {
|
||||
"args": "string[, string]",
|
||||
"desc": "플로우 컨텍스트 속성을 취득합니다."
|
||||
},
|
||||
"$globalContext": {
|
||||
"args": "string[, string]",
|
||||
"desc": "플로우의 글로벌 컨텍스트 속성을 취득합니다."
|
||||
},
|
||||
"$pad": {
|
||||
"args": "string, width [, char]",
|
||||
"desc": "문자수가 인수 `width`의 절대값이상이 되도록, 필요한 경우 여분의 패딩을 사용하여 `string`의 복사본을 반환합니다. \n\n `width`가 양수인 경우, 오른쪽으로 채워지고, 음수이면 왼쪽으로 채워집니다. \n\n 임의의 `char`인수에는 이 함수에서 사용할 패딩을 지정합니다. 지정하지 않는 경우에는, 기본값으로 공백을 사용합니다."
|
||||
},
|
||||
"$fromMillis": {
|
||||
"args": "number",
|
||||
"desc": "Unix Epoch (1970 년 1 월 1 일 UTC) 이후의 밀리 초를 나타내는 숫자를 ISO 8601 형식의 타임 스탬프 문자열로 변환합니다."
|
||||
},
|
||||
"$formatNumber": {
|
||||
"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 쌍을 포함하는 오브젝트여야 합니다."
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
"desc": "`number`를 인수 `radix`에 지정한 값을 기수로하는 문자열로 변환합니다. `radix`가 지정되지 않은 경우, 기수 10이 기본값으로 설정됩니다. `radix`에는 2~36의 값을 설정할 수 있고, 그 외의 값의 경우에는 에러가 발생합니다."
|
||||
},
|
||||
"$toMillis": {
|
||||
"args": "timestamp",
|
||||
"desc": "ISO 8601 형식의 `timestamp`를 Unix Epoch (1970 년 1 월 1 일 UTC) 이후의 밀리 초 수로 변환합니다. 문자열이 올바른 형식이 아닌 경우 에러가 발생합니다."
|
||||
},
|
||||
"$env": {
|
||||
"args": "arg",
|
||||
"desc": "환경변수를 값으로 반환합니다.\n\n 이 함수는 Node-RED 정의 함수입니다."
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -125,14 +125,20 @@ RED.history = (function() {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
|
||||
ev.subflow.instances.forEach(function(n) {
|
||||
var node = RED.nodes.node(n.id);
|
||||
if (node) {
|
||||
node.changed = n.changed;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
if (ev.subflow) {
|
||||
if (ev.subflow.hasOwnProperty('instances')) {
|
||||
ev.subflow.instances.forEach(function(n) {
|
||||
var node = RED.nodes.node(n.id);
|
||||
if (node) {
|
||||
node.changed = n.changed;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ev.subflow.hasOwnProperty('status')) {
|
||||
subflow = RED.nodes.subflow(ev.subflow.id);
|
||||
subflow.status = ev.subflow.status;
|
||||
}
|
||||
}
|
||||
if (subflow) {
|
||||
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
||||
@@ -232,6 +238,11 @@ RED.history = (function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ev.subflow.hasOwnProperty('status')) {
|
||||
if (ev.subflow.status) {
|
||||
delete ev.node.status;
|
||||
}
|
||||
}
|
||||
RED.editor.validateNode(ev.node);
|
||||
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
||||
n.inputs = ev.node.in.length;
|
||||
@@ -290,6 +301,7 @@ RED.history = (function() {
|
||||
RED.workspaces.order(ev.order);
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(modifiedTabs).forEach(function(id) {
|
||||
var subflow = RED.nodes.subflow(id);
|
||||
if (subflow) {
|
||||
@@ -303,6 +315,7 @@ RED.history = (function() {
|
||||
RED.palette.refresh();
|
||||
RED.workspaces.refresh();
|
||||
RED.sidebar.config.refresh();
|
||||
RED.subflow.refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
"*": {
|
||||
"ctrl-shift-p":"core:manage-palette",
|
||||
"ctrl-f": "core:search",
|
||||
"ctrl-shift-f": "core:list-flows",
|
||||
"ctrl-=": "core:zoom-in",
|
||||
"ctrl--": "core:zoom-out",
|
||||
"ctrl-0": "core:zoom-reset",
|
||||
|
@@ -358,7 +358,10 @@ RED.nodes = (function() {
|
||||
}
|
||||
subflows[sf.id] = sf;
|
||||
RED.nodes.registerType("subflow:"+sf.id, {
|
||||
defaults:{name:{value:""}},
|
||||
defaults:{
|
||||
name:{value:""},
|
||||
env:{value:[]}
|
||||
},
|
||||
icon: function() { return sf.icon||"subflow.png" },
|
||||
category: sf.category || "subflows",
|
||||
inputs: sf.in.length,
|
||||
@@ -369,6 +372,16 @@ RED.nodes = (function() {
|
||||
paletteLabel: function() { return RED.nodes.subflow(sf.id).name },
|
||||
inputLabels: function(i) { return sf.inputLabels?sf.inputLabels[i]:null },
|
||||
outputLabels: function(i) { return sf.outputLabels?sf.outputLabels[i]:null },
|
||||
oneditresize: function(size) {
|
||||
var rows = $("#dialog-form>div:not(.node-input-env-container-row)");
|
||||
var height = size.height;
|
||||
for (var i=0; i<rows.size(); i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
var editorRow = $("#dialog-form>div.node-input-env-container-row");
|
||||
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-env-container").editableList('height',height-80);
|
||||
},
|
||||
set:{
|
||||
module: "node-red"
|
||||
}
|
||||
@@ -535,6 +548,7 @@ RED.nodes = (function() {
|
||||
node.category = n.category;
|
||||
node.in = [];
|
||||
node.out = [];
|
||||
node.env = n.env;
|
||||
|
||||
n.in.forEach(function(p) {
|
||||
var nIn = {x:p.x,y:p.y,wires:[]};
|
||||
@@ -571,6 +585,18 @@ RED.nodes = (function() {
|
||||
node.icon = n.icon;
|
||||
}
|
||||
}
|
||||
if (n.status) {
|
||||
node.status = {x: n.status.x, y: n.status.y, wires:[]};
|
||||
links.forEach(function(d) {
|
||||
if (d.target === n.status) {
|
||||
if (d.source.type != "subflow") {
|
||||
node.status.wires.push({id:d.source.id, port:d.sourcePort})
|
||||
} else {
|
||||
node.status.wires.push({id:n.id, port:0})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -740,6 +766,20 @@ RED.nodes = (function() {
|
||||
if (!$.isArray(newNodes)) {
|
||||
newNodes = [newNodes];
|
||||
}
|
||||
|
||||
// Scan for any duplicate nodes and remove them. This is a temporary
|
||||
// fix to help resolve corrupted flows caused by 0.20.0 where multiple
|
||||
// copies of the flow would get loaded at the same time.
|
||||
// If the user hit deploy they would have saved those duplicates.
|
||||
var seenIds = {};
|
||||
newNodes = newNodes.filter(function(n) {
|
||||
if (seenIds[n.id]) {
|
||||
return false;
|
||||
}
|
||||
seenIds[n.id] = true;
|
||||
return true;
|
||||
})
|
||||
|
||||
var isInitialLoad = false;
|
||||
if (!initialLoad) {
|
||||
isInitialLoad = true;
|
||||
@@ -851,6 +891,12 @@ RED.nodes = (function() {
|
||||
output.i = i;
|
||||
output.id = getID();
|
||||
});
|
||||
if (n.status) {
|
||||
n.status.type = "subflow";
|
||||
n.status.direction = "status";
|
||||
n.status.z = n.id;
|
||||
n.status.id = getID();
|
||||
}
|
||||
new_subflows.push(n);
|
||||
addSubflow(n,createNewIds);
|
||||
}
|
||||
@@ -1018,6 +1064,7 @@ RED.nodes = (function() {
|
||||
node.name = n.name;
|
||||
node.outputs = subflow.out.length;
|
||||
node.inputs = subflow.in.length;
|
||||
node.env = n.env;
|
||||
} else {
|
||||
if (!node._def) {
|
||||
if (node.x && node.y) {
|
||||
@@ -1189,6 +1236,19 @@ RED.nodes = (function() {
|
||||
});
|
||||
delete output.wires;
|
||||
});
|
||||
if (n.status) {
|
||||
n.status.wires.forEach(function(wire) {
|
||||
var link;
|
||||
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
|
||||
link = {source:n.in[wire.port], sourcePort:wire.port,target:n.status};
|
||||
} else {
|
||||
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:n.status};
|
||||
}
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
});
|
||||
delete n.status.wires;
|
||||
}
|
||||
}
|
||||
|
||||
RED.workspaces.refresh();
|
||||
|
@@ -28,15 +28,25 @@ var RED = (function() {
|
||||
var hasDeferred = false;
|
||||
|
||||
var nodeConfigEls = $("<div>"+nodeConfig+"</div>");
|
||||
nodeConfigEls.find("script").each(function(i,el) {
|
||||
var scripts = nodeConfigEls.find("script");
|
||||
var scriptCount = scripts.length;
|
||||
scripts.each(function(i,el) {
|
||||
var srcUrl = $(el).attr('src');
|
||||
if (srcUrl && !/^\s*(https?:|\/|\.)/.test(srcUrl)) {
|
||||
$(el).remove();
|
||||
var newScript = document.createElement("script");
|
||||
newScript.onload = function() { $("body").append(nodeConfigEls); done() }
|
||||
newScript.onload = function() {
|
||||
scriptCount--;
|
||||
if (scriptCount === 0) {
|
||||
$("body").append(nodeConfigEls);
|
||||
done()
|
||||
}
|
||||
}
|
||||
$('body').append(newScript);
|
||||
newScript.src = RED.settings.apiRootUrl+srcUrl;
|
||||
hasDeferred = true;
|
||||
} else {
|
||||
scriptCount--;
|
||||
}
|
||||
})
|
||||
if (!hasDeferred) {
|
||||
@@ -211,7 +221,7 @@ var RED = (function() {
|
||||
}
|
||||
]
|
||||
} else if (msg.error === "missing-types") {
|
||||
text+="<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
text+="<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
if (!!RED.projects.getActiveProject()) {
|
||||
options.buttons = [
|
||||
{
|
||||
@@ -239,7 +249,7 @@ var RED = (function() {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Setup credentials",
|
||||
text: RED._("notification.project.setupCredentials"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showCredentialsPrompt();
|
||||
@@ -250,7 +260,7 @@ var RED = (function() {
|
||||
} else {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Close",
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
}
|
||||
@@ -261,7 +271,7 @@ var RED = (function() {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Setup project files",
|
||||
text: RED._("notification.project.setupProjectFiles"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showFilesPrompt();
|
||||
@@ -273,10 +283,10 @@ var RED = (function() {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Create default package file",
|
||||
text: RED._("notification.project.setupProjectFiles"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.createDefaultPackageFile();
|
||||
RED.projects.showFilesPrompt();
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -285,13 +295,13 @@ var RED = (function() {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "No thanks",
|
||||
text: RED._("notification.project.no"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Create default project files",
|
||||
text: RED._("notification.project.createDefault"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.createDefaultFileSet();
|
||||
@@ -305,7 +315,7 @@ var RED = (function() {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Show merge conflicts",
|
||||
text: RED._("notification.project.mergeConflict"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.sidebar.versionControl.showLocalChanges();
|
||||
|
@@ -327,6 +327,14 @@
|
||||
},
|
||||
length: function() {
|
||||
return this.element.children().length;
|
||||
},
|
||||
show: function(item) {
|
||||
var items = this.element.children().filter(function(f) {
|
||||
return item === $(this).find(".red-ui-editableList-item-content").data('data');
|
||||
});
|
||||
if (items.length > 0) {
|
||||
this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top)
|
||||
}
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
|
@@ -15,6 +15,19 @@
|
||||
**/
|
||||
(function($) {
|
||||
|
||||
/**
|
||||
* options:
|
||||
* - minimumLength : the minimum length of text before firing a change event
|
||||
* - delay : delay, in ms, after a keystroke before firing change event
|
||||
*
|
||||
* methods:
|
||||
* - value([val]) - gets the current value, or, if `val` is provided, sets the value
|
||||
* - count - sets or clears a sub-label on the input. This can be used to provide
|
||||
* a feedback on the number of matches, or number of available entries to search
|
||||
* - change - trigger a change event
|
||||
*
|
||||
*/
|
||||
|
||||
$.widget( "nodered.searchBox", {
|
||||
_create: function() {
|
||||
var that = this;
|
||||
|
@@ -36,7 +36,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
if (options.addButton) {
|
||||
wrapper.addClass("red-ui-tabs-add");
|
||||
var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
|
||||
var addButton = $('<div class="red-ui-tab-button red-ui-tabs-add"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
|
||||
addButton.find('a').click(function(evt) {
|
||||
evt.preventDefault();
|
||||
if (typeof options.addButton === 'function') {
|
||||
@@ -69,7 +69,25 @@ RED.tabs = (function() {
|
||||
RED.actions.invoke(options.addButton,{index:targetIndex});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
if (options.searchButton) {
|
||||
wrapper.addClass("red-ui-tabs-search");
|
||||
var searchButton = $('<div class="red-ui-tab-button red-ui-tabs-search"><a href="#"><i class="fa fa-list-ul"></i></a></div>').appendTo(wrapper);
|
||||
searchButton.find('a').click(function(evt) {
|
||||
evt.preventDefault();
|
||||
if (typeof options.searchButton === 'function') {
|
||||
options.searchButton()
|
||||
} else if (typeof options.searchButton === 'string') {
|
||||
RED.actions.invoke(options.searchButton);
|
||||
}
|
||||
})
|
||||
if (typeof options.searchButton === 'string') {
|
||||
var l = options.searchButton;
|
||||
if (options.searchButtonCaption) {
|
||||
l = options.searchButtonCaption
|
||||
}
|
||||
RED.popover.tooltip(searchButton,l,options.searchButton);
|
||||
}
|
||||
|
||||
}
|
||||
var scrollLeft;
|
||||
|
@@ -148,7 +148,7 @@
|
||||
if (item.icon) {
|
||||
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
|
||||
}
|
||||
$('<span class="red-ui-treeList-label-text"></span>').html(item.label).appendTo(label);
|
||||
$('<span class="red-ui-treeList-label-text"></span>').text(item.label).appendTo(label);
|
||||
if (item.children) {
|
||||
if (Array.isArray(item.children)) {
|
||||
that._addChildren(container,item.children,depth);
|
||||
@@ -171,6 +171,13 @@
|
||||
} else {
|
||||
return this._data;
|
||||
}
|
||||
},
|
||||
show: function(id) {
|
||||
for (var i=0;i<this._data.length;i++) {
|
||||
if (this._data[i].id === id) {
|
||||
this._topList.editableList('show',this._data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -159,6 +159,11 @@
|
||||
that.uiSelect.css("margin"+d,m);
|
||||
that.input.css("margin"+d,0);
|
||||
});
|
||||
|
||||
["type","placeholder"].forEach(function(d) {
|
||||
var m = that.element.attr(d);
|
||||
that.input.attr(d,m);
|
||||
});
|
||||
|
||||
this.uiSelect.addClass("red-ui-typedInput-container");
|
||||
|
||||
|
@@ -261,7 +261,9 @@ RED.deploy = (function() {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function sanitize(html) {
|
||||
return html.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")
|
||||
}
|
||||
function restart() {
|
||||
var startTime = Date.now();
|
||||
$(".deploy-button-content").css('opacity',0);
|
||||
@@ -353,7 +355,7 @@ RED.deploy = (function() {
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.unknown')+"</p>"+
|
||||
'<ul class="node-dialog-configm-deploy-list"><li>'+cropList(unknownNodes).join("</li><li>")+"</li></ul><p>"+
|
||||
'<ul class="node-dialog-configm-deploy-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
|
||||
@@ -373,7 +375,7 @@ RED.deploy = (function() {
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.improperlyConfigured')+"</p>"+
|
||||
'<ul class="node-dialog-configm-deploy-list"><li>'+cropList(invalidNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"})).join("</li><li>")+"</li></ul><p>"+
|
||||
'<ul class="node-dialog-configm-deploy-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
notificationButtons= [
|
||||
|
@@ -687,7 +687,7 @@ RED.diff = (function() {
|
||||
diff: remoteDiff
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var selectState = "";
|
||||
|
||||
if (conflicted) {
|
||||
@@ -1158,19 +1158,19 @@ RED.diff = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
var diff = {
|
||||
currentConfig: currentConfig,
|
||||
newConfig: newConfig,
|
||||
added: added,
|
||||
deleted: deleted,
|
||||
changed: changed,
|
||||
moved: moved
|
||||
}
|
||||
};
|
||||
return diff;
|
||||
}
|
||||
function resolveDiffs(localDiff,remoteDiff) {
|
||||
var conflicted = {};
|
||||
var resolutions = {};
|
||||
|
||||
var diff = {
|
||||
localDiff: localDiff,
|
||||
remoteDiff: remoteDiff,
|
||||
@@ -1348,7 +1348,7 @@ RED.diff = (function() {
|
||||
if (node) {
|
||||
nodeChangedStates[id] = node.changed;
|
||||
}
|
||||
localChangedStates[id] = true;
|
||||
localChangedStates[id] = 1;
|
||||
newConfig.push(remoteDiff.newConfig.all[id]);
|
||||
}
|
||||
} else {
|
||||
@@ -1363,7 +1363,7 @@ RED.diff = (function() {
|
||||
nodeChangedStates[id] = node.changed;
|
||||
}
|
||||
if (!localDiff.added.hasOwnProperty(id)) {
|
||||
localChangedStates[id] = true;
|
||||
localChangedStates[id] = 2;
|
||||
newConfig.push(remoteDiff.newConfig.all[id]);
|
||||
}
|
||||
}
|
||||
@@ -1376,24 +1376,42 @@ RED.diff = (function() {
|
||||
}
|
||||
|
||||
function mergeDiff(diff) {
|
||||
//console.log(diff);
|
||||
var appliedDiff = applyDiff(diff);
|
||||
|
||||
var newConfig = appliedDiff.config;
|
||||
var nodeChangedStates = appliedDiff.nodeChangedStates;
|
||||
var localChangedStates = appliedDiff.localChangedStates;
|
||||
|
||||
var isDirty = RED.nodes.dirty();
|
||||
|
||||
var historyEvent = {
|
||||
t:"replace",
|
||||
config: RED.nodes.createCompleteNodeSet(),
|
||||
changed: nodeChangedStates,
|
||||
dirty: RED.nodes.dirty(),
|
||||
dirty: isDirty,
|
||||
rev: RED.nodes.version()
|
||||
}
|
||||
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
var originalFlow = RED.nodes.originalFlow();
|
||||
// originalFlow is what the editor things it loaded
|
||||
// - add any newly added nodes from remote diff as they are now part of the record
|
||||
for (var id in diff.remoteDiff.added) {
|
||||
if (diff.remoteDiff.added.hasOwnProperty(id)) {
|
||||
if (diff.remoteDiff.newConfig.all.hasOwnProperty(id)) {
|
||||
originalFlow.push(JSON.parse(JSON.stringify(diff.remoteDiff.newConfig.all[id])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.clear();
|
||||
var imported = RED.nodes.import(newConfig);
|
||||
|
||||
// Restore the original flow so subsequent merge resolutions can properly
|
||||
// identify new-vs-old
|
||||
RED.nodes.originalFlow(originalFlow);
|
||||
imported[0].forEach(function(n) {
|
||||
if (nodeChangedStates[n.id] || localChangedStates[n.id]) {
|
||||
n.changed = true;
|
||||
@@ -1402,11 +1420,16 @@ RED.diff = (function() {
|
||||
|
||||
RED.nodes.version(diff.remoteDiff.rev);
|
||||
|
||||
if (isDirty) {
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
|
||||
RED.view.redraw(true);
|
||||
RED.palette.refresh();
|
||||
RED.workspaces.refresh();
|
||||
RED.sidebar.config.refresh();
|
||||
}
|
||||
|
||||
function showTestFlowDiff(index) {
|
||||
if (index === 1) {
|
||||
var localFlow = RED.nodes.createCompleteNodeSet();
|
||||
|
@@ -498,7 +498,6 @@ RED.editor = (function() {
|
||||
}
|
||||
|
||||
function getEditStackTitle() {
|
||||
var title = '<ul class="editor-tray-breadcrumbs">';
|
||||
var label;
|
||||
for (var i=editStack.length-1;i<editStack.length;i++) {
|
||||
var node = editStack[i];
|
||||
@@ -514,33 +513,174 @@ RED.editor = (function() {
|
||||
} else if (node.type === '_buffer') {
|
||||
label = RED._("bufferEditor.title");
|
||||
} else if (node.type === 'subflow') {
|
||||
label = RED._("subflow.editSubflow",{name:node.name})
|
||||
label = RED._("subflow.editSubflow",{name:RED.utils.sanitize(node.name)})
|
||||
} else if (node.type.indexOf("subflow:")===0) {
|
||||
var subflow = RED.nodes.subflow(node.type.substring(8));
|
||||
label = RED._("subflow.editSubflow",{name:subflow.name})
|
||||
label = RED._("subflow.editSubflowInstance",{name:RED.utils.sanitize(subflow.name)})
|
||||
} else {
|
||||
if (typeof node._def.paletteLabel !== "undefined") {
|
||||
try {
|
||||
label = (typeof node._def.paletteLabel === "function" ? node._def.paletteLabel.call(node._def) : node._def.paletteLabel)||"";
|
||||
label = RED.utils.sanitize((typeof node._def.paletteLabel === "function" ? node._def.paletteLabel.call(node._def) : node._def.paletteLabel)||"");
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+node.type+".paletteLabel",err);
|
||||
}
|
||||
}
|
||||
if (i === editStack.length-1) {
|
||||
if (RED.nodes.node(node.id)) {
|
||||
label = RED._("editor.editNode",{type:label});
|
||||
label = RED._("editor.editNode",{type:RED.utils.sanitize(label)});
|
||||
} else {
|
||||
label = RED._("editor.addNewConfig",{type:label});
|
||||
label = RED._("editor.addNewConfig",{type:RED.utils.sanitize(label)});
|
||||
}
|
||||
}
|
||||
}
|
||||
title += '<li>'+label+'</li>';
|
||||
}
|
||||
title += '</ul>';
|
||||
return label;
|
||||
}
|
||||
|
||||
function buildEditForm(container,formId,type,ns) {
|
||||
function buildEnvForm(container, node) {
|
||||
var env_container = $('#node-input-env-container');
|
||||
env_container
|
||||
.css({
|
||||
'min-height':'150px',
|
||||
'min-width':'450px'
|
||||
})
|
||||
.editableList({
|
||||
addItem: function(container, i, opt) {
|
||||
var row = $('<div/>').appendTo(container);
|
||||
if (opt.parent) {
|
||||
$('<div/>', {
|
||||
class:"uneditable-input",
|
||||
style: "margin-left: 5px; width: calc(40% - 8px)",
|
||||
}).appendTo(row).text(opt.name);
|
||||
} else {
|
||||
$('<input/>', {
|
||||
class: "node-input-env-name",
|
||||
type: "text",
|
||||
style: "margin-left: 5px; width: calc(40% - 8px)",
|
||||
placeholder: RED._("common.label.name")
|
||||
}).appendTo(row).val(opt.name);
|
||||
}
|
||||
var valueField = $('<input/>',{
|
||||
class: "node-input-env-value",
|
||||
type: "text",
|
||||
style: "margin-left: 5px; width: calc(60% - 8px)"
|
||||
}).appendTo(row)
|
||||
|
||||
valueField.typedInput({default:'str',
|
||||
types:['str','num','bool','json','bin','env']
|
||||
});
|
||||
|
||||
valueField.typedInput('type', opt.parent?(opt.type||opt.parent.type):opt.type);
|
||||
valueField.typedInput('value', opt.parent?(opt.value||opt.parent.value):opt.value);
|
||||
|
||||
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(container);
|
||||
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
||||
container.parent().addClass("red-ui-editableList-item-removable");
|
||||
if (opt.parent) {
|
||||
if (opt.value && (opt.value !== opt.parent.value || opt.type !== opt.parent.type)) {
|
||||
actionButton.show();
|
||||
} else {
|
||||
actionButton.hide();
|
||||
}
|
||||
var restoreTip = RED.popover.tooltip(actionButton,RED._("subflow.env.restore"));
|
||||
valueField.change(function(evt) {
|
||||
var newType = valueField.typedInput('type');
|
||||
var newValue = valueField.typedInput('value');
|
||||
if (newType === opt.parent.type && newValue === opt.parent.value) {
|
||||
actionButton.hide();
|
||||
} else {
|
||||
actionButton.show();
|
||||
}
|
||||
})
|
||||
actionButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
restoreTip.close();
|
||||
valueField.typedInput('type', opt.parent.type);
|
||||
valueField.typedInput('value', opt.parent.value);
|
||||
})
|
||||
} else {
|
||||
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
||||
actionButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
removeTip.close();
|
||||
container.parent().addClass("red-ui-editableList-item-deleting")
|
||||
container.fadeOut(300, function() {
|
||||
env_container.editableList('removeItem',opt);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
sortable: false,
|
||||
removable: false
|
||||
});
|
||||
var parentEnv = {};
|
||||
var envList = [];
|
||||
if (/^subflow:/.test(node.type)) {
|
||||
var subflowDef = RED.nodes.subflow(node.type.substring(8));
|
||||
if (subflowDef.env) {
|
||||
subflowDef.env.forEach(function(env) {
|
||||
var item = {
|
||||
name:env.name,
|
||||
parent: {
|
||||
type: env.type,
|
||||
value: env.value
|
||||
}
|
||||
}
|
||||
envList.push(item);
|
||||
parentEnv[env.name] = item;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (node.env) {
|
||||
for (var i = 0; i < node.env.length; i++) {
|
||||
var env = node.env[i];
|
||||
if (parentEnv.hasOwnProperty(env.name)) {
|
||||
parentEnv[env.name].type = env.type;
|
||||
parentEnv[env.name].value = env.value;
|
||||
} else {
|
||||
envList.push({
|
||||
name: env.name,
|
||||
type: env.type,
|
||||
value: env.value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
envList.forEach(function(env) {
|
||||
env_container.editableList('addItem', env);
|
||||
})
|
||||
}
|
||||
|
||||
function exportEnvList(list) {
|
||||
if (list) {
|
||||
var env = [];
|
||||
list.each(function(i) {
|
||||
var entry = $(this);
|
||||
var item = entry.data('data');
|
||||
var name = item.parent?item.name:entry.find(".node-input-env-name").val();
|
||||
var valueInput = entry.find(".node-input-env-value");
|
||||
var value = valueInput.typedInput("value");
|
||||
var type = valueInput.typedInput("type");
|
||||
if (!item.parent || (item.parent.value !== value || item.parent.type !== type)) {
|
||||
var item = {
|
||||
name: name,
|
||||
type: type,
|
||||
value: value
|
||||
};
|
||||
env.push(item);
|
||||
}
|
||||
});
|
||||
return env;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isSameEnv(env0, env1) {
|
||||
return (JSON.stringify(env0) === JSON.stringify(env1));
|
||||
}
|
||||
|
||||
function buildEditForm(container,formId,type,ns,node) {
|
||||
var dialogForm = $('<form id="'+formId+'" class="form-horizontal" autocomplete="off"></form>').appendTo(container);
|
||||
dialogForm.html($("script[data-template-name='"+type+"']").html());
|
||||
ns = ns||"node-red";
|
||||
@@ -561,6 +701,11 @@ RED.editor = (function() {
|
||||
}
|
||||
$(this).attr("data-i18n",keys.join(";"));
|
||||
});
|
||||
|
||||
if ((type === "subflow") || (type === "subflow-template")) {
|
||||
buildEnvForm(dialogForm, node);
|
||||
}
|
||||
|
||||
// Add dummy fields to prevent 'Enter' submitting the form in some
|
||||
// cases, and also prevent browser auto-fill of password
|
||||
// Add in reverse order as they are prepended...
|
||||
@@ -692,7 +837,7 @@ RED.editor = (function() {
|
||||
var id = "node-label-form-"+type+"-"+index;
|
||||
$('<label>',{for:id}).text((index+1)+".").appendTo(result);
|
||||
var input = $('<input>',{type:"text",id:id, placeholder: placeHolder}).val(value).appendTo(result);
|
||||
var clear = $('<button class="editor-button editor-button-small"><i class="fa fa-times"></i></button>').appendTo(result);
|
||||
var clear = $('<button type="button" class="editor-button editor-button-small"><i class="fa fa-times"></i></button>').appendTo(result);
|
||||
clear.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
input.val("");
|
||||
@@ -749,7 +894,7 @@ RED.editor = (function() {
|
||||
var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
|
||||
var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
|
||||
var summary = $('<span>').appendTo(metaRow);
|
||||
var resetButton = $('<button class="editor-button editor-button-small">'+RED._("editor.useDefault")+'</button>').appendTo(metaRow).click(function(e) {
|
||||
var resetButton = $('<button type="button" class="editor-button editor-button-small">'+RED._("editor.useDefault")+'</button>').appendTo(metaRow).click(function(e) {
|
||||
e.preventDefault();
|
||||
hide();
|
||||
done(null);
|
||||
@@ -798,7 +943,7 @@ RED.editor = (function() {
|
||||
|
||||
$('<div class="form-row">'+
|
||||
'<label for="node-input-show-label-btn" data-i18n="editor.label"></label>'+
|
||||
'<button id="node-input-show-label-btn" class="editor-button" style="min-width: 80px; text-align: left;" type="button"><i id="node-input-show-label-btn-i" class="fa fa-toggle-on"></i> <span id="node-input-show-label-label"></span></button> '+
|
||||
'<button type="button" id="node-input-show-label-btn" class="editor-button" style="min-width: 80px; text-align: left;" type="button"><i id="node-input-show-label-btn-i" class="fa fa-toggle-on"></i> <span id="node-input-show-label-label"></span></button> '+
|
||||
'<input type="checkbox" id="node-input-show-label" style="display: none;"/>'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
|
||||
@@ -832,7 +977,7 @@ RED.editor = (function() {
|
||||
var iconRow = $('<div class="form-row"></div>').appendTo(dialogForm);
|
||||
$('<label data-i18n="editor.settingIcon">').appendTo(iconRow);
|
||||
|
||||
var iconButton = $('<button class="editor-button" id="node-settings-icon-button">').appendTo(iconRow);
|
||||
var iconButton = $('<button type="button" class="editor-button" id="node-settings-icon-button">').appendTo(iconRow);
|
||||
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconButton);
|
||||
var colour = RED.utils.getNodeColor(node.type, node._def);
|
||||
@@ -1268,6 +1413,16 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
if (type === "subflow") {
|
||||
var old_env = editing_node.env;
|
||||
var new_env = exportEnvList($("#node-input-env-container").editableList("items"));
|
||||
if (!isSameEnv(old_env, new_env)) {
|
||||
editing_node.env = new_env;
|
||||
changes.env = editing_node.env;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
var wasChanged = editing_node.changed;
|
||||
editing_node.changed = true;
|
||||
@@ -1373,7 +1528,7 @@ RED.editor = (function() {
|
||||
content: $('<div>', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-cog"
|
||||
};
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns);
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns,node);
|
||||
editorTabs.addTab(nodePropertiesTab);
|
||||
|
||||
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
|
||||
@@ -1580,7 +1735,7 @@ RED.editor = (function() {
|
||||
if (nodeUserFlows[ws.id]) {
|
||||
workspaceLabel = "* "+workspaceLabel;
|
||||
}
|
||||
tabSelect.append('<option value="'+ws.id+'"'+(ws.id==editing_config_node.z?" selected":"")+'>'+workspaceLabel+'</option>');
|
||||
$('<option value="'+ws.id+'"'+(ws.id==editing_config_node.z?" selected":"")+'></option>').text(workspaceLabel).appendTo(tabSelect);
|
||||
});
|
||||
tabSelect.append('<option disabled data-i18n="sidebar.config.subflows"></option>');
|
||||
RED.nodes.eachSubflow(function(ws) {
|
||||
@@ -1588,7 +1743,7 @@ RED.editor = (function() {
|
||||
if (nodeUserFlows[ws.id]) {
|
||||
workspaceLabel = "* "+workspaceLabel;
|
||||
}
|
||||
tabSelect.append('<option value="'+ws.id+'"'+(ws.id==editing_config_node.z?" selected":"")+'>'+workspaceLabel+'</option>');
|
||||
$('<option value="'+ws.id+'"'+(ws.id==editing_config_node.z?" selected":"")+'></option>').text(workspaceLabel).appendTo(tabSelect);
|
||||
});
|
||||
if (flowCount > 0) {
|
||||
tabSelect.on('change',function() {
|
||||
@@ -1909,7 +2064,7 @@ RED.editor = (function() {
|
||||
}
|
||||
|
||||
configNodes.forEach(function(cn) {
|
||||
select.append('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'>'+RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)+'</option>');
|
||||
$('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'></option>').text(RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)).appendTo(select);
|
||||
delete cn.__label__;
|
||||
});
|
||||
|
||||
@@ -1986,6 +2141,14 @@ RED.editor = (function() {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
var old_env = editing_node.env;
|
||||
var new_env = exportEnvList($("#node-input-env-container").editableList("items"));
|
||||
if (!isSameEnv(old_env, new_env)) {
|
||||
editing_node.env = new_env;
|
||||
changes.env = editing_node.env;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
RED.palette.refresh();
|
||||
|
||||
if (changed) {
|
||||
@@ -2024,9 +2187,17 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
$(".editor-tray-content").height(dimensions.height - 50);
|
||||
var form = $(".editor-tray-content form").height(dimensions.height - 50 - 40);
|
||||
resize: function(size) {
|
||||
$(".editor-tray-content").height(size.height - 50);
|
||||
// var form = $(".editor-tray-content form").height(size.height - 50 - 40);
|
||||
var rows = $("#dialog-form>div:not(.node-input-env-container-row)");
|
||||
var height = size.height;
|
||||
for (var i=0; i<rows.size(); i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
var editorRow = $("#dialog-form>div.node-input-env-container-row");
|
||||
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-env-container").editableList('height',height-80);
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayFooter = tray.find(".editor-tray-footer");
|
||||
@@ -2063,7 +2234,7 @@ RED.editor = (function() {
|
||||
content: $('<div>', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
|
||||
iconClass: "fa fa-cog"
|
||||
};
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template");
|
||||
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
|
||||
editorTabs.addTab(nodePropertiesTab);
|
||||
|
||||
var descriptionTab = {
|
||||
@@ -2224,7 +2395,7 @@ RED.editor = (function() {
|
||||
$(el).addClass("node-text-editor-container-toolbar");
|
||||
editor.toolbar = customEditTypes['_markdown'].buildToolbar(toolbarRow,editor);
|
||||
if (options.expandable !== false) {
|
||||
var expandButton = $('<button class="editor-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(editor.toolbar);
|
||||
var expandButton = $('<button type="button" class="editor-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(editor.toolbar);
|
||||
|
||||
expandButton.click(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -2243,7 +2414,7 @@ RED.editor = (function() {
|
||||
})
|
||||
});
|
||||
}
|
||||
var helpButton = $('<button class="node-text-editor-help editor-button editor-button-small"><i class="fa fa-question"></i></button>').appendTo($(el).parent());
|
||||
var helpButton = $('<button type="button" class="node-text-editor-help editor-button editor-button-small"><i class="fa fa-question"></i></button>').appendTo($(el).parent());
|
||||
RED.popover.create({
|
||||
target: helpButton,
|
||||
trigger: 'click',
|
||||
|
@@ -17,21 +17,21 @@
|
||||
|
||||
var toolbarTemplate = '<div style="margin-bottom: 5px">'+
|
||||
'<span class="button-group">'+
|
||||
'<button class="editor-button" data-style="h1" style="font-size:1.1em; font-weight: bold">h1</button>'+
|
||||
'<button class="editor-button" data-style="h2" style="font-size:1.0em; font-weight: bold">h2</button>'+
|
||||
'<button class="editor-button" data-style="h3" style="font-size:0.9em; font-weight: bold">h3</button>'+
|
||||
'<button type="button" class="editor-button" data-style="h1" style="font-size:1.1em; font-weight: bold">h1</button>'+
|
||||
'<button type="button" class="editor-button" data-style="h2" style="font-size:1.0em; font-weight: bold">h2</button>'+
|
||||
'<button type="button" class="editor-button" data-style="h3" style="font-size:0.9em; font-weight: bold">h3</button>'+
|
||||
'</span>'+
|
||||
'<span class="button-group">'+
|
||||
'<button class="editor-button" data-style="b"><i class="fa fa-bold"></i></button>'+
|
||||
'<button class="editor-button" data-style="i"><i class="fa fa-italic"></i></button>'+
|
||||
'<button class="editor-button" data-style="code"><i class="fa fa-code"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="b"><i class="fa fa-bold"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="i"><i class="fa fa-italic"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="code"><i class="fa fa-code"></i></button>'+
|
||||
'</span>'+
|
||||
'<span class="button-group">'+
|
||||
'<button class="editor-button" data-style="ol"><i class="fa fa-list-ol"></i></button>'+
|
||||
'<button class="editor-button" data-style="ul"><i class="fa fa-list-ul"></i></button>'+
|
||||
'<button class="editor-button" data-style="bq"><i class="fa fa-quote-left"></i></button>'+
|
||||
'<button class="editor-button" data-style="hr"><i class="fa fa-minus"></i></button>'+
|
||||
'<button class="editor-button" data-style="link"><i class="fa fa-link"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="ol"><i class="fa fa-list-ol"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="ul"><i class="fa fa-list-ul"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="bq"><i class="fa fa-quote-left"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="hr"><i class="fa fa-minus"></i></button>'+
|
||||
'<button type="button" class="editor-button" data-style="link"><i class="fa fa-link"></i></button>'+
|
||||
'</span>'
|
||||
'</div>';
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
panels.ratio(1);
|
||||
|
||||
$('<span class="button-group" style="float:right">'+
|
||||
'<button id="node-btn-markdown-preview" class="editor-button toggle single"><i class="fa fa-eye"></i></button>'+
|
||||
'<button type="button" id="node-btn-markdown-preview" class="editor-button toggle single"><i class="fa fa-eye"></i></button>'+
|
||||
'</span>').appendTo(expressionEditor.toolbar);
|
||||
|
||||
$("#node-btn-markdown-preview").click(function(e) {
|
||||
|
15
packages/node_modules/@node-red/editor-client/src/js/ui/library.js
vendored
Normal file → Executable file
15
packages/node_modules/@node-red/editor-client/src/js/ui/library.js
vendored
Normal file → Executable file
@@ -44,8 +44,8 @@ RED.library = (function() {
|
||||
li.className = "dropdown-submenu pull-left";
|
||||
a = document.createElement("a");
|
||||
a.href="#";
|
||||
var label = i.replace(/^@.*\//,"").replace(/^node-red-contrib-/,"").replace(/^node-red-node-/,"").replace(/-/," ").replace(/_/," ");
|
||||
a.innerHTML = label;
|
||||
var label = i.replace(/^@.*\//,"").replace(/^node-red-contrib-/,"").replace(/^node-red-node-/,"").replace(/-/g," ").replace(/_/g," ");
|
||||
a.innerText = label;
|
||||
li.appendChild(a);
|
||||
li.appendChild(buildMenu(data.d[i],root+(root!==""?"/":"")+i));
|
||||
ul.appendChild(li);
|
||||
@@ -58,7 +58,7 @@ RED.library = (function() {
|
||||
li = document.createElement("li");
|
||||
a = document.createElement("a");
|
||||
a.href="#";
|
||||
a.innerHTML = data.f[i];
|
||||
a.innerText = data.f[i];
|
||||
a.flowName = root+(root!==""?"/":"")+data.f[i];
|
||||
a.onclick = function() {
|
||||
$.get('library/flows/'+this.flowName, function(data) {
|
||||
@@ -125,8 +125,8 @@ RED.library = (function() {
|
||||
li.onclick = (function () {
|
||||
var dirName = v;
|
||||
return function(e) {
|
||||
var bcli = $('<li class="active"><span class="divider">/</span> <a href="#">'+dirName+'</a></li>');
|
||||
$("a",bcli).click(function(e) {
|
||||
var bcli = $('<li class="active"><span class="divider">/</span> </li>');
|
||||
$('<a href="#"></a>').text(dirName).appendTo(bcli).click(function(e) {
|
||||
$(this).parent().nextAll().remove();
|
||||
$.getJSON("library/"+options.url+root+dirName,function(data) {
|
||||
$("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
|
||||
@@ -141,12 +141,13 @@ RED.library = (function() {
|
||||
});
|
||||
}
|
||||
})();
|
||||
li.innerHTML = '<i class="fa fa-folder"></i> '+v+"</i>";
|
||||
$('<i class="fa fa-folder"></i>').appendTo(li);
|
||||
$('<span>').text(" "+v).appendTo(li);
|
||||
ul.appendChild(li);
|
||||
} else {
|
||||
// file
|
||||
li = buildFileListItem(v);
|
||||
li.innerHTML = v.name;
|
||||
li.innerText = v.name;
|
||||
li.onclick = (function() {
|
||||
var item = v;
|
||||
return function(e) {
|
||||
|
23
packages/node_modules/@node-red/editor-client/src/js/ui/palette.js
vendored
Normal file → Executable file
23
packages/node_modules/@node-red/editor-client/src/js/ui/palette.js
vendored
Normal file → Executable file
@@ -78,6 +78,8 @@ RED.palette = (function() {
|
||||
var lineHeight = 20;
|
||||
var portHeight = 10;
|
||||
|
||||
label = RED.utils.sanitize(label);
|
||||
|
||||
var words = label.split(/[ -]/);
|
||||
|
||||
var displayLines = [];
|
||||
@@ -175,13 +177,19 @@ RED.palette = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
$('<div/>',{class:"palette_label"+(def.align=="right"?" palette_label_right":"")}).appendTo(d);
|
||||
$('<div/>', {
|
||||
class: "palette_label"
|
||||
+ (((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " palette_label_right" : "")
|
||||
}).appendTo(d);
|
||||
|
||||
d.className="palette_node";
|
||||
|
||||
if (def.icon) {
|
||||
var icon_url = RED.utils.getNodeIcon(def);
|
||||
var iconContainer = $('<div/>',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d);
|
||||
var iconContainer = $('<div/>', {
|
||||
class: "palette_icon_container"
|
||||
+ (((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " palette_icon_container_right" : "")
|
||||
}).appendTo(d);
|
||||
RED.utils.createIconElement(icon_url, iconContainer, true);
|
||||
}
|
||||
|
||||
@@ -382,6 +390,17 @@ RED.palette = (function() {
|
||||
var portInput = paletteNode.find(".palette_port_input");
|
||||
var portOutput = paletteNode.find(".palette_port_output");
|
||||
|
||||
var paletteLabel = paletteNode.find(".palette_label");
|
||||
paletteLabel.attr("class","palette_label"
|
||||
+ (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " palette_label_right" : "")
|
||||
);
|
||||
|
||||
var paletteIconContainer = paletteNode.find(".palette_icon_container");
|
||||
paletteIconContainer.attr("class","palette_icon_container"
|
||||
+ (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " palette_icon_container_right" : "")
|
||||
);
|
||||
|
||||
|
||||
if (portInput.length === 0 && sf.in.length > 0) {
|
||||
var portIn = document.createElement("div");
|
||||
portIn.className = "palette_port palette_port_input";
|
||||
|
@@ -526,7 +526,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
}
|
||||
|
||||
function showProjectFileListing(row,activeProject,current,filter,done) {
|
||||
function showProjectFileListing(row,activeProject,current,selectFilter,done) {
|
||||
var dialog;
|
||||
var dialogBody;
|
||||
var filesList;
|
||||
@@ -569,14 +569,15 @@ RED.projects.settings = (function() {
|
||||
})
|
||||
return result;
|
||||
}
|
||||
var files = sortFiles("",files,"");
|
||||
createFileSubList(container,files.children,current,filter,done,"height: 175px");
|
||||
var files = sortFiles("",files,"")
|
||||
|
||||
createFileSubList(container,files.children,current,selectFilter,done,"height: 175px");
|
||||
spinner.remove();
|
||||
});
|
||||
return container;
|
||||
}
|
||||
|
||||
function createFileSubList(container, files, current, filter, onselect, style) {
|
||||
function createFileSubList(container, files, current, selectFilter, onselect, style) {
|
||||
style = style || "";
|
||||
var list = $('<ol>',{class:"projects-dialog-file-list", style:style}).appendTo(container).editableList({
|
||||
addButton: false,
|
||||
@@ -592,7 +593,7 @@ RED.projects.settings = (function() {
|
||||
} else {
|
||||
children.hide();
|
||||
}
|
||||
createFileSubList(children,entry.children,current,filter,onselect);
|
||||
createFileSubList(children,entry.children,current,selectFilter,onselect);
|
||||
header.addClass("selectable");
|
||||
header.click(function(e) {
|
||||
if ($(this).hasClass("expanded")) {
|
||||
@@ -618,7 +619,7 @@ RED.projects.settings = (function() {
|
||||
header.addClass("projects-dialog-file-list-entry-file-type-git");
|
||||
}
|
||||
$('<span class="projects-dialog-file-list-entry-file"> <i class="fa '+fileIcon+'"></i></span>').appendTo(header);
|
||||
if (filter.test(entry.name)) {
|
||||
if (selectFilter(entry)) {
|
||||
header.addClass("selectable");
|
||||
if (entry.path === current) {
|
||||
header.addClass("selected");
|
||||
@@ -626,7 +627,7 @@ RED.projects.settings = (function() {
|
||||
header.click(function(e) {
|
||||
$(".projects-dialog-file-list-entry.selected").removeClass("selected");
|
||||
$(this).addClass("selected");
|
||||
onselect(entry.path);
|
||||
onselect(entry.path,true);
|
||||
})
|
||||
header.dblclick(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -730,18 +731,27 @@ RED.projects.settings = (function() {
|
||||
var title = $('<h3></h3>').text(RED._("sidebar.project.projectSettings.files")).appendTo(pane);
|
||||
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.projectSettings.edit') + '</button>')
|
||||
var editFilesButton = $('<button type="button" id="project-settings-tab-settings-file-edit" class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.projectSettings.edit') + '</button>')
|
||||
.appendTo(title)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
formButtons.show();
|
||||
editFilesButton.hide();
|
||||
// packageFileLabelText.hide();
|
||||
|
||||
if (!activeProject.files.package) {
|
||||
packageFileSubLabel.find(".projects-edit-form-sublabel-text").text(RED._("sidebar.project.projectSettings.packageCreate"));
|
||||
packageFileSubLabel.show();
|
||||
}
|
||||
|
||||
packageFileInputSearch.show();
|
||||
// packageFileInputCreate.show();
|
||||
flowFileLabelText.hide();
|
||||
flowFileInput.show();
|
||||
flowFileInputSearch.show();
|
||||
credFileLabel.hide();
|
||||
credFileInput.show();
|
||||
flowFileInput.focus();
|
||||
|
||||
flowFileInputResize();
|
||||
|
||||
// credentialStateLabel.parent().hide();
|
||||
credentialStateLabel.addClass("uneditable-input");
|
||||
$(".user-settings-row-credentials").show();
|
||||
@@ -752,14 +762,83 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
var row;
|
||||
|
||||
// Flow files
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.package")).appendTo(row);
|
||||
var packageFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
|
||||
var packageFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.package||"package.json").appendTo(packageFileLabel);
|
||||
var packageFileInput = $('<input type="hidden">').val(activeProject.files.package||"package.json").appendTo(packageFileLabel);
|
||||
|
||||
var packageFileInputSearch = $('<button type="button" class="editor-button toggle single" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 36px; height: 34px; position: absolute; top: -1px; right: -1px;"><i class="fa fa-folder-open-o"></i></button>')
|
||||
.hide()
|
||||
.appendTo(packageFileLabel)
|
||||
.click(function(e) {
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected');
|
||||
packageFileLabel.find('.project-file-listing-container').slideUp(200,function() {
|
||||
$(this).remove();
|
||||
packageFileLabel.css('height','');
|
||||
});
|
||||
packageFileLabel.css('color','');
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
packageFileLabel.css('color','inherit');
|
||||
var fileList = showProjectFileListing(packageFileLabel,activeProject,packageFileInput.val(),
|
||||
function(entry) { return entry.children || /package\.json$/.test(entry.path); },
|
||||
function(result,close) {
|
||||
if (result) {
|
||||
packageFileInput.val(result);
|
||||
packageFileLabelText.text(result);
|
||||
var rootDir = result.substring(0,result.length - 12);
|
||||
flowFileLabelPrefixText.text(rootDir);
|
||||
credFileLabelPrefixText.text(rootDir);
|
||||
flowFileInputResize();
|
||||
packageFileSubLabel.hide();
|
||||
}
|
||||
if (close) {
|
||||
$(packageFileInputSearch).click();
|
||||
}
|
||||
checkFiles();
|
||||
});
|
||||
packageFileLabel.css('height','auto');
|
||||
setTimeout(function() {
|
||||
fileList.slideDown(200);
|
||||
},50);
|
||||
|
||||
}
|
||||
})
|
||||
RED.popover.tooltip(packageFileInputSearch,RED._("sidebar.project.projectSettings.selectFile"));
|
||||
var packageFileSubLabel = $('<label style="margin-left: 110px" class="projects-edit-form-sublabel"><small><span class="form-warning"><i class="fa fa-warning"></i> <span class="projects-edit-form-sublabel-text"></span></small></label>').appendTo(row).hide();
|
||||
if (!activeProject.files.package) {
|
||||
packageFileSubLabel.find(".projects-edit-form-sublabel-text").text(RED._("sidebar.project.projectSettings.fileNotExist"));
|
||||
packageFileSubLabel.show();
|
||||
}
|
||||
|
||||
|
||||
var projectPackage = activeProject.files.package||"package.json";
|
||||
var projectRoot = projectPackage.substring(0,projectPackage.length - 12);
|
||||
|
||||
// Flow files
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.flow")).appendTo(row);
|
||||
var flowFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
|
||||
var flowFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.flow).appendTo(flowFileLabel);
|
||||
|
||||
var flowFileInput = $('<input id="" type="text" style="margin-bottom: 0;width: 100%; border: none;">').val(activeProject.files.flow).hide().appendTo(flowFileLabel);
|
||||
var flowFileInputSearch = $('<button class="editor-button" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 36px; height: 34px; position: absolute; top: -1px; right: -1px;"><i class="fa fa-folder-open-o"></i></button>')
|
||||
var flowFileLabelPrefixText = $('<span style="display:inline-block; padding: 6px 0 6px 6px">').text(projectRoot).appendTo(flowFileLabel);
|
||||
var flowFileName = "flows.json";
|
||||
if (activeProject.files.flow) {
|
||||
if (activeProject.files.flow.indexOf(projectRoot) === 0) {
|
||||
flowFileName = activeProject.files.flow.substring(projectRoot.length);
|
||||
} else {
|
||||
flowFileName = activeProject.files.flow;
|
||||
}
|
||||
}
|
||||
var flowFileLabelText = $('<span style="display:inline-block; padding: 6px 6px 6px 0">').text(flowFileName).appendTo(flowFileLabel);
|
||||
var flowFileInputResize = function() {
|
||||
flowFileInput.css({
|
||||
"width": "calc(100% - "+(flowFileInputSearch.width() + flowFileLabelPrefixText.width())+"px)"
|
||||
});
|
||||
}
|
||||
var flowFileInput = $('<input type="text" style="padding-left:1px; margin-top: -2px; margin-bottom: 0;border: none;">').val(flowFileName).hide().appendTo(flowFileLabel);
|
||||
var flowFileInputSearch = $('<button type="button" class="editor-button toggle single" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 36px; height: 34px; position: absolute; top: -1px; right: -1px;"><i class="fa fa-folder-open-o"></i></button>')
|
||||
.hide()
|
||||
.appendTo(flowFileLabel)
|
||||
.click(function(e) {
|
||||
@@ -773,15 +852,24 @@ RED.projects.settings = (function() {
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
flowFileLabel.css('color','inherit');
|
||||
var fileList = showProjectFileListing(flowFileLabel,activeProject,flowFileInput.val(), /.*\.json$/,function(result,isDblClick) {
|
||||
if (result) {
|
||||
flowFileInput.val(result);
|
||||
}
|
||||
if (isDblClick) {
|
||||
$(flowFileInputSearch).click();
|
||||
}
|
||||
checkFiles();
|
||||
});
|
||||
var packageFile = packageFileInput.val();
|
||||
var packagePrefix = packageFile.substring(0,packageFile.length - 12);
|
||||
var re = new RegExp("^"+packagePrefix+".*\.json$");
|
||||
var fileList = showProjectFileListing(flowFileLabel,
|
||||
activeProject,
|
||||
flowFileInput.val(),
|
||||
function(entry) { return !/package.json$/.test(entry.path) && re.test(entry.path) && !/_cred\.json$/.test(entry.path) },
|
||||
function(result,isDblClick) {
|
||||
if (result) {
|
||||
flowFileInput.val(result.substring(packagePrefix.length));
|
||||
|
||||
}
|
||||
if (isDblClick) {
|
||||
$(flowFileInputSearch).click();
|
||||
}
|
||||
checkFiles();
|
||||
}
|
||||
);
|
||||
flowFileLabel.css('height','auto');
|
||||
setTimeout(function() {
|
||||
fileList.slideDown(200);
|
||||
@@ -789,26 +877,41 @@ RED.projects.settings = (function() {
|
||||
|
||||
}
|
||||
})
|
||||
RED.popover.tooltip(flowFileInputSearch,RED._("sidebar.project.projectSettings.selectFile"));
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.credentials")).appendTo(row);
|
||||
var credFileLabel = $('<div class="uneditable-input">').text(activeProject.files.credentials).appendTo(row);
|
||||
var credFileInput = $('<div class="uneditable-input">').text(activeProject.files.credentials).hide().insertAfter(credFileLabel);
|
||||
|
||||
var credFileName = "flows_cred.json";
|
||||
if (activeProject.files.credentials) {
|
||||
if (activeProject.files.flow.indexOf(projectRoot) === 0) {
|
||||
credFileName = activeProject.files.credentials.substring(projectRoot.length);
|
||||
} else {
|
||||
credFileName = activeProject.files.credentials;
|
||||
}
|
||||
}
|
||||
|
||||
var credFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
|
||||
var credFileLabelPrefixText = $('<span style="display:inline-block;padding: 6px 0 6px 6px">').text(projectRoot).appendTo(credFileLabel);
|
||||
var credFileLabelText = $('<span style="display:inline-block; padding: 6px 6px 6px 0">').text(credFileName).appendTo(credFileLabel);
|
||||
|
||||
var credFileInput = $('<input type="hidden">').val(credFileName).insertAfter(credFileLabel);
|
||||
|
||||
var checkFiles = function() {
|
||||
var saveDisabled;
|
||||
var currentFlowValue = flowFileInput.val();
|
||||
var m = /^(.+?)(\.[^.]*)?$/.exec(currentFlowValue);
|
||||
if (m) {
|
||||
credFileInput.text(m[1]+"_cred"+(m[2]||".json"));
|
||||
credFileLabelText.text(m[1]+"_cred"+(m[2]||".json"));
|
||||
} else if (currentFlowValue === "") {
|
||||
credFileInput.text("");
|
||||
credFileLabelText.text("");
|
||||
}
|
||||
credFileInput.val(credFileLabelText.text());
|
||||
var isFlowInvalid = currentFlowValue==="" ||
|
||||
/\.\./.test(currentFlowValue) ||
|
||||
/\/$/.test(currentFlowValue);
|
||||
|
||||
saveDisabled = isFlowInvalid || credFileInput.text()==="";
|
||||
saveDisabled = isFlowInvalid || credFileLabelText.text()==="";
|
||||
|
||||
if (credentialSecretExistingInput.is(":visible")) {
|
||||
credentialSecretExistingInput.toggleClass("input-error", credentialSecretExistingInput.val() === "");
|
||||
@@ -821,19 +924,22 @@ RED.projects.settings = (function() {
|
||||
|
||||
|
||||
flowFileInput.toggleClass("input-error", isFlowInvalid);
|
||||
credFileInput.toggleClass("input-error",credFileInput.text()==="");
|
||||
// credFileInput.toggleClass("input-error",credFileInput.text()==="");
|
||||
saveButton.toggleClass('disabled',saveDisabled);
|
||||
saveButton.prop('disabled',saveDisabled);
|
||||
}
|
||||
flowFileInput.on("change keyup paste",checkFiles);
|
||||
|
||||
|
||||
if (!activeProject.files.flow) {
|
||||
$('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(flowFileLabelText);
|
||||
}
|
||||
if (!activeProject.files.credentials) {
|
||||
$('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(credFileLabel);
|
||||
}
|
||||
// if (!activeProject.files.package) {
|
||||
// $('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(packageFileLabelText);
|
||||
// }
|
||||
// if (!activeProject.files.flow) {
|
||||
// $('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(flowFileLabelText);
|
||||
// }
|
||||
// if (!activeProject.files.credentials) {
|
||||
// $('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(credFileLabel);
|
||||
// }
|
||||
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
|
||||
@@ -844,7 +950,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
credentialStateLabel.css('color','#666');
|
||||
credentialSecretButtons.css('vertical-align','top');
|
||||
var credentialSecretResetButton = $('<button class="editor-button" style="vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-trash-o"></i></button>')
|
||||
var credentialSecretResetButton = $('<button type="button" class="editor-button" style="vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-trash-o"></i></button>')
|
||||
.appendTo(credentialSecretButtons)
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -866,7 +972,9 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
checkFiles();
|
||||
});
|
||||
var credentialSecretEditButton = $('<button class="editor-button" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-pencil"></i></button>')
|
||||
RED.popover.tooltip(credentialSecretResetButton,RED._("sidebar.project.projectSettings.resetTheEncryptionKey"));
|
||||
|
||||
var credentialSecretEditButton = $('<button type="button" class="editor-button" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-pencil"></i></button>')
|
||||
.appendTo(credentialSecretButtons)
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -896,6 +1004,7 @@ RED.projects.settings = (function() {
|
||||
checkFiles();
|
||||
})
|
||||
|
||||
RED.popover.tooltip(credentialSecretEditButton,RED._("sidebar.project.projectSettings.changeTheEncryptionKey"));
|
||||
|
||||
row = $('<div class="user-settings-row user-settings-row-credentials"></div>').hide().appendTo(filesContainer);
|
||||
|
||||
@@ -930,11 +1039,13 @@ RED.projects.settings = (function() {
|
||||
var hideEditForm = function() {
|
||||
editFilesButton.show();
|
||||
formButtons.hide();
|
||||
// packageFileLabelText.show();
|
||||
packageFileInputSearch.hide();
|
||||
// packageFileInputCreate.hide();
|
||||
flowFileLabelText.show();
|
||||
flowFileInput.hide();
|
||||
flowFileInputSearch.hide();
|
||||
credFileLabel.show();
|
||||
credFileInput.hide();
|
||||
|
||||
// credentialStateLabel.parent().show();
|
||||
credentialStateLabel.removeClass("uneditable-input");
|
||||
credentialStateLabel.css('height','');
|
||||
@@ -954,13 +1065,26 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
|
||||
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
|
||||
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
|
||||
$('<button type="button" class="editor-button">' + RED._("common.label.cancel") + '</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var projectPackage = activeProject.files.package||"package.json";
|
||||
var projectRoot = projectPackage.substring(0,projectPackage.length - 12);
|
||||
flowFileLabelPrefixText.text(projectRoot);
|
||||
credFileLabelPrefixText.text(projectRoot);
|
||||
packageFileLabelText.text(activeProject.files.package||"package.json");
|
||||
if (!activeProject.files.package) {
|
||||
packageFileSubLabel.find(".projects-edit-form-sublabel-text").text(RED._("sidebar.project.projectSettings.fileNotExist"));
|
||||
packageFileSubLabel.show();
|
||||
} else {
|
||||
packageFileSubLabel.hide();
|
||||
}
|
||||
flowFileInput.val(flowFileLabelText.text());
|
||||
credFileLabelText.text(credFileName);
|
||||
hideEditForm();
|
||||
});
|
||||
var saveButton = $('<button class="editor-button">' + RED._("common.label.save") + '</button>')
|
||||
var saveButton = $('<button type="button" class="editor-button">' + RED._("common.label.save") + '</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -972,13 +1096,17 @@ RED.projects.settings = (function() {
|
||||
return;
|
||||
}
|
||||
flowFileLabelText.text(flowFileInput.val());
|
||||
credFileLabel.text(credFileInput.text());
|
||||
credFileLabelText.text(credFileInput.val());
|
||||
packageFileSubLabel.hide();
|
||||
hideEditForm();
|
||||
}
|
||||
var rootPath = packageFileInput.val();
|
||||
rootPath = rootPath.substring(0,rootPath.length-12);
|
||||
var payload = {
|
||||
files: {
|
||||
flow: flowFileInput.val(),
|
||||
credentials: credFileInput.text()
|
||||
package: packageFileInput.val(),
|
||||
flow: rootPath+flowFileInput.val(),
|
||||
credentials: rootPath+credFileInput.val()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,8 +1119,6 @@ RED.projects.settings = (function() {
|
||||
payload.currentCredentialSecret = credentialSecretExistingInput.val();
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(JSON.stringify(payload,null,4));
|
||||
RED.deploy.setDeployInflight(true);
|
||||
utils.sendRequest({
|
||||
url: "projects/"+activeProject.name,
|
||||
|
14
packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js
vendored
Normal file → Executable file
14
packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js
vendored
Normal file → Executable file
@@ -105,7 +105,7 @@ RED.projects = (function() {
|
||||
buttons: [
|
||||
{
|
||||
// id: "clipboard-dialog-cancel",
|
||||
text: "Open existing project", //RED._("projects.welcome.not-right-now"),
|
||||
text: RED._("projects.welcome.openExistingProject"),
|
||||
class: "secondary",
|
||||
click: function() {
|
||||
createProjectOptions = {
|
||||
@@ -666,6 +666,10 @@ RED.projects = (function() {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'missing_package_file': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'project_empty': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
@@ -1565,6 +1569,10 @@ RED.projects = (function() {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'missing_package_file': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'project_empty': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
@@ -2053,7 +2061,6 @@ RED.projects = (function() {
|
||||
console.log(xhr);
|
||||
console.log(textStatus);
|
||||
console.log(err);
|
||||
console.log(stack);
|
||||
}).always(function() {
|
||||
var delta = Date.now() - start;
|
||||
delta = Math.max(0,500-delta);
|
||||
@@ -2381,6 +2388,9 @@ RED.projects = (function() {
|
||||
return;
|
||||
}
|
||||
RED.projects.settings.show('settings');
|
||||
setTimeout(function() {
|
||||
$("#project-settings-tab-settings-file-edit").click();
|
||||
},200)
|
||||
},
|
||||
showProjectDependencies: function() {
|
||||
RED.projects.settings.show('deps');
|
||||
|
@@ -82,9 +82,18 @@ RED.search = (function() {
|
||||
|
||||
function search(val) {
|
||||
searchResults.editableList('empty');
|
||||
var typeFilter;
|
||||
var m = /(?:^| )type:([^ ]+)/.exec(val);
|
||||
if (m) {
|
||||
val = val.replace(/(?:^| )type:[^ ]+/,"");
|
||||
typeFilter = m[1];
|
||||
}
|
||||
|
||||
val = val.trim();
|
||||
|
||||
selected = -1;
|
||||
results = [];
|
||||
if (val.length > 0) {
|
||||
if (val.length > 0 || typeFilter) {
|
||||
val = val.toLowerCase();
|
||||
var i;
|
||||
var j;
|
||||
@@ -96,8 +105,10 @@ RED.search = (function() {
|
||||
if (kpos > -1) {
|
||||
for (j=0;j<index[key].length;j++) {
|
||||
var node = index[key][j];
|
||||
nodes[node.node.id] = nodes[node.node.id] = node;
|
||||
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
|
||||
if (!typeFilter || node.node.type === typeFilter) {
|
||||
nodes[node.node.id] = nodes[node.node.id] = node;
|
||||
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,34 +16,36 @@
|
||||
|
||||
RED.subflow = (function() {
|
||||
|
||||
var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow">'+
|
||||
'<div class="form-row"><label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label><input type="text" id="node-input-name"></div>'+
|
||||
'<div class="form-row" style="margin-bottom: 0px;"><label style="width: auto;" data-i18n="[append]editor:editor-tab.env"><i class="fa fa-th-list"></i> </label></div>'+
|
||||
'<div class="form-row node-input-env-container-row"><ol id="node-input-env-container"></ol></div>'+
|
||||
'</script>';
|
||||
|
||||
var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow"><div class="form-row"><label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label><input type="text" id="node-input-name"></div></script>';
|
||||
var _subflowTemplateEditTemplate = '<script type="text/x-red" data-template-name="subflow-template">'+
|
||||
'<div class="form-row"><i class="fa fa-tag"></i> <label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name"></div>'+
|
||||
'<div class="form-row"><i class="fa fa-folder-o"></i> <label for="subflow-input-category" data-i18n="editor:subflow.category"></label><select style="width: 250px;" id="subflow-input-category"></select><input style="display:none; margin-left: 10px; width:calc(100% - 250px)" type="text" id="subflow-input-custom-category"></div>'+
|
||||
'<div class="form-row" style="margin-bottom: 0px;"><label style="width: auto;" data-i18n="[append]editor:editor-tab.env"><i class="fa fa-th-list"></i> </label></div>'+
|
||||
'<div class="form-row node-input-env-container-row"><ol id="node-input-env-container"></ol></div>'+
|
||||
'<div class="form-row form-tips" id="subflow-dialog-user-count"></div>'+
|
||||
'</script>';
|
||||
|
||||
|
||||
function getSubflow() {
|
||||
return RED.nodes.subflow(RED.workspaces.active());
|
||||
}
|
||||
|
||||
function findAvailableSubflowIOPosition(subflow,isInput) {
|
||||
var pos = {x:50,y:30};
|
||||
if (!isInput) {
|
||||
pos.x += 110;
|
||||
}
|
||||
for (var i=0;i<subflow.out.length+subflow.in.length;i++) {
|
||||
var port;
|
||||
if (i < subflow.out.length) {
|
||||
port = subflow.out[i];
|
||||
} else {
|
||||
port = subflow.in[i-subflow.out.length];
|
||||
}
|
||||
var ports = [].concat(subflow.out).concat(subflow.in);
|
||||
if (subflow.status) {
|
||||
ports.push(subflow.status);
|
||||
}
|
||||
ports.sort(function(A,B) {
|
||||
return A.x-B.x;
|
||||
});
|
||||
for (var i=0; i<ports.length; i++) {
|
||||
var port = ports[i];
|
||||
if (port.x == pos.x && port.y == pos.y) {
|
||||
pos.x += 55;
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
@@ -87,6 +89,7 @@ RED.subflow = (function() {
|
||||
RED.view.redraw();
|
||||
$("#workspace-subflow-input-add").addClass("active");
|
||||
$("#workspace-subflow-input-remove").removeClass("active");
|
||||
RED.palette.refresh();
|
||||
}
|
||||
|
||||
function removeSubflowInput() {
|
||||
@@ -108,6 +111,7 @@ RED.subflow = (function() {
|
||||
$("#workspace-subflow-input-add").removeClass("active");
|
||||
$("#workspace-subflow-input-remove").addClass("active");
|
||||
activeSubflow.changed = true;
|
||||
RED.palette.refresh();
|
||||
return {subflowInputs: [ removedInput ], links:removedInputLinks};
|
||||
}
|
||||
|
||||
@@ -148,6 +152,7 @@ RED.subflow = (function() {
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
$("#workspace-subflow-output .spinner-value").text(subflow.out.length);
|
||||
RED.palette.refresh();
|
||||
}
|
||||
|
||||
function removeSubflowOutput(removedSubflowOutputs) {
|
||||
@@ -187,10 +192,65 @@ RED.subflow = (function() {
|
||||
}
|
||||
}
|
||||
activeSubflow.changed = true;
|
||||
|
||||
RED.palette.refresh();
|
||||
return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
|
||||
}
|
||||
|
||||
function addSubflowStatus() {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
if (subflow.status) {
|
||||
return;
|
||||
}
|
||||
var position = findAvailableSubflowIOPosition(subflow,false);
|
||||
var statusNode = {
|
||||
type:"subflow",
|
||||
direction:"status",
|
||||
z:subflow.id,
|
||||
x:position.x,
|
||||
y:position.y,
|
||||
id:RED.nodes.id()
|
||||
};
|
||||
subflow.status = statusNode;
|
||||
subflow.dirty = true;
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
var wasChanged = subflow.changed;
|
||||
subflow.changed = true;
|
||||
var result = refresh(true);
|
||||
var historyEvent = {
|
||||
t:'edit',
|
||||
node:subflow,
|
||||
dirty:wasDirty,
|
||||
changed:wasChanged,
|
||||
subflow: { status: true }
|
||||
};
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select();
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
$("#workspace-subflow-status").prop("checked",!!subflow.status);
|
||||
$("#workspace-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
|
||||
}
|
||||
|
||||
function removeSubflowStatus() {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
if (!subflow.status) {
|
||||
return;
|
||||
}
|
||||
var subflowRemovedLinks = [];
|
||||
RED.nodes.eachLink(function(l) {
|
||||
if (l.target.type == "subflow" && l.target.z == subflow.id && l.target.direction == "status") {
|
||||
subflowRemovedLinks.push(l);
|
||||
}
|
||||
});
|
||||
subflowRemovedLinks.forEach(function(l) { RED.nodes.removeLink(l)});
|
||||
delete subflow.status;
|
||||
|
||||
$("#workspace-subflow-status").prop("checked",!!subflow.status);
|
||||
$("#workspace-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
|
||||
|
||||
return { links: subflowRemovedLinks }
|
||||
}
|
||||
|
||||
function refresh(markChange) {
|
||||
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
refreshToolbar(activeSubflow);
|
||||
@@ -219,12 +279,17 @@ RED.subflow = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshToolbar(activeSubflow) {
|
||||
if (activeSubflow) {
|
||||
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
|
||||
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
|
||||
|
||||
$("#workspace-subflow-output .spinner-value").text(activeSubflow.out.length);
|
||||
|
||||
$("#workspace-subflow-status").prop("checked",!!activeSubflow.status);
|
||||
$("#workspace-subflow-status").parent().parent().toggleClass("active",!!activeSubflow.status);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,22 +297,32 @@ RED.subflow = (function() {
|
||||
var toolbar = $("#workspace-toolbar");
|
||||
toolbar.empty();
|
||||
|
||||
// Edit properties
|
||||
$('<a class="button" id="workspace-subflow-edit" href="#" data-i18n="[append]subflow.editSubflowProperties"><i class="fa fa-pencil"></i> </a>').appendTo(toolbar);
|
||||
|
||||
// Inputs
|
||||
$('<span style="margin-left: 5px;" data-i18n="subflow.input"></span> '+
|
||||
'<div style="display: inline-block;" class="button-group">'+
|
||||
'<a id="workspace-subflow-input-remove" class="button active" href="#">0</a>'+
|
||||
'<a id="workspace-subflow-input-add" class="button" href="#">1</a>'+
|
||||
'</div>').appendTo(toolbar);
|
||||
|
||||
// Outputs
|
||||
$('<span style="margin-left: 5px;" data-i18n="subflow.output"></span> <div id="workspace-subflow-output" style="display: inline-block;" class="button-group spinner-group">'+
|
||||
'<a id="workspace-subflow-output-remove" class="button" href="#"><i class="fa fa-minus"></i></a>'+
|
||||
'<div class="spinner-value">3</div>'+
|
||||
'<a id="workspace-subflow-output-add" class="button" href="#"><i class="fa fa-plus"></i></a>'+
|
||||
'</div>').appendTo(toolbar);
|
||||
|
||||
// Status
|
||||
$('<span class="button-group"><span class="button" style="padding:0"><label for="workspace-subflow-status"><input id="workspace-subflow-status" type="checkbox"> <span data-i18n="subflow.status"></span></label></span></span>').appendTo(toolbar);
|
||||
|
||||
// $('<a class="button disabled" id="workspace-subflow-add-input" href="#" data-i18n="[append]subflow.input"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
|
||||
// $('<a class="button" id="workspace-subflow-add-output" href="#" data-i18n="[append]subflow.output"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
|
||||
|
||||
// Delete
|
||||
$('<a class="button" id="workspace-subflow-delete" href="#" data-i18n="[append]subflow.deleteSubflow"><i class="fa fa-trash"></i> </a>').appendTo(toolbar);
|
||||
|
||||
toolbar.i18n();
|
||||
|
||||
|
||||
@@ -274,6 +349,7 @@ RED.subflow = (function() {
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
});
|
||||
|
||||
$("#workspace-subflow-output-add").click(function(event) {
|
||||
event.preventDefault();
|
||||
addSubflowOutput();
|
||||
@@ -283,6 +359,7 @@ RED.subflow = (function() {
|
||||
event.preventDefault();
|
||||
addSubflowInput();
|
||||
});
|
||||
|
||||
$("#workspace-subflow-input-remove").click(function(event) {
|
||||
event.preventDefault();
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
@@ -307,6 +384,33 @@ RED.subflow = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
$("#workspace-subflow-status").change(function(evt) {
|
||||
if (this.checked) {
|
||||
addSubflowStatus();
|
||||
} else {
|
||||
var currentStatus = activeSubflow.status;
|
||||
var wasChanged = activeSubflow.changed;
|
||||
var result = removeSubflowStatus();
|
||||
if (result) {
|
||||
activeSubflow.changed = true;
|
||||
var wasDirty = RED.nodes.dirty();
|
||||
RED.history.push({
|
||||
t:'delete',
|
||||
links:result.links,
|
||||
changed: wasChanged,
|
||||
dirty:wasDirty,
|
||||
subflow: {
|
||||
id: activeSubflow.id,
|
||||
status: currentStatus
|
||||
}
|
||||
});
|
||||
RED.view.select();
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$("#workspace-subflow-edit").click(function(event) {
|
||||
RED.editor.editSubflow(RED.nodes.subflow(RED.workspaces.active()));
|
||||
event.preventDefault();
|
||||
@@ -328,6 +432,7 @@ RED.subflow = (function() {
|
||||
$("#chart").css({"margin-top": "40px"});
|
||||
$("#workspace-toolbar").show();
|
||||
}
|
||||
|
||||
function hideWorkspaceToolbar() {
|
||||
$("#workspace-toolbar").hide().empty();
|
||||
$("#chart").css({"margin-top": "0"});
|
||||
@@ -373,6 +478,7 @@ RED.subflow = (function() {
|
||||
subflows: [activeSubflow]
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
RED.events.on("workspace:change",function(event) {
|
||||
var activeSubflow = RED.nodes.subflow(event.workspace);
|
||||
@@ -436,6 +542,7 @@ RED.subflow = (function() {
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
function convertToSubflow() {
|
||||
var selection = RED.view.selection();
|
||||
if (!selection.nodes) {
|
||||
@@ -451,7 +558,6 @@ RED.subflow = (function() {
|
||||
var candidateOutputs = [];
|
||||
var candidateInputNodes = {};
|
||||
|
||||
|
||||
var boundingBox = [selection.nodes[0].x,
|
||||
selection.nodes[0].y,
|
||||
selection.nodes[0].x,
|
||||
@@ -467,8 +573,8 @@ RED.subflow = (function() {
|
||||
Math.max(boundingBox[3],n.y)
|
||||
]
|
||||
}
|
||||
var offsetX = snapToGrid(boundingBox[0] - 180);
|
||||
var offsetY = snapToGrid(boundingBox[1] - 60);
|
||||
var offsetX = snapToGrid(boundingBox[0] - 200);
|
||||
var offsetY = snapToGrid(boundingBox[1] - 80);
|
||||
|
||||
|
||||
var center = [
|
||||
@@ -540,7 +646,7 @@ RED.subflow = (function() {
|
||||
}}),
|
||||
out: candidateOutputs.map(function(v,i) { var index = i; return {
|
||||
type:"subflow",
|
||||
direction:"in",
|
||||
direction:"out",
|
||||
x:snapToGrid(v.source.x+(v.source.w/2)+80 - offsetX),
|
||||
y:snapToGrid(v.source.y - offsetY),
|
||||
z:subflowId,
|
||||
@@ -643,8 +749,6 @@ RED.subflow = (function() {
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
init: init,
|
||||
createSubflow: createSubflow,
|
||||
@@ -652,6 +756,7 @@ RED.subflow = (function() {
|
||||
removeSubflow: removeSubflow,
|
||||
refresh: refresh,
|
||||
removeInput: removeSubflowInput,
|
||||
removeOutput: removeSubflowOutput
|
||||
removeOutput: removeSubflowOutput,
|
||||
removeStatus: removeSubflowStatus
|
||||
}
|
||||
})();
|
||||
|
@@ -294,7 +294,7 @@ RED.sidebar.info = (function() {
|
||||
if (node.type !== 'tab') {
|
||||
if (m) {
|
||||
$('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody);
|
||||
$('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+subflowNode.name+'</span></td></tr>').appendTo(tableBody);
|
||||
$('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+RED.utils.sanitize(subflowNode.name)+'</span></td></tr>').appendTo(tableBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -192,6 +192,14 @@ RED.utils = (function() {
|
||||
format = 'hex'
|
||||
}
|
||||
} else if (format === 'dateMS' || format == 'dateS') {
|
||||
if ((obj.toString().length===13) && (obj<=2147483647000)) {
|
||||
format = 'dateML';
|
||||
} else if ((obj.toString().length===10) && (obj<=2147483647)) {
|
||||
format = 'dateL';
|
||||
} else {
|
||||
format = 'hex'
|
||||
}
|
||||
} else if (format === 'dateML' || format == 'dateL') {
|
||||
format = 'hex';
|
||||
} else {
|
||||
format = 'dec';
|
||||
@@ -210,6 +218,12 @@ RED.utils = (function() {
|
||||
element.text((new Date(obj)).toISOString());
|
||||
} else if (format === 'dateS') {
|
||||
element.text((new Date(obj*1000)).toISOString());
|
||||
} else if (format === 'dateML') {
|
||||
var dd = new Date(obj);
|
||||
element.text(dd.toLocaleString() + " [UTC" + ( dd.getTimezoneOffset()/-60 <=0?"":"+" ) + dd.getTimezoneOffset()/-60 +"]");
|
||||
} else if (format === 'dateL') {
|
||||
var ddl = new Date(obj*1000);
|
||||
element.text(ddl.toLocaleString() + " [UTC" + ( ddl.getTimezoneOffset()/-60 <=0?"":"+" ) + ddl.getTimezoneOffset()/-60 +"]");
|
||||
} else if (format === 'hex') {
|
||||
element.text("0x"+(obj).toString(16));
|
||||
}
|
||||
@@ -953,6 +967,7 @@ RED.utils = (function() {
|
||||
addSpinnerOverlay: addSpinnerOverlay,
|
||||
decodeObject: decodeObject,
|
||||
parseContextKey: parseContextKey,
|
||||
createIconElement: createIconElement
|
||||
createIconElement: createIconElement,
|
||||
sanitize: sanitize
|
||||
}
|
||||
})();
|
||||
|
104
packages/node_modules/@node-red/editor-client/src/js/ui/view.js
vendored
Normal file → Executable file
104
packages/node_modules/@node-red/editor-client/src/js/ui/view.js
vendored
Normal file → Executable file
@@ -1261,6 +1261,13 @@ RED.view = (function() {
|
||||
moving_set.push({n:n});
|
||||
}
|
||||
});
|
||||
if (activeSubflow.status) {
|
||||
activeSubflow.status.selected = (activeSubflow.status.x > x && activeSubflow.status.x < x2 && activeSubflow.status.y > y && activeSubflow.status.y < y2);
|
||||
if (activeSubflow.status.selected) {
|
||||
activeSubflow.status.dirty = true;
|
||||
moving_set.push({n:activeSubflow.status});
|
||||
}
|
||||
}
|
||||
}
|
||||
updateSelection();
|
||||
lasso.remove();
|
||||
@@ -1367,6 +1374,13 @@ RED.view = (function() {
|
||||
moving_set.push({n:n});
|
||||
}
|
||||
});
|
||||
if (activeSubflow.status) {
|
||||
if (!activeSubflow.status.selected) {
|
||||
activeSubflow.status.selected = true;
|
||||
activeSubflow.status.dirty = true;
|
||||
moving_set.push({n:activeSubflow.status});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selected_link = null;
|
||||
@@ -1552,6 +1566,7 @@ RED.view = (function() {
|
||||
var removedLinks = [];
|
||||
var removedSubflowOutputs = [];
|
||||
var removedSubflowInputs = [];
|
||||
var removedSubflowStatus = undefined;
|
||||
var subflowInstances = [];
|
||||
|
||||
var startDirty = RED.nodes.dirty();
|
||||
@@ -1573,6 +1588,8 @@ RED.view = (function() {
|
||||
removedSubflowOutputs.push(node);
|
||||
} else if (node.direction === "in") {
|
||||
removedSubflowInputs.push(node);
|
||||
} else if (node.direction === "status") {
|
||||
removedSubflowStatus = node;
|
||||
}
|
||||
node.dirty = true;
|
||||
}
|
||||
@@ -1590,12 +1607,19 @@ RED.view = (function() {
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
}
|
||||
}
|
||||
if (removedSubflowStatus) {
|
||||
result = RED.subflow.removeStatus();
|
||||
if (result) {
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
}
|
||||
}
|
||||
|
||||
var instances = RED.subflow.refresh(true);
|
||||
if (instances) {
|
||||
subflowInstances = instances.instances;
|
||||
}
|
||||
moving_set = [];
|
||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0) {
|
||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus) {
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
@@ -1651,10 +1675,14 @@ RED.view = (function() {
|
||||
subflowOutputs:removedSubflowOutputs,
|
||||
subflowInputs:removedSubflowInputs,
|
||||
subflow: {
|
||||
id: activeSubflow?activeSubflow.id:undefined,
|
||||
instances: subflowInstances
|
||||
},
|
||||
dirty:startDirty
|
||||
};
|
||||
if (removedSubflowStatus) {
|
||||
historyEvent.subflow.status = removedSubflowStatus;
|
||||
}
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
@@ -2420,6 +2448,49 @@ RED.view = (function() {
|
||||
|
||||
inGroup.append("svg:text").attr("class","port_label").attr("x",18).attr("y",20).style("font-size","10px").text("input");
|
||||
|
||||
var subflowStatus = nodeLayer.selectAll(".subflowstatus").data(activeSubflow.status?[activeSubflow.status]:[],function(d,i){ return d.id;});
|
||||
subflowStatus.exit().remove();
|
||||
|
||||
var statusGroup = subflowStatus.enter().insert("svg:g").attr("class","node subflowstatus").attr("transform",function(d) { return "translate("+(d.x-20)+","+(d.y-20)+")"});
|
||||
statusGroup.each(function(d,i) {
|
||||
d.w=40;
|
||||
d.h=40;
|
||||
});
|
||||
statusGroup.append("rect").attr("class","subflowport").attr("rx",8).attr("ry",8).attr("width",40).attr("height",40)
|
||||
// TODO: This is exactly the same set of handlers used for regular nodes - DRY
|
||||
.on("mouseup",nodeMouseUp)
|
||||
.on("mousedown",nodeMouseDown)
|
||||
.on("touchstart",function(d) {
|
||||
var obj = d3.select(this);
|
||||
var touch0 = d3.event.touches.item(0);
|
||||
var pos = [touch0.pageX,touch0.pageY];
|
||||
startTouchCenter = [touch0.pageX,touch0.pageY];
|
||||
startTouchDistance = 0;
|
||||
touchStartTime = setTimeout(function() {
|
||||
showTouchMenu(obj,pos);
|
||||
},touchLongPressTimeout);
|
||||
nodeMouseDown.call(this,d)
|
||||
})
|
||||
.on("touchend", function(d) {
|
||||
clearTimeout(touchStartTime);
|
||||
touchStartTime = null;
|
||||
if (RED.touch.radialMenu.active()) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
nodeMouseUp.call(this,d);
|
||||
});
|
||||
|
||||
statusGroup.append("g").attr('transform','translate(-5,15)').append("rect").attr("class","port").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
|
||||
.on("mousedown", function(d,i){portMouseDown(d,PORT_TYPE_INPUT,0);} )
|
||||
.on("touchstart", function(d,i){portMouseDown(d,PORT_TYPE_INPUT,0);} )
|
||||
.on("mouseup", function(d,i){portMouseUp(d,PORT_TYPE_INPUT,0);})
|
||||
.on("touchend",function(d,i){portMouseUp(d,PORT_TYPE_INPUT,0);} )
|
||||
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_INPUT,0);})
|
||||
.on("mouseout",function(d){portMouseOut(d3.select(this),d,PORT_TYPE_INPUT,0);});
|
||||
|
||||
statusGroup.append("svg:text").attr("class","port_label").attr("x",22).attr("y",20).style("font-size","10px").text("status");
|
||||
|
||||
subflowOutputs.each(function(d,i) {
|
||||
if (d.dirty) {
|
||||
var output = d3.select(this);
|
||||
@@ -2439,9 +2510,22 @@ RED.view = (function() {
|
||||
d.dirty = false;
|
||||
}
|
||||
});
|
||||
subflowStatus.each(function(d,i) {
|
||||
if (d.dirty) {
|
||||
var output = d3.select(this);
|
||||
output.selectAll(".subflowport").classed("node_selected",function(d) { return d.selected; })
|
||||
output.selectAll(".port_index").text(function(d){ return d.i+1});
|
||||
output.attr("transform", function(d) { return "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")"; });
|
||||
dirtyNodes[d.id] = d;
|
||||
d.dirty = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
} else {
|
||||
nodeLayer.selectAll(".subflowoutput").remove();
|
||||
nodeLayer.selectAll(".subflowinput").remove();
|
||||
nodeLayer.selectAll(".subflowstatus").remove();
|
||||
}
|
||||
|
||||
var node = nodeLayer.selectAll(".nodegroup").data(activeNodes,function(d){return d.id});
|
||||
@@ -2672,7 +2756,7 @@ RED.view = (function() {
|
||||
.attr("rx",2).attr("ry",2).attr("stroke-width","3");
|
||||
var statusLabel = status.append("svg:text")
|
||||
.attr("class","node_status_label")
|
||||
.attr("x",20).attr("y",9);
|
||||
.attr("x",20).attr("y",10);
|
||||
|
||||
//node.append("circle").attr({"class":"centerDot","cx":0,"cy":0,"r":5});
|
||||
|
||||
@@ -2717,6 +2801,15 @@ RED.view = (function() {
|
||||
//thisNode.selectAll(".node-gradient-top").attr("width",function(d){return d.w});
|
||||
//thisNode.selectAll(".node-gradient-bottom").attr("width",function(d){return d.w}).attr("y",function(d){return d.h-30});
|
||||
|
||||
if ((!d._def.align && d.inputs !== 0 && d.outputs === 0) || "right" === d._def.align) {
|
||||
thisNode.selectAll(".node_icon_group").classed("node_icon_group_right", true);
|
||||
thisNode.selectAll(".node_label").classed("node_label_right", true).attr("text-anchor", "end");
|
||||
} else {
|
||||
thisNode.selectAll(".node_icon_group").classed("node_icon_group_right", false);
|
||||
thisNode.selectAll(".node_label").classed("node_label_right", false).attr("text-anchor", "start");
|
||||
}
|
||||
thisNode.selectAll(".node_icon_group").attr("transform", function (d) { return "translate(0, 0)"; });
|
||||
thisNode.selectAll(".node_label").attr("x", function (d) { return 38; });
|
||||
thisNode.selectAll(".node_icon_group_right").attr("transform", function(d){return "translate("+(d.w-30)+",0)"});
|
||||
thisNode.selectAll(".node_label_right").attr("x", function(d){return d.w-38});
|
||||
//thisNode.selectAll(".node_icon_right").attr("x",function(d){return d.w-d3.select(this).attr("width")-1-(d.outputs>0?5:0);});
|
||||
@@ -2867,7 +2960,9 @@ RED.view = (function() {
|
||||
|
||||
thisNode.selectAll(".node_icon").attr("y",function(d){return (d.h-d3.select(this).attr("height"))/2;});
|
||||
thisNode.selectAll(".node_icon_shade").attr("height",function(d){return d.h;});
|
||||
thisNode.selectAll(".node_icon_shade_border").attr("d",function(d){ return "M "+(("right" == d._def.align) ?0:30)+" 1 l 0 "+(d.h-2)});
|
||||
thisNode.selectAll(".node_icon_shade_border").attr("d", function (d) {
|
||||
return "M " + (((!d._def.align && d.inputs !== 0 && d.outputs === 0) || "right" === d._def.align) ? 0 : 30) + " 1 l 0 " + (d.h - 2);
|
||||
});
|
||||
thisNode.selectAll(".fa-lg").attr("y",function(d){return (d.h+13)/2;});
|
||||
|
||||
thisNode.selectAll(".node_button").attr("opacity",function(d) {
|
||||
@@ -2924,11 +3019,12 @@ RED.view = (function() {
|
||||
if (!showStatus || !d.status) {
|
||||
thisNode.selectAll(".node_status_group").style("display","none");
|
||||
} else {
|
||||
thisNode.selectAll(".node_status_group").style("display","inline").attr("transform","translate(3,"+(d.h+3)+")");
|
||||
var fill = status_colours[d.status.fill]; // Only allow our colours for now
|
||||
if (d.status.shape == null && fill == null) {
|
||||
thisNode.selectAll(".node_status").style("display","none");
|
||||
thisNode.selectAll(".node_status_group").style("display","inline").attr("transform","translate(-14,"+(d.h+3)+")");
|
||||
} else {
|
||||
thisNode.selectAll(".node_status_group").style("display","inline").attr("transform","translate(3,"+(d.h+3)+")");
|
||||
var style;
|
||||
if (d.status.shape == null || d.status.shape == "dot") {
|
||||
style = {
|
||||
|
@@ -309,7 +309,9 @@ RED.workspaces = (function() {
|
||||
minimumActiveTabWidth: 150,
|
||||
scrollable: true,
|
||||
addButton: "core:add-flow",
|
||||
addButtonCaption: RED._("workspace.addFlow")
|
||||
addButtonCaption: RED._("workspace.addFlow"),
|
||||
searchButton: "core:list-flows",
|
||||
searchButtonCaption: RED._("workspace.listFlows")
|
||||
});
|
||||
workspaceTabCount = 0;
|
||||
}
|
||||
@@ -343,6 +345,10 @@ RED.workspaces = (function() {
|
||||
RED.actions.add("core:edit-flow",editWorkspace);
|
||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||
|
||||
RED.actions.add("core:list-flows",function() {
|
||||
RED.actions.invoke("core:search","type:tab ");
|
||||
})
|
||||
|
||||
hideWorkspace();
|
||||
}
|
||||
|
||||
|
@@ -60,7 +60,7 @@
|
||||
.project-settings-tab-pane {
|
||||
& * .projects-edit-form-sublabel {
|
||||
margin-right: 50px;
|
||||
margin-top: -10px;
|
||||
margin-top: -10px !important;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
@@ -71,6 +71,7 @@ body {
|
||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
padding-top: 100px;
|
||||
background: $background-color;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
#main-container {
|
||||
@@ -135,3 +136,16 @@ pre code {
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0 0 0 15px;
|
||||
margin: 0 0 20px;
|
||||
border-left: 4px solid #ddd;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
font-weight: inherit;
|
||||
line-height: 1.25;
|
||||
color: #777;
|
||||
}
|
||||
}
|
||||
|
@@ -111,6 +111,7 @@
|
||||
font-weight: bold;
|
||||
.red-ui-tabs-badge-selected {
|
||||
display: inline;
|
||||
background: white;
|
||||
}
|
||||
.red-ui-tabs-badge-changed {
|
||||
display: none;
|
||||
@@ -133,6 +134,10 @@
|
||||
&.red-ui-tabs-add.red-ui-tabs-scrollable {
|
||||
padding-right: 59px;
|
||||
}
|
||||
&.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-scrollable {
|
||||
padding-right: 95px;
|
||||
}
|
||||
|
||||
&.red-ui-tabs-collapsible {
|
||||
li:not(.active) {
|
||||
display: none;
|
||||
@@ -285,6 +290,14 @@
|
||||
right: 38px;
|
||||
}
|
||||
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search .red-ui-tab-scroll-right {
|
||||
right: 76px;
|
||||
}
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search .red-ui-tabs-add {
|
||||
right: 38px;
|
||||
}
|
||||
|
||||
|
||||
img.red-ui-tab-icon {
|
||||
margin-left: -8px;
|
||||
margin-right: 3px;
|
||||
|
@@ -33,6 +33,15 @@
|
||||
transition: right 0.2s ease;
|
||||
overflow: hidden;
|
||||
|
||||
label {
|
||||
padding: 1px 8px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
margin: 0 3px 0 0 ;
|
||||
padding: 0;
|
||||
}
|
||||
.button {
|
||||
@include workspace-button;
|
||||
margin-right: 10px;
|
||||
|
@@ -172,17 +172,23 @@
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
outputLabels: function(index) {
|
||||
var labels = { str:"string", num:"number", bool:"boolean", json:"object", flow:"flow context", global:"global context" };
|
||||
var lab = labels[this.payloadType] || this.payloadType;
|
||||
if (lab === "object") {
|
||||
var lab = this.payloadType;
|
||||
if (lab === "json") {
|
||||
try {
|
||||
lab = typeof JSON.parse(this.payload);
|
||||
if (lab === "object") {
|
||||
if (Array.isArray(JSON.parse(this.payload))) { lab = "Array"; }
|
||||
}
|
||||
} catch(e) { lab = "Invalid JSON Object"; }
|
||||
} catch(e) {
|
||||
return this._("inject.label.invalid"); }
|
||||
}
|
||||
return lab; },
|
||||
var name = "inject.label."+lab;
|
||||
var label = this._(name);
|
||||
if (name !== label) {
|
||||
return label;
|
||||
}
|
||||
return lab;
|
||||
},
|
||||
label: function() {
|
||||
var suffix = "";
|
||||
// if fire once then add small indication
|
||||
|
@@ -7,6 +7,10 @@
|
||||
<option value="target" data-i18n="catch.scope.selected"></options>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-uncaught-row">
|
||||
<input type="checkbox" id="node-input-uncaught" style="display: inline-block; width: auto; vertical-align: top; margin-left: 30px; margin-right: 5px;">
|
||||
<label for="node-input-uncaught" style="width: auto" data-i18n="catch.label.uncaught"></label>
|
||||
</div>
|
||||
<div class="form-row node-input-target-row" style="display: none;">
|
||||
<div id="node-input-catch-target-container-div" style="min-height: 100px;position: relative; box-sizing: border-box; border-radius: 2px; height: 180px; border: 1px solid #ccc;overflow:hidden; ">
|
||||
<div style="box-sizing: border-box; line-height: 20px; font-size: 0.8em; border-bottom: 1px solid #ddd; height: 20px;">
|
||||
@@ -64,13 +68,20 @@
|
||||
color:"#e49191",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
scope: {value:null}
|
||||
scope: {value:null},
|
||||
uncaught: {value:false}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "alert.png",
|
||||
label: function() {
|
||||
return this.name||(this.scope?this._("catch.catchNodes",{number:this.scope.length}):this._("catch.catch"));
|
||||
if (this.name) {
|
||||
return this.name;
|
||||
}
|
||||
if (this.scope) {
|
||||
return this._("catch.catchNodes",{number:this.scope.length});
|
||||
}
|
||||
return this.uncaught?this._("catch.catchUncaught"):this._("catch.catch")
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
@@ -210,8 +221,10 @@
|
||||
if (scope === "target") {
|
||||
createNodeList();
|
||||
$(".node-input-target-row").show();
|
||||
$(".node-input-uncaught-row").hide();
|
||||
} else {
|
||||
$(".node-input-target-row").hide();
|
||||
$(".node-input-uncaught-row").show();
|
||||
}
|
||||
node.resize();
|
||||
});
|
||||
@@ -227,6 +240,7 @@
|
||||
if (scope === 'all') {
|
||||
this.scope = null;
|
||||
} else {
|
||||
$("#node-input-uncaught").prop("checked",false);
|
||||
var node = this;
|
||||
node.scope = [];
|
||||
$(".node-input-target-node-checkbox").each(function(n) {
|
||||
|
@@ -21,6 +21,7 @@ module.exports = function(RED) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
this.scope = n.scope;
|
||||
this.uncaught = n.uncaught;
|
||||
this.on("input",function(msg) {
|
||||
this.send(msg);
|
||||
});
|
||||
|
@@ -54,7 +54,7 @@
|
||||
flowMap[activeSubflow.id] = {
|
||||
id: activeSubflow.id,
|
||||
class: 'palette-header',
|
||||
label: "Subflow : "+(activeSubflow.name || activeSubflow.id),
|
||||
label: "Subflow : "+(activeSubflow.name || activeSubflow.id)+(node.z===ws.id ? " *":""),
|
||||
expanded: true,
|
||||
children: []
|
||||
};
|
||||
@@ -64,8 +64,8 @@
|
||||
flowMap[ws.id] = {
|
||||
id: ws.id,
|
||||
class: 'palette-header',
|
||||
label: (ws.label || ws.id),
|
||||
expanded: ws.id === node.z,
|
||||
label: (ws.label || ws.id)+(node.z===ws.id ? " *":""),
|
||||
expanded: true,
|
||||
children: []
|
||||
}
|
||||
flows.push(flowMap[ws.id])
|
||||
@@ -88,7 +88,10 @@
|
||||
}
|
||||
});
|
||||
flows = flows.filter(function(f) { return f.children.length > 0 })
|
||||
treeList.treeList('data',flows)
|
||||
treeList.treeList('data',flows);
|
||||
setTimeout(function() {
|
||||
treeList.treeList('show',node.z);
|
||||
},100);
|
||||
}
|
||||
|
||||
function resizeNodeList() {
|
||||
|
@@ -66,7 +66,13 @@
|
||||
},
|
||||
inputs:1,
|
||||
outputs:3,
|
||||
outputLabels: ["stdout","stderr","return code"],
|
||||
outputLabels: function(i) {
|
||||
return [
|
||||
this._("exec.label.stdout"),
|
||||
this._("exec.label.stderr"),
|
||||
this._("exec.label.retcode")
|
||||
][i];
|
||||
},
|
||||
icon: "arrow-in.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
|
@@ -158,9 +158,8 @@ module.exports = function(RED) {
|
||||
},
|
||||
env: {
|
||||
get: function(envVar) {
|
||||
// For now, just return the env var. This will eventually
|
||||
// also return project settings and subflow instance properties
|
||||
return process.env[envVar]
|
||||
var flow = node._flow;
|
||||
return flow.getSetting(envVar);
|
||||
}
|
||||
},
|
||||
setTimeout: function () {
|
||||
|
@@ -449,7 +449,7 @@ RED.debug = (function() {
|
||||
var metaRow = $('<div class="debug-message-meta"></div>').appendTo(msg);
|
||||
$('<span class="debug-message-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
|
||||
if (sourceNode) {
|
||||
$('<a>',{href:"#",class:"debug-message-name"}).html('node: '+(sourceNode.name||sourceNode.id))
|
||||
$('<a>',{href:"#",class:"debug-message-name"}).text('node: '+(sourceNode.name||sourceNode.id))
|
||||
.appendTo(metaRow)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
@@ -34,6 +34,7 @@
|
||||
<option value="auto" data-i18n="mqtt.output.auto"></option>
|
||||
<option value="buffer" data-i18n="mqtt.output.buffer"></option>
|
||||
<option value="utf8" data-i18n="mqtt.output.string"></option>
|
||||
<option value="json" data-i18n="mqtt.output.json"></option>
|
||||
<option value="base64" data-i18n="mqtt.output.base64"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
@@ -399,16 +399,23 @@ module.exports = function(RED) {
|
||||
if (this.topic) {
|
||||
node.brokerConn.register(this);
|
||||
this.brokerConn.subscribe(this.topic,this.qos,function(topic,payload,packet) {
|
||||
if (node.datatype =="buffer") {
|
||||
if (node.datatype === "buffer") {
|
||||
// payload = payload;
|
||||
} else if (node.datatype =="base64") {
|
||||
} else if (node.datatype === "base64") {
|
||||
payload = payload.toString('base64');
|
||||
} else if (node.datatype =="utf8") {
|
||||
} else if (node.datatype === "utf8") {
|
||||
payload = payload.toString('utf8');
|
||||
} else if (node.datatype === "json") {
|
||||
if (isUtf8(payload)) {
|
||||
payload = payload.toString();
|
||||
try { payload = JSON.parse(payload); }
|
||||
catch(e) { node.error(RED._("mqtt.errors.invalid-json-parse"),{payload:payload, topic:topic, qos:packet.qos, retain:packet.retain}); return; }
|
||||
}
|
||||
else { node.error((RED._("mqtt.errors.invalid-json-string")),{payload:payload, topic:topic, qos:packet.qos, retain:packet.retain}); return; }
|
||||
} else {
|
||||
if (isUtf8(payload)) { payload = payload.toString(); }
|
||||
}
|
||||
var msg = {topic:topic,payload:payload, qos: packet.qos, retain: packet.retain};
|
||||
var msg = {topic:topic, payload:payload, qos:packet.qos, retain:packet.retain};
|
||||
if ((node.brokerConn.broker === "localhost")||(node.brokerConn.broker === "127.0.0.1")) {
|
||||
msg._topic = topic;
|
||||
}
|
||||
|
@@ -25,11 +25,17 @@
|
||||
<option value="use" data-i18n="httpin.setby"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
||||
<input id="node-input-url" type="text" placeholder="http://">
|
||||
</div>
|
||||
|
||||
<div class="form-row node-input-paytoqs-row">
|
||||
<input type="checkbox" id="node-input-paytoqs" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-paytoqs" style="width: auto" data-i18n="httpin.label.paytoqs"></label>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
|
||||
@@ -43,11 +49,19 @@
|
||||
<label for="node-input-useAuth" style="width: 70%;"><span data-i18n="httpin.basicauth"></span></label>
|
||||
<div style="margin-left: 20px" class="node-input-useAuth-row hide">
|
||||
<div class="form-row">
|
||||
<label for="node-input-authType"><i class="fa fa-user-secret "></i> <span data-i18n="httpin.label.authType"></span></label>
|
||||
<select type="text" id="node-input-authType" style="width:70%;">
|
||||
<option value="basic" data-i18n="httpin.basic"></option>
|
||||
<option value="digest" data-i18n="httpin.digest"></option>
|
||||
<option value="bearer" data-i18n="httpin.bearer"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-basic-row">
|
||||
<label for="node-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
|
||||
<input type="text" id="node-input-user">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
|
||||
<label for="node-input-password"> <i class="fa fa-lock"></i> <span data-i18n="common.label.password" id="node-span-password"></span><span data-i18n="httpin.label.bearerToken" id="node-span-token" style="display:none"></span></label>
|
||||
<input type="password" id="node-input-password">
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,9 +98,11 @@
|
||||
name: {value:""},
|
||||
method:{value:"GET"},
|
||||
ret: {value:"txt"},
|
||||
paytoqs: {value: false},
|
||||
url:{value:"",validate:function(v) { return (v.trim().length === 0) || (v.indexOf("://") === -1) || (v.trim().indexOf("http") === 0)} },
|
||||
tls: {type:"tls-config",required: false},
|
||||
proxy: {type:"http proxy",required: false}
|
||||
proxy: {type:"http proxy",required: false},
|
||||
authType: {value: "basic"}
|
||||
},
|
||||
credentials: {
|
||||
user: {type:"text"},
|
||||
@@ -95,7 +111,11 @@
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function(i) {
|
||||
return ({txt:"UTF8 string", bin:"binary buffer", obj:"parsed JSON object"}[this.ret]);
|
||||
return ({
|
||||
txt: this._("httpin.label.utf8String"),
|
||||
bin: this._("httpin.label.binaryBuffer"),
|
||||
obj: this._("httpin.label.jsonObject")
|
||||
}[this.ret]);
|
||||
},
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
@@ -108,12 +128,36 @@
|
||||
$("#node-input-useAuth").change(function() {
|
||||
if ($(this).is(":checked")) {
|
||||
$(".node-input-useAuth-row").show();
|
||||
// Nodes (< version 0.20.x) with credentials but without authentication type, need type 'basic'
|
||||
if (!$('#node-input-authType').val()) {
|
||||
$('#node-input-authType').val('basic');
|
||||
}
|
||||
} else {
|
||||
$(".node-input-useAuth-row").hide();
|
||||
$('#node-input-authType').val('');
|
||||
$('#node-input-user').val('');
|
||||
$('#node-input-password').val('');
|
||||
}
|
||||
});
|
||||
$("#node-input-authType").change(function() {
|
||||
if ($(this).val() == "basic" || $(this).val() == "digest") {
|
||||
$(".node-input-basic-row").show();
|
||||
$('#node-span-password').show();
|
||||
$('#node-span-token').hide();
|
||||
} else if ($(this).val() == "bearer") {
|
||||
$(".node-input-basic-row").hide();
|
||||
$('#node-span-password').hide();
|
||||
$('#node-span-token').show();
|
||||
$('#node-input-user').val('');
|
||||
}
|
||||
});
|
||||
$("#node-input-method").change(function() {
|
||||
if ($(this).val() == "GET") {
|
||||
$(".node-input-paytoqs-row").show();
|
||||
} else {
|
||||
$(".node-input-paytoqs-row").hide();
|
||||
}
|
||||
});
|
||||
if (this.credentials.user || this.credentials.has_password) {
|
||||
$('#node-input-useAuth').prop('checked', true);
|
||||
} else {
|
||||
|
@@ -28,10 +28,12 @@ module.exports = function(RED) {
|
||||
var nodeUrl = n.url;
|
||||
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
|
||||
var nodeMethod = n.method || "GET";
|
||||
var paytoqs = n.paytoqs;
|
||||
if (n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
}
|
||||
this.ret = n.ret || "txt";
|
||||
this.authType = n.authType || "basic";
|
||||
if (RED.settings.httpRequestTimeout) { this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000; }
|
||||
else { this.reqTimeout = 120000; }
|
||||
|
||||
@@ -148,16 +150,9 @@ module.exports = function(RED) {
|
||||
};
|
||||
}
|
||||
if (opts.headers.hasOwnProperty('cookie')) {
|
||||
var cookies = cookie.parse(opts.headers.cookie);
|
||||
var cookies = cookie.parse(opts.headers.cookie, {decode:String});
|
||||
for (var name in cookies) {
|
||||
if (cookies.hasOwnProperty(name)) {
|
||||
if (cookies[name] === null) {
|
||||
// This case clears a cookie for HTTP In/Response nodes.
|
||||
// Ignore for this node.
|
||||
} else {
|
||||
opts.jar.setCookie(name + '=' + cookies[name], url);
|
||||
}
|
||||
}
|
||||
opts.jar.setCookie(cookie.serialize(name, cookies[name], {encode:String}), url);
|
||||
}
|
||||
delete opts.headers.cookie;
|
||||
}
|
||||
@@ -168,45 +163,92 @@ module.exports = function(RED) {
|
||||
// This case clears a cookie for HTTP In/Response nodes.
|
||||
// Ignore for this node.
|
||||
} else if (typeof msg.cookies[name] === 'object') {
|
||||
opts.jar.setCookie(name + '=' + msg.cookies[name].value, url);
|
||||
if(msg.cookies[name].encode === false){
|
||||
// If the encode option is false, the value is not encoded.
|
||||
opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value, {encode: String}), url);
|
||||
} else {
|
||||
// The value is encoded by encodeURIComponent().
|
||||
opts.jar.setCookie(cookie.serialize(name, msg.cookies[name].value), url);
|
||||
}
|
||||
} else {
|
||||
opts.jar.setCookie(name + '=' + msg.cookies[name], url);
|
||||
opts.jar.setCookie(cookie.serialize(name, msg.cookies[name]), url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.credentials && this.credentials.user) {
|
||||
opts.auth = {
|
||||
user: this.credentials.user,
|
||||
pass: this.credentials.password||""
|
||||
};
|
||||
if (this.credentials) {
|
||||
if (this.authType === "basic") {
|
||||
if (this.credentials.user) {
|
||||
opts.auth = {
|
||||
user: this.credentials.user,
|
||||
pass: this.credentials.password || ""
|
||||
};
|
||||
}
|
||||
} else if (this.authType === "digest") {
|
||||
if (this.credentials.user) {
|
||||
// The first request will be sent without auth information. Based on the 401 response, the library can determine
|
||||
// which auth type is required by the server. Then the request is resubmitted with the appropriate auth header.
|
||||
opts.auth = {
|
||||
user: this.credentials.user,
|
||||
pass: this.credentials.password || "",
|
||||
sendImmediately: false
|
||||
};
|
||||
}
|
||||
} else if (this.authType === "bearer") {
|
||||
opts.auth = {
|
||||
bearer: this.credentials.password || ""
|
||||
};
|
||||
}
|
||||
}
|
||||
var payload = null;
|
||||
|
||||
if (method !== 'GET' && method !== 'HEAD' && typeof msg.payload !== "undefined") {
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
payload = msg.payload;
|
||||
} else if (typeof msg.payload == "number") {
|
||||
payload = msg.payload+"";
|
||||
if (opts.headers['content-type'] == 'multipart/form-data' && typeof payload === "object") {
|
||||
opts.formData = msg.payload;
|
||||
} else {
|
||||
if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
|
||||
payload = querystring.stringify(msg.payload);
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
payload = msg.payload;
|
||||
} else if (typeof msg.payload == "number") {
|
||||
payload = msg.payload+"";
|
||||
} else {
|
||||
payload = JSON.stringify(msg.payload);
|
||||
if (opts.headers['content-type'] == null) {
|
||||
opts.headers[ctSet] = "application/json";
|
||||
if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
|
||||
payload = querystring.stringify(msg.payload);
|
||||
} else {
|
||||
payload = JSON.stringify(msg.payload);
|
||||
if (opts.headers['content-type'] == null) {
|
||||
opts.headers[ctSet] = "application/json";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts.headers['content-length'] == null) {
|
||||
if (Buffer.isBuffer(payload)) {
|
||||
opts.headers[clSet] = payload.length;
|
||||
} else {
|
||||
opts.headers[clSet] = Buffer.byteLength(payload);
|
||||
if (opts.headers['content-length'] == null) {
|
||||
if (Buffer.isBuffer(payload)) {
|
||||
opts.headers[clSet] = payload.length;
|
||||
} else {
|
||||
opts.headers[clSet] = Buffer.byteLength(payload);
|
||||
}
|
||||
}
|
||||
opts.body = payload;
|
||||
}
|
||||
opts.body = payload;
|
||||
}
|
||||
|
||||
if (method == 'GET' && typeof msg.payload !== "undefined" && paytoqs) {
|
||||
if (typeof msg.payload === "object") {
|
||||
try {
|
||||
if (opts.url.indexOf("?") !== -1) {
|
||||
opts.url += (opts.url.endsWith("?")?"":"&") + querystring.stringify(msg.payload);
|
||||
} else {
|
||||
opts.url += "?" + querystring.stringify(msg.payload);
|
||||
}
|
||||
} catch(err) {
|
||||
node.error(RED._("httpin.errors.invalid-payload"),msg);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
node.error(RED._("httpin.errors.invalid-payload"),msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// revert to user supplied Capitalisation if needed.
|
||||
if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) {
|
||||
opts.headers[ctSet] = opts.headers['content-type'];
|
||||
|
@@ -72,19 +72,19 @@ module.exports = function(RED) {
|
||||
var id = (1+Math.random()*4294967295).toString(16);
|
||||
if (node.isServer) {
|
||||
node._clients[id] = socket;
|
||||
node.emit('opened',Object.keys(node._clients).length);
|
||||
node.emit('opened',{count:Object.keys(node._clients).length,id:id});
|
||||
}
|
||||
socket.on('open',function() {
|
||||
if (!node.isServer) {
|
||||
node.emit('opened','');
|
||||
node.emit('opened',{count:'',id:id});
|
||||
}
|
||||
});
|
||||
socket.on('close',function() {
|
||||
if (node.isServer) {
|
||||
delete node._clients[id];
|
||||
node.emit('closed',Object.keys(node._clients).length);
|
||||
node.emit('closed',{count:Object.keys(node._clients).length,id:id});
|
||||
} else {
|
||||
node.emit('closed');
|
||||
node.emit('closed',{count:'',id:id});
|
||||
}
|
||||
if (!node.closing && !node.isServer) {
|
||||
clearTimeout(node.tout);
|
||||
@@ -95,7 +95,7 @@ module.exports = function(RED) {
|
||||
node.handleEvent(id,socket,'message',data,flags);
|
||||
});
|
||||
socket.on('error', function(err) {
|
||||
node.emit('erro');
|
||||
node.emit('erro',{err:err,id:id});
|
||||
if (!node.closing && !node.isServer) {
|
||||
clearTimeout(node.tout);
|
||||
node.tout = setTimeout(function() { startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ?
|
||||
@@ -230,14 +230,30 @@ module.exports = function(RED) {
|
||||
if (this.serverConfig) {
|
||||
this.serverConfig.registerInputNode(this);
|
||||
// TODO: nls
|
||||
this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); });
|
||||
this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"common.status.error"}); });
|
||||
this.serverConfig.on('closed', function(n) {
|
||||
if (n > 0) {
|
||||
node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})});
|
||||
this.serverConfig.on('opened', function(event) {
|
||||
node.status({
|
||||
fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count}),
|
||||
event:"connect",
|
||||
_session: {type:"websocket",id:event.id}
|
||||
});
|
||||
});
|
||||
this.serverConfig.on('erro', function(event) {
|
||||
node.status({
|
||||
fill:"red",shape:"ring",text:"common.status.error",
|
||||
event:"error",
|
||||
_session: {type:"websocket",id:event.id}
|
||||
});
|
||||
});
|
||||
this.serverConfig.on('closed', function(event) {
|
||||
var status;
|
||||
if (event.count > 0) {
|
||||
status = {fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count})};
|
||||
} else {
|
||||
node.status({fill:"red",shape:"ring",text:"common.status.disconnected"});
|
||||
status = {fill:"red",shape:"ring",text:"common.status.disconnected"};
|
||||
}
|
||||
status.event = "disconnect";
|
||||
status._session = {type:"websocket",id:event.id}
|
||||
node.status(status);
|
||||
});
|
||||
} else {
|
||||
this.error(RED._("websocket.errors.missing-conf"));
|
||||
@@ -261,11 +277,30 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
// TODO: nls
|
||||
this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); });
|
||||
this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"common.status.error"}); });
|
||||
this.serverConfig.on('closed', function(n) {
|
||||
if (n > 0) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); }
|
||||
else { node.status({fill:"red",shape:"ring",text:"common.status.disconnected"}); }
|
||||
this.serverConfig.on('opened', function(event) {
|
||||
node.status({
|
||||
fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count}),
|
||||
event:"connect",
|
||||
_session: {type:"websocket",id:event.id}
|
||||
});
|
||||
});
|
||||
this.serverConfig.on('erro', function(event) {
|
||||
node.status({
|
||||
fill:"red",shape:"ring",text:"common.status.error",
|
||||
event:"error",
|
||||
_session: {type:"websocket",id:event.id}
|
||||
})
|
||||
});
|
||||
this.serverConfig.on('closed', function(event) {
|
||||
var status;
|
||||
if (event.count > 0) {
|
||||
status = {fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:event.count})};
|
||||
} else {
|
||||
status = {fill:"red",shape:"ring",text:"common.status.disconnected"};
|
||||
}
|
||||
status.event = "disconnect";
|
||||
status._session = {type:"websocket",id:event.id}
|
||||
node.status(status);
|
||||
});
|
||||
}
|
||||
this.on("input", function(msg) {
|
||||
|
@@ -158,7 +158,13 @@ module.exports = function(RED) {
|
||||
var fromp;
|
||||
connectionPool[id] = socket;
|
||||
count++;
|
||||
node.status({text:RED._("tcpin.status.connections",{count:count})});
|
||||
node.status({
|
||||
text:RED._("tcpin.status.connections",{count:count}),
|
||||
event:"connect",
|
||||
ip:socket.remoteAddress,
|
||||
port:socket.remotePort,
|
||||
_session: {type:"tcp",id:id}
|
||||
});
|
||||
|
||||
var buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
socket.on('data', function (data) {
|
||||
@@ -209,7 +215,14 @@ module.exports = function(RED) {
|
||||
socket.on('close', function() {
|
||||
delete connectionPool[id];
|
||||
count--;
|
||||
node.status({text:RED._("tcpin.status.connections",{count:count})});
|
||||
node.status({
|
||||
text:RED._("tcpin.status.connections",{count:count}),
|
||||
event:"disconnect",
|
||||
ip:socket.remoteAddress,
|
||||
port:socket.remotePort,
|
||||
_session: {type:"tcp",id:id}
|
||||
|
||||
});
|
||||
});
|
||||
socket.on('error',function(err) {
|
||||
node.log(err);
|
||||
|
@@ -94,7 +94,7 @@ module.exports = function(RED) {
|
||||
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
|
||||
}
|
||||
} else if (rule.tot === 'env') {
|
||||
rule.to = RED.util.evaluateNodeProperty(rule.to,'env');
|
||||
rule.to = RED.util.evaluateNodeProperty(rule.to,'env',node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -631,8 +631,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (payloadType === 'object') {
|
||||
group.payload[propertyKey] = property;
|
||||
group.currentCount = Object.keys(group.payload).length;
|
||||
//msg.topic = node.topic || msg.topic;
|
||||
group.currentCount = (group.currentCount || 0) + 1;
|
||||
} else if (payloadType === 'merged') {
|
||||
if (Array.isArray(property) || typeof property !== 'object') {
|
||||
if (!msg.hasOwnProperty("complete")) {
|
||||
|
@@ -82,7 +82,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeof value === "object") {
|
||||
else if ((typeof value === "object") || (typeof value === "boolean") || (typeof value === "number")) {
|
||||
if (node.action === "" || node.action === "str") {
|
||||
if (!Buffer.isBuffer(value)) {
|
||||
try {
|
||||
|
@@ -22,6 +22,11 @@
|
||||
<input type="checkbox" id="node-input-createDir" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-createDir" style="width: 70%;"><span data-i18n="file.label.createdir"></span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-encoding"><i class="fa fa-flag"></i> <span data-i18n="file.label.encoding"></span></label>
|
||||
<select type="text" id="node-input-encoding" style="width: 250px;">
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
@@ -48,6 +53,11 @@
|
||||
<input type="checkbox" id="node-input-sendError" style="width:auto">
|
||||
<label style="width:auto; margin-bottom:0; vertical-align: middle;" for="node-input-sendError" data-i18n="file.label.sendError"></label>
|
||||
</div>
|
||||
<div class="form-row" id="encoding-spec">
|
||||
<label for="node-input-encoding"><i class="fa fa-flag"></i> <span data-i18n="file.label.encoding"></span></label>
|
||||
<select type="text" id="node-input-encoding" style="width: 250px;">
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
@@ -56,6 +66,132 @@
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
var encodings = [
|
||||
[ "file.encoding.native",
|
||||
"utf8",
|
||||
"ucs2",
|
||||
"utf-16le",
|
||||
"ascii",
|
||||
"binary",
|
||||
"base64",
|
||||
"hex"
|
||||
],
|
||||
[ "file.encoding.unicode",
|
||||
"utf-16be",
|
||||
],
|
||||
[ "file.encoding.japanese",
|
||||
"Shift_JIS",
|
||||
"Windows-31j",
|
||||
"Windows932",
|
||||
"EUC-JP"
|
||||
],
|
||||
[ "file.encoding.chinese",
|
||||
"GB2312",
|
||||
"GBK",
|
||||
"GB18030",
|
||||
"Windows936",
|
||||
"EUC-CN"
|
||||
],
|
||||
[ "file.encoding.korean",
|
||||
"KS_C_5601",
|
||||
"Windows949",
|
||||
"EUC-KR"
|
||||
],
|
||||
[ "file.encoding.taiwan",
|
||||
"Big5",
|
||||
"Big5-HKSCS",
|
||||
"Windows950"
|
||||
],
|
||||
[ "file.encoding.windows",
|
||||
"cp874",
|
||||
"cp1250",
|
||||
"cp1251",
|
||||
"cp1252",
|
||||
"cp1253",
|
||||
"cp1254",
|
||||
"cp1255",
|
||||
"cp1256",
|
||||
"cp1257",
|
||||
"cp1258"
|
||||
],
|
||||
[ "file.encoding.iso",
|
||||
"ISO-8859-1",
|
||||
"ISO-8859-2",
|
||||
"ISO-8859-3",
|
||||
"ISO-8859-4",
|
||||
"ISO-8859-5",
|
||||
"ISO-8859-6",
|
||||
"ISO-8859-7",
|
||||
"ISO-8859-8",
|
||||
"ISO-8859-9",
|
||||
"ISO-8859-10",
|
||||
"ISO-8859-11",
|
||||
"ISO-8859-12",
|
||||
"ISO-8859-13",
|
||||
"ISO-8859-14",
|
||||
"ISO-8859-15",
|
||||
"ISO-8859-16"
|
||||
],
|
||||
[ "file.encoding.ibm",
|
||||
"cp437",
|
||||
"cp737",
|
||||
"cp775",
|
||||
"cp808",
|
||||
"cp850",
|
||||
"cp852",
|
||||
"cp855",
|
||||
"cp856",
|
||||
"cp857",
|
||||
"cp858",
|
||||
"cp860",
|
||||
"cp861",
|
||||
"cp866",
|
||||
"cp869",
|
||||
"cp922",
|
||||
"cp1046",
|
||||
"cp1124",
|
||||
"cp1125",
|
||||
"cp1129",
|
||||
"cp1133",
|
||||
"cp1161",
|
||||
"cp1162",
|
||||
"cp1163"
|
||||
],
|
||||
[ "file.encoding.mac",
|
||||
"maccroatian",
|
||||
"maccyrillic",
|
||||
"macgreek",
|
||||
"maciceland",
|
||||
"macroman",
|
||||
"macromania",
|
||||
"macthai",
|
||||
"macturkish",
|
||||
"macukraine",
|
||||
"maccenteuro",
|
||||
"macintosh"
|
||||
],
|
||||
[ "file.encoding.koi8",
|
||||
"koi8-r",
|
||||
"koi8-u",
|
||||
"koi8-ru",
|
||||
"koi8-t"
|
||||
],
|
||||
[ "file.encoding.misc",
|
||||
"armscii8",
|
||||
"rk1048",
|
||||
"tcvn",
|
||||
"georgianacademy",
|
||||
"georgianps",
|
||||
"pt154",
|
||||
"viscii",
|
||||
"iso646cn",
|
||||
"iso646jp",
|
||||
"hproman8",
|
||||
"tis620"
|
||||
]
|
||||
];
|
||||
|
||||
RED.nodes.registerType('file',{
|
||||
category: 'storage-output',
|
||||
defaults: {
|
||||
@@ -63,7 +199,8 @@
|
||||
filename: {value:""},
|
||||
appendNewline: {value:true},
|
||||
createDir: {value:false},
|
||||
overwriteFile: {value:"false"}
|
||||
overwriteFile: {value:"false"},
|
||||
encoding: {value:"none"}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
@@ -80,6 +217,34 @@
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
var encSel = $("#node-input-encoding");
|
||||
var label = node._("file.encoding.none");
|
||||
$("<option/>", {
|
||||
value: "none",
|
||||
label: label
|
||||
}).text(label).appendTo(encSel);
|
||||
encodings.forEach(function(item) {
|
||||
if(Array.isArray(item)) {
|
||||
var group = $("<optgroup/>", {
|
||||
label: node._(item[0])
|
||||
}).appendTo(encSel);
|
||||
for (var i = 1; i < item.length; i++) {
|
||||
var enc = item[i];
|
||||
$("<option/>", {
|
||||
value: enc,
|
||||
label: enc
|
||||
}).text(enc).appendTo(group);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("<option/>", {
|
||||
value: item,
|
||||
label: item
|
||||
}).text(item).appendTo(encSel);
|
||||
}
|
||||
});
|
||||
encSel.val(node.encoding);
|
||||
$("#node-input-overwriteFile").on("change",function() {
|
||||
if (this.value === "delete") { $(".form-row-file-write-options").hide(); }
|
||||
else { $(".form-row-file-write-options").show(); }
|
||||
@@ -94,13 +259,14 @@
|
||||
filename: {value:""},
|
||||
format: {value:"utf8"},
|
||||
chunk: {value:false},
|
||||
sendError: {value: false}
|
||||
sendError: {value: false},
|
||||
encoding: {value: "none"}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function(i) {
|
||||
return (this.format === "utf8") ? "UTF8 string" : "binary buffer";
|
||||
return (this._((this.format === "utf8") ? "file.label.utf8String" : "file.label.binaryBuffer"));
|
||||
},
|
||||
icon: "file-in.png",
|
||||
label: function() {
|
||||
@@ -110,19 +276,47 @@
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
var encSel = $("#node-input-encoding");
|
||||
var label = node._("file.encoding.none");
|
||||
$("<option/>", {
|
||||
value: "none",
|
||||
label: label
|
||||
}).text(label).appendTo(encSel);
|
||||
encodings.forEach(function(item) {
|
||||
if(Array.isArray(item)) {
|
||||
var group = $("<optgroup/>", {
|
||||
label: node._(item[0])
|
||||
}).appendTo(encSel);
|
||||
for (var i = 1; i < item.length; i++) {
|
||||
var enc = item[i];
|
||||
$("<option/>", {
|
||||
value: enc,
|
||||
label: enc
|
||||
}).text(enc).appendTo(group);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("<option/>", {
|
||||
value: item,
|
||||
label: item
|
||||
}).text(item).appendTo(encSel);
|
||||
}
|
||||
});
|
||||
encSel.val(node.encoding);
|
||||
if (this.sendError === undefined) {
|
||||
$("#node-input-sendError").prop("checked",true);
|
||||
}
|
||||
$("#node-input-format").on("change",function() {
|
||||
if ($("#node-input-format").val() === "utf8") {
|
||||
$("#buffer-input-type").hide();
|
||||
$("#line-input-type").show();
|
||||
var format = $("#node-input-format").val();
|
||||
if ((format === "utf8") || (format === "lines")) {
|
||||
$("#encoding-spec").show();
|
||||
}
|
||||
else {
|
||||
$("#buffer-input-type").show();
|
||||
$("#line-input-type").hide();
|
||||
$("#encoding-spec").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
@@ -19,13 +19,29 @@ module.exports = function(RED) {
|
||||
var fs = require("fs-extra");
|
||||
var os = require("os");
|
||||
var path = require("path");
|
||||
var iconv = require("iconv-lite")
|
||||
|
||||
function encode(data, enc) {
|
||||
if (enc !== "none") {
|
||||
return iconv.encode(data, enc);
|
||||
}
|
||||
return Buffer.from(data);
|
||||
}
|
||||
|
||||
function decode(data, enc) {
|
||||
if (enc !== "none") {
|
||||
return iconv.decode(data, enc);
|
||||
}
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
function FileNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.filename = n.filename;
|
||||
this.appendNewline = n.appendNewline;
|
||||
this.overwriteFile = n.overwriteFile.toString();
|
||||
this.createDir = n.createDir || false;
|
||||
this.encoding = n.encoding || "none";
|
||||
var node = this;
|
||||
node.wstream = null;
|
||||
node.msgQueue = [];
|
||||
@@ -75,6 +91,7 @@ module.exports = function(RED) {
|
||||
if (typeof data === "boolean") { data = data.toString(); }
|
||||
if (typeof data === "number") { data = data.toString(); }
|
||||
if ((node.appendNewline) && (!Buffer.isBuffer(data))) { data += os.EOL; }
|
||||
var buf = encode(data, node.encoding);
|
||||
if (node.overwriteFile === "true") {
|
||||
var wstream = fs.createWriteStream(filename, { encoding:'binary', flags:'w', autoClose:true });
|
||||
node.wstream = wstream;
|
||||
@@ -83,7 +100,7 @@ module.exports = function(RED) {
|
||||
done();
|
||||
});
|
||||
wstream.on("open", function() {
|
||||
wstream.end(data, function() {
|
||||
wstream.end(buf, function() {
|
||||
node.send(msg);
|
||||
done();
|
||||
});
|
||||
@@ -132,13 +149,13 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (node.filename) {
|
||||
// Static filename - write and reuse the stream next time
|
||||
node.wstream.write(data, function() {
|
||||
node.wstream.write(buf, function() {
|
||||
node.send(msg);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
// Dynamic filename - write and close the stream
|
||||
node.wstream.end(data, function() {
|
||||
node.wstream.end(buf, function() {
|
||||
node.send(msg);
|
||||
delete node.wstream;
|
||||
delete node.wstreamIno;
|
||||
@@ -221,6 +238,7 @@ module.exports = function(RED) {
|
||||
this.filename = n.filename;
|
||||
this.format = n.format;
|
||||
this.chunk = false;
|
||||
this.encoding = n.encoding || "none";
|
||||
if (n.sendError === undefined) {
|
||||
this.sendError = true;
|
||||
} else {
|
||||
@@ -260,7 +278,7 @@ module.exports = function(RED) {
|
||||
if (node.chunk === true) {
|
||||
getout = true;
|
||||
if (node.format === "lines") {
|
||||
spare += chunk.toString();
|
||||
spare += decode(chunk, node.encoding);
|
||||
var bits = spare.split("\n");
|
||||
for (var i=0; i < bits.length - 1; i++) {
|
||||
var m = {
|
||||
@@ -305,7 +323,9 @@ module.exports = function(RED) {
|
||||
})
|
||||
.on('end', function() {
|
||||
if (node.chunk === false) {
|
||||
if (node.format === "utf8") { msg.payload = lines.toString(); }
|
||||
if (node.format === "utf8") {
|
||||
msg.payload = decode(lines, node.encoding);
|
||||
}
|
||||
else { msg.payload = lines; }
|
||||
node.send(msg);
|
||||
}
|
||||
|
@@ -32,7 +32,8 @@
|
||||
halt. This node can be used to catch those errors and handle them with a
|
||||
dedicated flow.</p>
|
||||
<p>By default, the node will catch errors thrown by any node on the same tab. Alternatively
|
||||
it can be targetted at specific nodes.</p>
|
||||
it can be targetted at specific nodes, or configured to only catch errors that
|
||||
have not already been caught by a 'targeted' catch node.</p>
|
||||
<p>When an error is thrown, all matching catch nodes will receive the message.</p>
|
||||
<p>If an error is thrown within a subflow, the error will get handled by any
|
||||
catch nodes within the subflow. If none exists, the error will be propagated
|
||||
|
@@ -78,5 +78,18 @@
|
||||
<p>If <code>msg.payload</code> is an Object, the node will automatically set the content type
|
||||
of the request to <code>application/json</code> and encode the body as such.</p>
|
||||
<p>To encode the request as form data, <code>msg.headers["content-type"]</code> should be set to <code>application/x-www-form-urlencoded</code>.</p>
|
||||
<h4>File Upload</h4>
|
||||
<p>To perform a file upload, <code>msg.headers["content-type"]</code> should be set to <code>multipart/form-data</code>
|
||||
and the <code>msg.payload</code> passed to the node must be an object with the following structure:</p>
|
||||
<pre><code>{
|
||||
"KEY": {
|
||||
"value": FILE_CONTENTS,
|
||||
"options": {
|
||||
"filename": "FILENAME"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p>The values of <code>KEY</code>, <code>FILE_CONTENTS</code> and <code>FILENAME</code>
|
||||
should be set to the appropriate values.</p>
|
||||
|
||||
</script>
|
||||
|
72
packages/node_modules/@node-red/nodes/locales/en-US/messages.json
vendored
Normal file → Executable file
72
packages/node_modules/@node-red/nodes/locales/en-US/messages.json
vendored
Normal file → Executable file
@@ -35,7 +35,22 @@
|
||||
"stopped": "stopped",
|
||||
"failed": "Inject failed: __error__",
|
||||
"label": {
|
||||
"repeat": "Repeat"
|
||||
"repeat": "Repeat",
|
||||
"flow": "flow context",
|
||||
"global": "global context",
|
||||
"str": "string",
|
||||
"num": "number",
|
||||
"bool": "boolean",
|
||||
"json": "object",
|
||||
"bin": "buffer",
|
||||
"date": "timestamp",
|
||||
"env": "env variable",
|
||||
"object": "object",
|
||||
"string": "string",
|
||||
"boolean": "boolean",
|
||||
"number": "number",
|
||||
"Array": "Array",
|
||||
"invalid": "Invalid JSON Object"
|
||||
},
|
||||
"timestamp": "timestamp",
|
||||
"none": "none",
|
||||
@@ -72,13 +87,15 @@
|
||||
"catch": {
|
||||
"catch": "catch: all",
|
||||
"catchNodes": "catch: __number__",
|
||||
"catchUncaught": "catch: uncaught",
|
||||
"label": {
|
||||
"source": "Catch errors from",
|
||||
"node": "node",
|
||||
"type": "type",
|
||||
"selectAll": "select all",
|
||||
"sortByLabel": "sort by label",
|
||||
"sortByType": "sort by type"
|
||||
"sortByType": "sort by type",
|
||||
"uncaught": "Ignore errors handled by other Catch nodes"
|
||||
},
|
||||
"scope": {
|
||||
"all": "all nodes",
|
||||
@@ -172,7 +189,10 @@
|
||||
"timeout": "Timeout",
|
||||
"timeoutplace": "optional",
|
||||
"return": "Output",
|
||||
"seconds": "seconds"
|
||||
"seconds": "seconds",
|
||||
"stdout": "stdout",
|
||||
"stderr": "stderr",
|
||||
"retcode": "return code"
|
||||
},
|
||||
"placeholder": {
|
||||
"extraparams": "extra input parameters"
|
||||
@@ -222,7 +242,7 @@
|
||||
"limittopic": "For each msg.topic",
|
||||
"fairqueue": "Send each topic in turn",
|
||||
"timedqueue": "Send all topics",
|
||||
"milisecs": "Miliseconds",
|
||||
"milisecs": "Milliseconds",
|
||||
"secs": "Seconds",
|
||||
"sec": "Second",
|
||||
"mins": "Minutes",
|
||||
@@ -353,7 +373,8 @@
|
||||
"buffer": "a Buffer",
|
||||
"string": "a String",
|
||||
"base64": "a Base64 encoded string",
|
||||
"auto": "auto-detect"
|
||||
"auto": "auto-detect (string or buffer)",
|
||||
"json": "a parsed JSON object"
|
||||
},
|
||||
"true": "true",
|
||||
"false": "false",
|
||||
@@ -362,7 +383,9 @@
|
||||
"not-defined": "topic not defined",
|
||||
"missing-config": "missing broker configuration",
|
||||
"invalid-topic": "Invalid topic specified",
|
||||
"nonclean-missingclientid": "No client ID set, using clean session"
|
||||
"nonclean-missingclientid": "No client ID set, using clean session",
|
||||
"invalid-json-string": "Invalid JSON string",
|
||||
"invalid-json-parse": "Failed to parse JSON string"
|
||||
}
|
||||
},
|
||||
"httpin": {
|
||||
@@ -374,12 +397,21 @@
|
||||
"upload": "Accept file uploads?",
|
||||
"status": "Status code",
|
||||
"headers": "Headers",
|
||||
"other": "other"
|
||||
"other": "other",
|
||||
"paytoqs" : "Append msg.payload as query string parameters",
|
||||
"utf8String": "UTF8 string",
|
||||
"binaryBuffer": "binary buffer",
|
||||
"jsonObject": "parsed JSON object",
|
||||
"authType": "Type",
|
||||
"bearerToken": "Token"
|
||||
},
|
||||
"setby": "- set by msg.method -",
|
||||
"basicauth": "Use basic authentication",
|
||||
"basicauth": "Use authentication",
|
||||
"use-tls": "Enable secure (SSL/TLS) connection",
|
||||
"tls-config":"TLS Configuration",
|
||||
"basic": "basic authentication",
|
||||
"digest": "digest authentication",
|
||||
"bearer": "bearer authentication",
|
||||
"use-proxy": "Use proxy",
|
||||
"proxy-config": "Proxy Configuration",
|
||||
"use-proxyauth": "Use proxy authentication",
|
||||
@@ -402,7 +434,8 @@
|
||||
"deprecated-call":"Deprecated call to __method__",
|
||||
"invalid-transport":"non-http transport requested",
|
||||
"timeout-isnan": "Timeout value is not a valid number, ignoring",
|
||||
"timeout-isnegative": "Timeout value is negative, ignoring"
|
||||
"timeout-isnegative": "Timeout value is negative, ignoring",
|
||||
"invalid-payload": "Invalid payload"
|
||||
},
|
||||
"status": {
|
||||
"requesting": "requesting"
|
||||
@@ -430,7 +463,7 @@
|
||||
"connected_plural": "connected __count__"
|
||||
},
|
||||
"errors": {
|
||||
"connect-error": "An error occured on the ws connection: ",
|
||||
"connect-error": "An error occurred on the ws connection: ",
|
||||
"send-error": "An error occurred while sending: ",
|
||||
"missing-conf": "Missing server configuration",
|
||||
"duplicate-path": "Cannot have two WebSocket listeners on the same path: __path__"
|
||||
@@ -826,7 +859,9 @@
|
||||
"breaklines": "Break into lines",
|
||||
"filelabel": "file",
|
||||
"sendError": "Send message on error (legacy mode)",
|
||||
"deletelabel": "delete __file__"
|
||||
"deletelabel": "delete __file__",
|
||||
"utf8String": "UTF8 string",
|
||||
"binaryBuffer": "binary buffer"
|
||||
},
|
||||
"action": {
|
||||
"append": "append to file",
|
||||
@@ -844,6 +879,21 @@
|
||||
"deletedfile": "deleted file: __file__",
|
||||
"appendedfile": "appended to file: __file__"
|
||||
},
|
||||
"encoding": {
|
||||
"none": "default",
|
||||
"native": "Native",
|
||||
"unicode": "Unicode",
|
||||
"japanese": "Japanese",
|
||||
"chinese": "Chinese",
|
||||
"korean": "Korean",
|
||||
"taiwan": "Taiwan/Hong Kong",
|
||||
"windows": "Windows codepages",
|
||||
"iso": "ISO codepages",
|
||||
"ibm": "IBM codepages",
|
||||
"mac": "Mac codepages",
|
||||
"koi8": "KOI8 codepages",
|
||||
"misc": "Miscellaneous"
|
||||
},
|
||||
"errors": {
|
||||
"nofilename": "No filename specified",
|
||||
"invaliddelete": "Warning: Invalid delete. Please use specific delete option in config dialog.",
|
||||
|
@@ -32,6 +32,7 @@
|
||||
<p>It can be configured to overwrite the entire file rather than append. For example,
|
||||
when writing binary data to a file, such as an image, this option should be used
|
||||
and the option to append a newline should be disabled.</p>
|
||||
<p>Encoding of data written to a file can be specified from list of encodings.</p>
|
||||
<p>Alternatively, this node can be configured to delete the file.</p>
|
||||
</script>
|
||||
|
||||
@@ -63,6 +64,7 @@
|
||||
split into smaller buffer chunks - the chunk size being operating system dependant, but typically 64k (Linux/Mac) or 41k (Windows).</p>
|
||||
<p>When split into multiple messages, each message will have a <code>parts</code>
|
||||
property set, forming a complete message sequence.</p>
|
||||
<p>Encoding of input data can be specified from list of encodings if output format is string.</p>
|
||||
<h4>Legacy error handling</h4>
|
||||
<p>Before Node-RED 0.17, if this node hit an error whilst reading the file, it would
|
||||
send a message with no <code>msg.payload</code> and <code>msg.error</code> set to the
|
||||
|
@@ -29,7 +29,7 @@
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>メッセージの処理中にノードがエラーを送出した場合、フロー実行は基本的に停止します。このノードを使うと、エラーをキャッチして対応するフローで処理させることができます。</p>
|
||||
<p>デフォルトでは、同じタブの全てのノードが送出したエラーをキャッチします。特定のノードをキャッチ対象とすることも可能です。</p>
|
||||
<p>デフォルトでは、同じタブの全てのノードが送出したエラーをキャッチします。特定のノードをキャッチ対象とするか、対象catchノードで補足されていないエラーのみ補足するように指定することも可能です。</p>
|
||||
<p>エラー発生時には、マッチするすべてのcatchノードがメッセージを受け取ります。</p>
|
||||
<p>サブフロー内でエラーが送出された場合、まずサブフロー内のcatchノードで処理されます。対応するノードが存在しない場合には、そのサブフローが配置されたタブにエラーを伝播して処理します。</p>
|
||||
<p>メッセージが<code>error</code>プロパティを持っている場合、元の<code>error</code>は<code>_error</code>へコピーします。</p>
|
||||
|
@@ -46,4 +46,6 @@
|
||||
<li><code>node.id</code> - ノードのID</li>
|
||||
<li><code>node.name</code> - ノードの名称</li>
|
||||
</ul>
|
||||
<h4>環境変数の利用</h4>
|
||||
<p>環境変数は<code>env.get("MY_ENV_VAR")</code>により参照できます。</p>
|
||||
</script>
|
||||
|
@@ -42,6 +42,8 @@
|
||||
<p>というメッセージを受信した場合、</p>
|
||||
<pre>こんにちは山田さん。今日は月曜日です。</pre>
|
||||
<p>というプロパティが生成されます。</p>
|
||||
<p>フローコンテキストもしくはグローバルコンテキストのプロパティ値を使うこともできます。それぞれ、<code>{{flow.名前}}</code>もしくは<code>{{global.名前}}</code>を用います。</p>
|
||||
<p>フローコンテキストもしくはグローバルコンテキストのプロパティ値を使うこともできます。それぞれ、<code>{{flow.名前}}</code>もしくは<code>{{global.名前}}</code>を用います。もしくは、パーシスタブルストア(<code>store</code>)に対しては、<code>{{flow[store].名前}}</code>もしくは
|
||||
<code>{{global[store].名前}}</code>を用います。
|
||||
</p>
|
||||
<p><b>注: </b>デフォルトでは、<i>mustache</i>形式は置換対象のHTML要素をエスケープします。これを抑止するには<code>{{{三重}}}</code>括弧形式を使います。</p>
|
||||
</script>
|
||||
|
@@ -58,7 +58,7 @@
|
||||
<h3>詳細</h3>
|
||||
<p><code>statusCode</code>と<code>headers</code>はノードの設定で指定することも可能です。ノードの設定でプロパティを指定した場合には、対応するメッセージプロパティは使用しません。</p>
|
||||
<h4>クッキーの処理</h4>
|
||||
<p><code>cookies</code>はキー/値の組からなるオブジェクトとします。値にはデフォルトオプションを使ってクッキーの値として設定する文字列、もしくは、オプションを含むオブジェクトを指定できます。<p>
|
||||
<p><code>cookies</code>はキー/値の組からなるオブジェクトとします。値にはデフォルトオプションを使ってクッキーの値として設定する文字列、もしくは、オプションを含むオブジェクトを指定できます。</p>
|
||||
<p>以下の例では2つのクッキーを設定しています。1つ目は<code>name</code>でその値は<code>nick</code>、2つ目は<code>session</code>で値は<code>1234</code>、有効期限として15分を指定しています。</p>
|
||||
<pre>
|
||||
msg.cookies = {
|
||||
|
@@ -55,10 +55,21 @@
|
||||
<h4>複数のHTTPリクエストノードの利用</h4>
|
||||
<p>同一フローで本ノードを複数利用するためには、<code>msg.headers</code>プロパティの扱いに注意しなくてはなりません。例えば、最初のノードがレスポンスヘッダにこのプロパティを設定し、次のノードがこのプロパティをリクエストヘッダに利用するというのは一般的には期待する動作ではありません。<code>msg.headers</code>プロパティをノード間で変更しないままとすると、2つ目のノードで無視されることになります。カスタムヘッダを設定するためには、<code>msg.headers</code>をまず削除もしくは空のオブジェクト<code>{}</code>にリセットします。
|
||||
<h4>クッキーの扱い</h4>
|
||||
<p>ノードに<code>cookies</code>プロパティを渡す場合、その値はキー/値ペアからなるオブジェクトとしてください。値にはクッキーの値として設定する文字列、もしくは、単一の<code>value</code>プロパティを含むオブジェクトを指定できます。<p>
|
||||
<p>ノードに<code>cookies</code>プロパティを渡す場合、その値はキー/値ペアからなるオブジェクトとしてください。値にはクッキーの値として設定する文字列、もしくは、単一の<code>value</code>プロパティを含むオブジェクトを指定できます。</p>
|
||||
<p>リクエストに対して返却されたクッキーは<code>responseCookies</code>プロパティに格納されます。</p>
|
||||
<h4>要素タイプの扱い</h4>
|
||||
<p><code>msg.payload</code>がオブジェクトの場合、リクエストの要素タイプを<code>msg.payload</code>に自動的に設定し、ボディーをJSONに変換します。</p>
|
||||
<p>リクエストをフォームデータにエンコードするには、<code>msg.headers["content-type"]</code>を<code>application/x-www-form-urlencoded</code>に設定します。</p>
|
||||
<h4>ファイルのアップロード</h4>
|
||||
<p><code>msg.headers["content-type"]</code>に<code>multipart/form-data</code>を指定するとファイルをアップロードできます。この際、ノードの<code>msg.payload</code>に渡されるデータは以下の構造を持ったオブジェクトとします:</p>
|
||||
<pre><code>{
|
||||
"KEY": {
|
||||
"value": FILE_CONTENTS,
|
||||
"options": {
|
||||
"filename": "FILENAME"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p><code>KEY</code>, <code>FILE_CONTENTS</code> および <code>FILENAME</code>には適切な値を設定してください。</p>
|
||||
|
||||
</script>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp in">
|
||||
<p>TCPからの入力を行います。リモートTCPポートに接続するか、外部らからのコネクションを受け付けます。</p>
|
||||
<p>TCPからの入力を行います。リモートTCPポートに接続するか、外部からのコネクションを受け付けます。</p>
|
||||
<p><b>注: </b>1024番より小さな番号のポートをアクセスするにはrootもしくはadministrator権限が必要なシステムもあります。</p>
|
||||
</script>
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
<script type="text/x-red" data-help-name="tcp request">
|
||||
<p>シンプルなTCPリクエストノード。<code>msg.payload</code>をサーバのTCPポートに送信し、レスポンスを待ちます。</p>
|
||||
<p>サーバに接続、"リクエスト"送信、"レスポンス"受信を行います。固定長の文字数、指定文字へのマッチ、最初のリプライの到着から指定した時間待つ、データの到着待ち、データ送信を行いリプライを待たず接続を即時解除、などから動作を選択できます。</p>
|
||||
<p>レスポンスはバッファ形式で<code>msg.payload</code>に出力されます。文字列として扱いには、toString()を使用してください。</p>
|
||||
<p>レスポンスはバッファ形式で<code>msg.payload</code>に出力されます。文字列として扱いには、.toString()を使用してください。</p>
|
||||
<p>TCPホストのポート番号設定を空にした場合、<code>msg.host</code>および<code>msg.port</code>プロパティを設定しなくてはなりません。</p>
|
||||
</script>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
<p>受信したメッセージに対し、指定されたルールを順に評価し、マッチしたルールに対応する出力ポートにメッセージを送出します。</p>
|
||||
<p>最初にルールがマッチしたところで評価を止めることも可能です。</p>
|
||||
<p>評価ルールには、メッセージプロパティ、フローコンテキスト/グローバルコンテキストのプロパティ、JSONata式の評価結果が利用できます。</p>
|
||||
<h3>ルール</h3>
|
||||
<h4>ルール</h4>
|
||||
<p>振り分けルールは以下の4つに分類されます。</p>
|
||||
<ol>
|
||||
<li><b>値(value)</b>ルール - 指定したプロパティに対して評価</li>
|
||||
@@ -29,11 +29,11 @@
|
||||
<li><b>その他</b> - これより前のルールにマッチするものがなかった場合に適用</li>
|
||||
</ol>
|
||||
|
||||
<h3>注釈</h3>
|
||||
<h4>注釈</h4>
|
||||
<p><code>is true/false</code>と<code>is null</code>のルールは、型に対して厳密な比較を行います。型変換した上での比較はしません。</p>
|
||||
<p><code>is empty</code>のルールは、長さ0の文字列・配列・バッファ、またはプロパティを持たないオブジェクトを出力します。<code>null</code>や<code>undefined</code>は出力しません。</p>
|
||||
|
||||
<h3>メッセージ列の扱い</h3>
|
||||
<h4>メッセージ列の扱い</h4>
|
||||
<p>switchノードは入力メッセージの列に関する情報を保持する<code>msg.parts</code>をデフォルトでは変更しません。</p>
|
||||
<p>「<b>メッセージ列の補正</b>」オプションを指定すると、マッチした各ルールに対して新しいメッセージ列を生成します。このモードでは、switchノードは新たなメッセージ列を送信する前に、入力メッセージ列全体を内部に蓄積します。<b>settings.js</b>の<code>nodeMessageBufferMaxLength</code>を設定すると、蓄積するメッセージ数を制限できます。</p>
|
||||
</script>
|
||||
|
@@ -29,5 +29,5 @@
|
||||
<dt>移動</dt>
|
||||
<dd>プロパティの移動または名前の変更を行います。</dd>
|
||||
</dl>
|
||||
<p>「expression」には<a href="http://jsonata.org/" target="_new">JSONata</a>言語を指定できます。</p>
|
||||
<p>「JSONata式」には<a href="http://jsonata.org/" target="_new">JSONata</a>言語を指定できます。</p>
|
||||
</script>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
<h3>入力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload<span class="property-type">数値</span></dt>
|
||||
<dd>数値以外の場合は、数値に変換します。変換不能な場合はラーとなります。</dd>
|
||||
<dd>数値を指定します。数値以外を指定した場合は、数値に変換します。変換不能な場合はエラーとなります。</dd>
|
||||
</dl>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
|
@@ -97,7 +97,8 @@
|
||||
<p>出力メッセージのその他のプロパティはメッセージを送信する直前のメッセージをコピーします。</p>
|
||||
<p>「<i>合計値</i>」には出力メッセージを送信する前に受信すべきメッセージ数を指定します。オブジェクト出力の場合、この合計値に達すると後続メッセージの到着毎にメッセージを出力するように設定することもできます。</p>
|
||||
<p>「<i>秒</i>」には新規メッセージを送信するまでの経過時間を設定します。</p>
|
||||
<p><code>msg.complete</code>プロパティを設定したメッセージを受信すると、出力メッセージを送信します。</p>
|
||||
<p><code>msg.complete</code>プロパティを設定したメッセージを受信すると、出力メッセージを送信します。この時、メッセージ列の数をリセットします。</p>
|
||||
<p><code>msg.reset</code>プロパティを設定したメッセージを受診すると、部分的に受信済みのメッセージを破棄します。これらのメッセージは送信されません。この時、メッセージ列の数をリセットします。</p>
|
||||
|
||||
<h4>列の集約モード</h4>
|
||||
<p>列の集約モードを選択すると、メッセージ列を構成する各々のメッセージに対して式を適用し、集約した値を用いて一つのメッセージを構成します。</p>
|
||||
|
93
packages/node_modules/@node-red/nodes/locales/ja/messages.json
vendored
Normal file → Executable file
93
packages/node_modules/@node-red/nodes/locales/ja/messages.json
vendored
Normal file → Executable file
@@ -35,9 +35,24 @@
|
||||
"stopped": "stopped",
|
||||
"failed": "inject失敗: __error__",
|
||||
"label": {
|
||||
"repeat": "繰り返し"
|
||||
"repeat": "繰り返し",
|
||||
"flow": "フローコンテクスト",
|
||||
"global": "グローバルコンテクスト",
|
||||
"str": "文字列",
|
||||
"num": "数値",
|
||||
"bool": "真偽値",
|
||||
"json": "オブジェクト",
|
||||
"bin": "バッファ",
|
||||
"date": "タイムスタンプ",
|
||||
"env": "環境変数",
|
||||
"object": "オブジェクト",
|
||||
"string": "文字列",
|
||||
"boolean": "真偽値",
|
||||
"number": "数値",
|
||||
"Array": "配列",
|
||||
"invalid": "不正なJSON"
|
||||
},
|
||||
"timestamp": "timestamp",
|
||||
"timestamp": "タイムスタンプ",
|
||||
"none": "なし",
|
||||
"interval": "指定した時間間隔",
|
||||
"interval-time": "指定した時間間隔、日時",
|
||||
@@ -62,7 +77,7 @@
|
||||
"on": "曜日",
|
||||
"onstart": "Node-RED起動の",
|
||||
"onceDelay": "秒後、以下を行う",
|
||||
"tip": "<b>注釈:</b> 「指定した時間間隔、日時」と「指定した日時」はcronを使用します。詳細はノードの「情報」を確認してください。",
|
||||
"tip": "<b>注釈:</b> 「指定した時間間隔、日時」と「指定した日時」はcronを使用します。<br/>「時間間隔」には596時間より小さな値を指定します。<br/>詳細はノードの「情報」を確認してください。",
|
||||
"success": "inject処理を実行しました: __label__",
|
||||
"errors": {
|
||||
"failed": "inject処理が失敗しました。詳細はログを確認してください。",
|
||||
@@ -70,15 +85,17 @@
|
||||
}
|
||||
},
|
||||
"catch": {
|
||||
"catch": "catch all",
|
||||
"catchNodes": "catch (__number__)",
|
||||
"catch": "catch: 全て",
|
||||
"catchNodes": "catch: __number__",
|
||||
"catchUncaught": "catch: 未補足",
|
||||
"label": {
|
||||
"source": "エラー取得元",
|
||||
"node": "ノード",
|
||||
"type": "型",
|
||||
"selectAll": "全て選択",
|
||||
"sortByLabel": "ノード名で並べ替え",
|
||||
"sortByType": "型で並べ替え"
|
||||
"sortByType": "型で並べ替え",
|
||||
"uncaught": "Catchノードで処理済みのエラーを無視"
|
||||
},
|
||||
"scope": {
|
||||
"all": "全てのノード",
|
||||
@@ -86,8 +103,8 @@
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"status": "status (all)",
|
||||
"statusNodes": "status (__number__)",
|
||||
"status": "status: 全て",
|
||||
"statusNodes": "status: __number__",
|
||||
"label": {
|
||||
"source": "状態取得元",
|
||||
"node": "ノード",
|
||||
@@ -172,7 +189,10 @@
|
||||
"timeout": "タイムアウト",
|
||||
"timeoutplace": "任意",
|
||||
"return": "出力",
|
||||
"seconds": "秒"
|
||||
"seconds": "秒",
|
||||
"stdout": "標準出力",
|
||||
"stderr": "標準エラー出力",
|
||||
"retcode": "返却コード"
|
||||
},
|
||||
"placeholder": {
|
||||
"extraparams": "追加引数"
|
||||
@@ -263,7 +283,7 @@
|
||||
},
|
||||
"error": {
|
||||
"buffer": "バッファ上限の1000メッセージを超えました",
|
||||
"buffer1": "バッファ上限の1000メッセージを超えました"
|
||||
"buffer1": "バッファ上限の10000メッセージを超えました"
|
||||
}
|
||||
},
|
||||
"trigger": {
|
||||
@@ -353,7 +373,8 @@
|
||||
"buffer": "バイナリバッファ",
|
||||
"string": "文字列",
|
||||
"base64": "Base64文字列",
|
||||
"auto": "自動判定"
|
||||
"auto": "自動判定(文字列もしくはバイナリバッファ)",
|
||||
"json": "JSONオブジェクト"
|
||||
},
|
||||
"true": "する",
|
||||
"false": "しない",
|
||||
@@ -362,7 +383,9 @@
|
||||
"not-defined": "トピックが設定されていません",
|
||||
"missing-config": "ブローカが設定されていません",
|
||||
"invalid-topic": "不正なトピックが設定されています",
|
||||
"nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません"
|
||||
"nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません",
|
||||
"invalid-json-string": "不正なJSON文字列",
|
||||
"invalid-json-parse": "JSON文字列のパースに失敗しました"
|
||||
}
|
||||
},
|
||||
"httpin": {
|
||||
@@ -374,19 +397,28 @@
|
||||
"upload": "ファイルのアップロード",
|
||||
"status": "状態コード",
|
||||
"headers": "ヘッダ",
|
||||
"other": "その他"
|
||||
"other": "その他",
|
||||
"paytoqs" : "msg.payloadをクエリパラメータに追加",
|
||||
"utf8String": "UTF8文字列",
|
||||
"binaryBuffer": "バイナリバッファ",
|
||||
"jsonObject": "JSONオブジェクト",
|
||||
"authType": "種別",
|
||||
"bearerToken": "トークン"
|
||||
},
|
||||
"setby": "- msg.methodに定義 -",
|
||||
"basicauth": "ベーシック認証を使用",
|
||||
"basicauth": "認証を使用",
|
||||
"use-tls": "SSL/TLS接続を有効化",
|
||||
"tls-config": "TLS設定",
|
||||
"basic": "Basic認証",
|
||||
"digest": "Digest認証",
|
||||
"bearer": "Bearer認証",
|
||||
"use-proxy": "プロキシを使用",
|
||||
"proxy-config": "プロキシ設定",
|
||||
"use-proxyauth": "プロキシ認証を使用",
|
||||
"noproxy-hosts": "例外ホスト",
|
||||
"utf8": "文字列",
|
||||
"utf8": "UTF8文字列",
|
||||
"binary": "バイナリバッファ",
|
||||
"json": "JSON",
|
||||
"json": "JSONオブジェクト",
|
||||
"tip": {
|
||||
"in": "URLは相対パスになります。",
|
||||
"res": "本ノードに送付するメッセージは、<i>http input</i>ノードを起点としてください。",
|
||||
@@ -402,7 +434,8 @@
|
||||
"deprecated-call": "非推奨の呼び出しです __method__",
|
||||
"invalid-transport": "httpでないトランスポートが要求されました",
|
||||
"timeout-isnan": "タイムアウト値が数値ではないため無視します",
|
||||
"timeout-isnegative": "タイムアウト値が負数のため無視します"
|
||||
"timeout-isnegative": "タイムアウト値が負数のため無視します",
|
||||
"invalid-payload": "不正なペイロード"
|
||||
},
|
||||
"status": {
|
||||
"requesting": "要求中"
|
||||
@@ -432,7 +465,8 @@
|
||||
"errors": {
|
||||
"connect-error": "ws接続でエラーが発生しました: ",
|
||||
"send-error": "送信中にエラーが発生しました: ",
|
||||
"missing-conf": "サーバ設定が不足しています"
|
||||
"missing-conf": "サーバ設定が不足しています",
|
||||
"duplicate-path": "同じパスに対して2つのWebSocketリスナは指定できません: __path__"
|
||||
}
|
||||
},
|
||||
"watch": {
|
||||
@@ -823,7 +857,9 @@
|
||||
"breaklines": "行へ分割",
|
||||
"filelabel": "file",
|
||||
"sendError": "エラーメッセージを送信(互換モード)",
|
||||
"deletelabel": "delete __file__"
|
||||
"deletelabel": "delete __file__",
|
||||
"utf8String": "UTF8文字列",
|
||||
"binaryBuffer": "バイナリバッファ"
|
||||
},
|
||||
"action": {
|
||||
"append": "ファイルへ追記",
|
||||
@@ -841,6 +877,21 @@
|
||||
"deletedfile": "ファイルを削除しました: __file__",
|
||||
"appendedfile": "ファイルへ追記しました: __file__"
|
||||
},
|
||||
"encoding": {
|
||||
"none": "デフォルト",
|
||||
"native": "ネイティブ",
|
||||
"unicode": "UNICODE",
|
||||
"japanese": "日本",
|
||||
"chinese": "中国",
|
||||
"korean": "韓国",
|
||||
"taiwan": "台湾/香港",
|
||||
"windows": "Windowsコードページ",
|
||||
"iso": "ISOコードページ",
|
||||
"ibm": "IBMコードページ",
|
||||
"mac": "Macコードページ",
|
||||
"koi8": "KOI8コードページ",
|
||||
"misc": "その他"
|
||||
},
|
||||
"errors": {
|
||||
"nofilename": "ファイル名が設定されていません",
|
||||
"invaliddelete": "警告: 削除が無効です。設定ダイアログで特定の削除設定を使用してください",
|
||||
@@ -849,7 +900,7 @@
|
||||
"appendfail": "ファイルの追記処理が失敗しました: __error__",
|
||||
"createfail": "ファイルの作成処理が失敗しました: __error__"
|
||||
},
|
||||
"tip": "注釈: 「ファイル名」はフルパスを設定する必要があります。"
|
||||
"tip": "注釈: 「ファイル名」にフルパスを設定しない場合は、Node-REDプロセスの実行ディレクトリからの相対パスとなります。"
|
||||
},
|
||||
"split": {
|
||||
"split": "split",
|
||||
@@ -920,7 +971,7 @@
|
||||
"ascending": "昇順",
|
||||
"descending": "降順",
|
||||
"as-number": "数値として比較",
|
||||
"invalid-exp": "sortノードで不正なJSONata式が指定されました",
|
||||
"invalid-exp": "sortノードで不正なJSONata式が指定されました: __message__",
|
||||
"too-many": "sortノードの未処理メッセージの数が許容数を超えました",
|
||||
"clear": "sortノードの未処理メッセージを破棄しました"
|
||||
},
|
||||
|
@@ -27,6 +27,7 @@
|
||||
<p>入力メッセージのペイロードをファイルの最後に追記します。改行(\n)を各データの最後に追加することもできます。</p>
|
||||
<p><code>msg.filename</code>を使う場合、書き込みを行う毎にファイルをクローズします。より良い性能を得るためにはファイル名をノードに設定してください。</p>
|
||||
<p>追記を行う代わりに、ファイル全体を上書きするように設定することもできます。例えば、画像のようなバイナリデータをファイルに書き出す場合は、このオプションを指定し、改行を追記するオプションを指定しないようにします。</p>
|
||||
<p>ファイル出力の際のエンコーディングは、エンコーディングリストから選択できます。</p>
|
||||
<p>この他、ファイルの削除を行うことも可能です。</p>
|
||||
</script>
|
||||
|
||||
@@ -51,6 +52,7 @@
|
||||
<p>Windowsではパスの区切り文字を(例えば、<code>\\ユーザー\\名前</code>のように)エスケープする必要があります。</p>
|
||||
<p>テキストファイルの場合、行毎に分割して各々メッセージを送信することができます。また、バイナリファイルの場合、小さな塊のバッファに分割して送信できます。バッファの分割単位はオペレーティングシステム依存ですが、一般に64k(Linux/Mac)もしくは41k(Windows)です。</p>
|
||||
<p>複数のメッセージに分割する場合、各メッセージには<code>parts</code>プロパティが設定され、メッセージ列を構成します。</p>
|
||||
<p>主力形式が文字列の場合、入力データのエンコーディングをエンコーディングリストから選択できます。</p>
|
||||
<h4>旧式のエラー処理</h4>
|
||||
<p>Node-RED 0.17より前の版では、ファイルの読み込み時にエラーが発生すると<code>payload</code>を持たず<code>error</code>プロパティにエラーの詳細情報を設定したメッセージを送信します。この動作モードは非推奨であり、新しいノード実装ではデフォルトでは無効としています。ノードの設定により、必要に応じてこのモードを有効にできます。</p>
|
||||
<p>エラーはcatchノードで補足して処理することを推奨します。</p>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -15,28 +15,29 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.7.0",
|
||||
"ajv": "6.10.0",
|
||||
"body-parser": "1.18.3",
|
||||
"cheerio": "0.22.0",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cookie-parser": "1.4.4",
|
||||
"cookie": "0.3.1",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.6.0",
|
||||
"cron": "1.7.0",
|
||||
"denque": "1.4.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.1",
|
||||
"js-yaml": "3.12.2",
|
||||
"media-typer": "1.0.1",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.1",
|
||||
"mustache": "3.0.1",
|
||||
"on-headers": "1.0.1",
|
||||
"on-headers": "1.0.2",
|
||||
"raw-body": "2.3.3",
|
||||
"request": "2.88.0",
|
||||
"ws": "6.1.3",
|
||||
"xml2js": "0.4.19"
|
||||
"ws": "6.2.0",
|
||||
"xml2js": "0.4.19",
|
||||
"iconv-lite": "0.4.24"
|
||||
}
|
||||
}
|
||||
|
@@ -104,7 +104,7 @@ function installModule(module,version) {
|
||||
}
|
||||
|
||||
var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
|
||||
var args = ['install','--save','--save-prefix="~"','--production',installName];
|
||||
var args = ['install','--no-audit','--no-update-notifier','--save','--save-prefix="~"','--production',installName];
|
||||
log.trace(npmCommand + JSON.stringify(args));
|
||||
exec.run(npmCommand,args,{
|
||||
cwd: installDir
|
||||
@@ -197,7 +197,7 @@ function uninstallModule(module) {
|
||||
var list = registry.removeModule(module);
|
||||
log.info(log._("server.install.uninstalling",{name:module}));
|
||||
|
||||
var args = ['remove','--save',module];
|
||||
var args = ['remove','--no-audit','--no-update-notifier','--save',module];
|
||||
log.trace(npmCommand + JSON.stringify(args));
|
||||
|
||||
exec.run(npmCommand,args,{
|
||||
|
@@ -34,14 +34,14 @@ function init(_runtime) {
|
||||
registryUtil.init(runtime);
|
||||
}
|
||||
|
||||
function load(defaultNodesDir,disableNodePathScan) {
|
||||
function load(disableNodePathScan) {
|
||||
// To skip node scan, the following line will use the stored node list.
|
||||
// We should expose that as an option at some point, although the
|
||||
// performance gains are minimal.
|
||||
//return loadNodeFiles(registry.getModuleList());
|
||||
runtime.log.info(runtime.log._("server.loading"));
|
||||
|
||||
var nodeFiles = localfilesystem.getNodeFiles(defaultNodesDir,disableNodePathScan);
|
||||
var nodeFiles = localfilesystem.getNodeFiles(disableNodePathScan);
|
||||
return loadNodeFiles(nodeFiles);
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "0.20.0-beta.4",
|
||||
"@node-red/util": "0.20.2",
|
||||
"semver": "5.6.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8"
|
||||
|
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* A WebSocket connection between the runtime and the editor.
|
||||
* @typedef CommsConnection
|
||||
* @type {object}
|
||||
* @property {string} session - a unique session identifier
|
||||
@@ -37,7 +38,12 @@ function handleCommsEvent(event) {
|
||||
publish(event.topic,event.data,event.retain);
|
||||
}
|
||||
function handleStatusEvent(event) {
|
||||
publish("status/"+event.id,event.status,true);
|
||||
var status = {
|
||||
text: event.status.text,
|
||||
fill: event.status.fill,
|
||||
shape: event.status.shape
|
||||
};
|
||||
publish("status/"+event.id,status,true);
|
||||
}
|
||||
function handleRuntimeEvent(event) {
|
||||
runtime.log.trace("runtime event: "+JSON.stringify(event));
|
||||
|
@@ -38,7 +38,11 @@ function Node(n) {
|
||||
// Make this a non-enumerable property as it may cause
|
||||
// circular references. Any existing code that tries to JSON serialise
|
||||
// the object (such as dashboard) will not like circular refs
|
||||
Object.defineProperty(this,'_flow', {value: n._flow, })
|
||||
// The value must still be writable in the case that a node does:
|
||||
// Object.assign(this,config)
|
||||
// as part of its constructure - config._flow will overwrite this._flow
|
||||
// which we can tolerate as they are the same object.
|
||||
Object.defineProperty(this,'_flow', {value: n._flow, enumerable: false, writable: true })
|
||||
}
|
||||
this.updateWires(n.wires);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ var clone = require("clone");
|
||||
var log = require("@node-red/util").log;
|
||||
var util = require("@node-red/util").util;
|
||||
var memory = require("./memory");
|
||||
var flows;
|
||||
|
||||
var settings;
|
||||
|
||||
@@ -47,6 +48,7 @@ function logUnknownStore(name) {
|
||||
}
|
||||
|
||||
function init(_settings) {
|
||||
flows = require("../flows");
|
||||
settings = _settings;
|
||||
contexts = {};
|
||||
stores = {};
|
||||
@@ -198,8 +200,24 @@ function getContextStorage(storage) {
|
||||
}
|
||||
}
|
||||
|
||||
function followParentContext(parent, key) {
|
||||
if (key === "$parent") {
|
||||
return [parent, undefined];
|
||||
}
|
||||
else if (key.startsWith("$parent.")) {
|
||||
var len = "$parent.".length;
|
||||
var new_key = key.substring(len);
|
||||
var ctx = parent;
|
||||
while (ctx && new_key.startsWith("$parent.")) {
|
||||
ctx = ctx.$parent;
|
||||
new_key = new_key.substring(len);
|
||||
}
|
||||
return [ctx, new_key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function createContext(id,seed) {
|
||||
function createContext(id,seed,parent) {
|
||||
// Seed is only set for global context - sourced from functionGlobalContext
|
||||
var scope = id;
|
||||
var obj = seed || {};
|
||||
@@ -254,6 +272,21 @@ function createContext(id,seed) {
|
||||
if (!storage) {
|
||||
storage = keyParts.store || "_";
|
||||
}
|
||||
var result = followParentContext(parent, key);
|
||||
if (result) {
|
||||
var [ctx, new_key] = result;
|
||||
if (ctx && new_key) {
|
||||
return ctx.get(new_key, storage, callback);
|
||||
}
|
||||
else {
|
||||
if (callback) {
|
||||
return callback(undefined);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!storage) {
|
||||
storage = "_";
|
||||
@@ -321,6 +354,19 @@ function createContext(id,seed) {
|
||||
if (!storage) {
|
||||
storage = keyParts.store || "_";
|
||||
}
|
||||
var result = followParentContext(parent, key);
|
||||
if (result) {
|
||||
var [ctx, new_key] = result;
|
||||
if (ctx && new_key) {
|
||||
return ctx.set(new_key, value, storage, callback);
|
||||
}
|
||||
else {
|
||||
if (callback) {
|
||||
return callback();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!storage) {
|
||||
storage = "_";
|
||||
@@ -346,7 +392,7 @@ function createContext(id,seed) {
|
||||
}
|
||||
context = getContextStorage(storage);
|
||||
}
|
||||
if (seed) {
|
||||
if (seed && settings.exportGlobalContextKeys !== false) {
|
||||
if (callback) {
|
||||
context.keys(scope, function(err,keys) {
|
||||
callback(err,Array.from(new Set(seedKeys.concat(keys)).keys()));
|
||||
@@ -361,10 +407,36 @@ function createContext(id,seed) {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (parent) {
|
||||
Object.defineProperty(obj, "$parent", {
|
||||
value: parent
|
||||
});
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function getContext(localId,flowId) {
|
||||
function createRootContext() {
|
||||
var obj = {};
|
||||
Object.defineProperties(obj, {
|
||||
get: {
|
||||
value: function(key, storage, callback) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
set: {
|
||||
value: function(key, value, storage, callback) {
|
||||
}
|
||||
},
|
||||
keys: {
|
||||
value: function(storage, callback) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
function getContext(localId,flowId,parent) {
|
||||
var contextId = localId;
|
||||
if (flowId) {
|
||||
contextId = localId+":"+flowId;
|
||||
@@ -372,10 +444,19 @@ function getContext(localId,flowId) {
|
||||
if (contexts.hasOwnProperty(contextId)) {
|
||||
return contexts[contextId];
|
||||
}
|
||||
var newContext = createContext(contextId);
|
||||
var newContext = createContext(contextId,undefined,parent);
|
||||
if (flowId) {
|
||||
var node = flows.get(flowId);
|
||||
var parent = undefined;
|
||||
if (node && node.type.startsWith("subflow:")) {
|
||||
parent = node.context().flow;
|
||||
}
|
||||
else {
|
||||
parent = createRootContext();
|
||||
}
|
||||
var flowContext = getContext(flowId,undefined,parent);
|
||||
Object.defineProperty(newContext, 'flow', {
|
||||
value: getContext(flowId)
|
||||
value: flowContext
|
||||
});
|
||||
}
|
||||
Object.defineProperty(newContext, 'global', {
|
||||
|
@@ -176,9 +176,9 @@ class Flow {
|
||||
subflowDefinition,
|
||||
node
|
||||
);
|
||||
this.subflowInstanceNodes[id] = subflow;
|
||||
subflow.start();
|
||||
this.activeNodes[id] = subflow.node;
|
||||
this.subflowInstanceNodes[id] = subflow;
|
||||
|
||||
// this.subflowInstanceNodes[id] = nodes.map(function(n) { return n.id});
|
||||
// for (var i=0;i<nodes.length;i++) {
|
||||
@@ -212,6 +212,21 @@ class Flow {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.catchNodes.sort(function(A,B) {
|
||||
if (A.scope && !B.scope) {
|
||||
return -1;
|
||||
} else if (!A.scope && B.scope) {
|
||||
return 1;
|
||||
} else if (A.scope && B.scope) {
|
||||
return 0;
|
||||
} else if (A.uncaught && !B.uncaught) {
|
||||
return 1;
|
||||
} else if (!A.uncaught && B.uncaught) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (activeCount > 0) {
|
||||
this.trace("------------------|--------------|-----------------");
|
||||
}
|
||||
@@ -232,6 +247,7 @@ class Flow {
|
||||
if (!stopList) {
|
||||
stopList = Object.keys(this.activeNodes);
|
||||
}
|
||||
// this.trace(" stopList: "+stopList.join(","))
|
||||
// Convert the list to a map to avoid multiple scans of the list
|
||||
var removedMap = {};
|
||||
removedList = removedList || [];
|
||||
@@ -246,8 +262,9 @@ class Flow {
|
||||
delete this.activeNodes[stopList[i]];
|
||||
if (this.subflowInstanceNodes[stopList[i]]) {
|
||||
try {
|
||||
var subflow = this.subflowInstanceNodes[stopList[i]];
|
||||
promises.push(stopNode(node,false).then(() => { subflow.stop() }));
|
||||
(function(subflow) {
|
||||
promises.push(stopNode(node,false).then(() => { subflow.stop() }));
|
||||
})(this.subflowInstanceNodes[stopList[i]]);
|
||||
} catch(err) {
|
||||
node.error(err);
|
||||
}
|
||||
@@ -265,7 +282,6 @@ class Flow {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the flow definition. This doesn't change anything that is running.
|
||||
* This should be called after `stop` and before `start`.
|
||||
@@ -281,11 +297,13 @@ class Flow {
|
||||
/**
|
||||
* Get a node instance from this flow. If the node is not known to this
|
||||
* flow, pass the request up to the parent.
|
||||
* @param {[type]} id [description]
|
||||
* @param {String} id [description]
|
||||
* @param {Boolean} cancelBubble if true, prevents the flow from passing the request to the parent
|
||||
* This stops infinite loops when the parent asked this Flow for the
|
||||
* node to begin with.
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getNode(id) {
|
||||
// console.log('getNode',id,!!this.activeNodes[id])
|
||||
getNode(id, cancelBubble) {
|
||||
if (!id) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -297,8 +315,22 @@ class Flow {
|
||||
} else if (this.activeNodes[id]) {
|
||||
// TEMP: this is a subflow internal node within this flow
|
||||
return this.activeNodes[id];
|
||||
} else if (cancelBubble) {
|
||||
// The node could be inside one of this flow's subflows
|
||||
var node;
|
||||
for (var sfId in this.subflowInstanceNodes) {
|
||||
if (this.subflowInstanceNodes.hasOwnProperty(sfId)) {
|
||||
node = this.subflowInstanceNodes[sfId].getNode(id,cancelBubble);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Node not found inside this flow - ask the parent
|
||||
return this.parent.getNode(id);
|
||||
}
|
||||
return this.parent.getNode(id);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,18 +390,17 @@ class Flow {
|
||||
return;
|
||||
}
|
||||
var message = {
|
||||
status: {
|
||||
text: "",
|
||||
source: {
|
||||
id: node.id,
|
||||
type: node.type,
|
||||
name: node.name
|
||||
}
|
||||
}
|
||||
};
|
||||
status: clone(statusMessage)
|
||||
}
|
||||
if (statusMessage.hasOwnProperty("text")) {
|
||||
message.status.text = statusMessage.text.toString();
|
||||
}
|
||||
message.status.source = {
|
||||
id: node.id,
|
||||
type: node.type,
|
||||
name: node.name
|
||||
}
|
||||
|
||||
targetStatusNode.receive(message);
|
||||
handled = true;
|
||||
});
|
||||
@@ -415,10 +446,20 @@ class Flow {
|
||||
}
|
||||
handled = true;
|
||||
} else {
|
||||
var handledByUncaught = false;
|
||||
|
||||
this.catchNodes.forEach(function(targetCatchNode) {
|
||||
if (targetCatchNode.scope && targetCatchNode.scope.indexOf(reportingNode.id) === -1) {
|
||||
return;
|
||||
}
|
||||
if (!targetCatchNode.scope && targetCatchNode.uncaught && !handledByUncaught) {
|
||||
if (handled) {
|
||||
// This has been handled by a !uncaught catch node
|
||||
return;
|
||||
}
|
||||
// This is an uncaught error
|
||||
handledByUncaught = true;
|
||||
}
|
||||
var errorMessage;
|
||||
if (msg) {
|
||||
errorMessage = redUtil.cloneMessage(msg);
|
||||
@@ -461,6 +502,7 @@ class Flow {
|
||||
}
|
||||
console.log("==================")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -17,11 +17,14 @@
|
||||
const clone = require("clone");
|
||||
const Flow = require('./Flow').Flow;
|
||||
|
||||
const util = require("util");
|
||||
|
||||
const redUtil = require("@node-red/util").util;
|
||||
const flowUtil = require("./util");
|
||||
|
||||
var Log;
|
||||
|
||||
|
||||
/**
|
||||
* This class represents a subflow - which is handled as a special type of Flow
|
||||
*/
|
||||
@@ -37,7 +40,6 @@ class Subflow extends Flow {
|
||||
* @param {[type]} subflowInstance [description]
|
||||
*/
|
||||
constructor(parent,globalFlow,subflowDef,subflowInstance) {
|
||||
// console.log(subflowDef);
|
||||
// console.log("CREATE SUBFLOW",subflowDef.id,subflowInstance.id);
|
||||
// console.log("SubflowInstance\n"+JSON.stringify(subflowInstance," ",2));
|
||||
// console.log("SubflowDef\n"+JSON.stringify(subflowDef," ",2));
|
||||
@@ -90,6 +92,15 @@ class Subflow extends Flow {
|
||||
this.subflowDef = subflowDef;
|
||||
this.subflowInstance = subflowInstance;
|
||||
this.node_map = node_map;
|
||||
|
||||
var env = [];
|
||||
if (this.subflowDef.env) {
|
||||
this.subflowDef.env.forEach(e => { env[e.name] = e; });
|
||||
}
|
||||
if (this.subflowInstance.env) {
|
||||
this.subflowInstance.env.forEach(e => { env[e.name] = e; });
|
||||
}
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +115,40 @@ class Subflow extends Flow {
|
||||
var self = this;
|
||||
// Create a subflow node to accept inbound messages and route appropriately
|
||||
var Node = require("../Node");
|
||||
|
||||
if (this.subflowDef.status) {
|
||||
var subflowStatusConfig = {
|
||||
id: this.subflowInstance.id+":status",
|
||||
type: "subflow-status",
|
||||
z: this.subflowInstance.id,
|
||||
_flow: this.parent
|
||||
}
|
||||
this.statusNode = new Node(subflowStatusConfig);
|
||||
this.statusNode.on("input", function(msg) {
|
||||
if (msg.payload !== undefined) {
|
||||
if (typeof msg.payload === "string") {
|
||||
// if msg.payload is a String, use it as status text
|
||||
self.node.status({text:msg.payload})
|
||||
return;
|
||||
} else if (Object.prototype.toString.call(msg.payload) === "[object Object]") {
|
||||
if (msg.payload.hasOwnProperty('text') || msg.payload.hasOwnProperty('fill') || msg.payload.hasOwnProperty('shape') || Object.keys(msg.payload).length === 0) {
|
||||
// msg.payload is an object that looks like a status object
|
||||
self.node.status(msg.payload);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Anything else - inspect it and use as status text
|
||||
var text = util.inspect(msg.payload);
|
||||
if (text.length > 32) { text = text.substr(0,32) + "..."; }
|
||||
self.node.status({text:text});
|
||||
} else if (msg.status !== undefined) {
|
||||
// if msg.status exists
|
||||
self.node.status(msg.status)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
var subflowInstanceConfig = {
|
||||
id: this.subflowInstance.id,
|
||||
type: this.subflowInstance.type,
|
||||
@@ -119,6 +164,8 @@ class Subflow extends Flow {
|
||||
|
||||
this.node = new Node(subflowInstanceConfig);
|
||||
this.node.on("input", function(msg) { this.send(msg);});
|
||||
this.node.on("close", function() { this.status({}); })
|
||||
this.node.status = status => this.parent.handleStatus(this.node,status);
|
||||
|
||||
this.node._updateWires = this.node.updateWires;
|
||||
|
||||
@@ -164,15 +211,14 @@ class Subflow extends Flow {
|
||||
self.node._updateWires(subflowInstanceConfig.wires);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Wire the subflow outputs
|
||||
if (this.subflowDef.out) {
|
||||
var modifiedNodes = {};
|
||||
for (var i=0;i<this.subflowDef.out.length;i++) {
|
||||
// i: the output index
|
||||
// This is what this Output is wired to
|
||||
wires = this.subflowDef.out[i].wires;
|
||||
var wires = this.subflowDef.out[i].wires;
|
||||
for (var j=0;j<wires.length;j++) {
|
||||
if (wires[j].id === this.subflowDef.id) {
|
||||
// A subflow input wired straight to a subflow output
|
||||
@@ -180,7 +226,6 @@ class Subflow extends Flow {
|
||||
this.node._updateWires(subflowInstanceConfig.wires);
|
||||
} else {
|
||||
var node = self.node_map[wires[j].id];
|
||||
modifiedNodes[node.id] = node;
|
||||
if (!node._originalWires) {
|
||||
node._originalWires = clone(node.wires);
|
||||
}
|
||||
@@ -189,9 +234,72 @@ class Subflow extends Flow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.subflowDef.status) {
|
||||
var subflowStatusId = this.statusNode.id;
|
||||
wires = this.subflowDef.status.wires;
|
||||
for (var j=0;j<wires.length;j++) {
|
||||
if (wires[j].id === this.subflowDef.id) {
|
||||
// A subflow input wired straight to a subflow output
|
||||
subflowInstanceConfig.wires[wires[j].port].push(subflowStatusId);
|
||||
this.node._updateWires(subflowInstanceConfig.wires);
|
||||
} else {
|
||||
var node = self.node_map[wires[j].id];
|
||||
if (!node._originalWires) {
|
||||
node._originalWires = clone(node.wires);
|
||||
}
|
||||
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
|
||||
node.wires[wires[j].port].push(subflowStatusId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.start(diff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get environment variable of subflow
|
||||
* @param {String} name name of env var
|
||||
* @return {Object} val value of env var
|
||||
*/
|
||||
getSetting(name) {
|
||||
var env = this.env;
|
||||
if (env && env.hasOwnProperty(name)) {
|
||||
var val = env[name];
|
||||
try {
|
||||
var ret = redUtil.evaluateNodeProperty(val.value, val.type, this.node, null, null);
|
||||
return ret;
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
var parent = this.parent;
|
||||
if (parent) {
|
||||
var val = parent.getSetting(name);
|
||||
return val;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a node instance from this subflow.
|
||||
* If the subflow has a status node, check for that, otherwise use
|
||||
* the super-class function
|
||||
* @param {String} id [description]
|
||||
* @param {Boolean} cancelBubble if true, prevents the flow from passing the request to the parent
|
||||
* This stops infinite loops when the parent asked this Flow for the
|
||||
* node to begin with.
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getNode(id, cancelBubble) {
|
||||
if (this.statusNode && this.statusNode.id === id) {
|
||||
return this.statusNode;
|
||||
}
|
||||
return super.getNode(id,cancelBubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a status event from a node within this flow.
|
||||
* @param {Node} node The original node that triggered the event
|
||||
@@ -205,10 +313,14 @@ class Subflow extends Flow {
|
||||
handleStatus(node,statusMessage,reportingNode,muteStatus) {
|
||||
let handled = super.handleStatus(node,statusMessage,reportingNode,muteStatus);
|
||||
if (!handled) {
|
||||
// No status node on this subflow caught the status message.
|
||||
// Pass up to the parent with this subflow's instance as the
|
||||
// reporting node
|
||||
handled = this.parent.handleStatus(node,statusMessage,this.node,true);
|
||||
if (!this.statusNode || node === this.node) {
|
||||
// No status node on this subflow caught the status message.
|
||||
// AND there is no Subflow Status node - so the user isn't
|
||||
// wanting to manage status messages themselves
|
||||
// Pass up to the parent with this subflow's instance as the
|
||||
// reporting node
|
||||
handled = this.parent.handleStatus(node,statusMessage,this.node,true);
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
|
||||
@@ -234,7 +346,6 @@ class Subflow extends Flow {
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -70,6 +70,7 @@ function init(runtime) {
|
||||
typeEventRegistered = true;
|
||||
}
|
||||
Flow.init(runtime);
|
||||
flowUtil.init(runtime);
|
||||
}
|
||||
|
||||
function loadFlows() {
|
||||
@@ -207,11 +208,11 @@ function setFlows(_config,type,muteLog,forceStart) {
|
||||
function getNode(id) {
|
||||
var node;
|
||||
if (activeNodesToFlow[id] && activeFlows[activeNodesToFlow[id]]) {
|
||||
return activeFlows[activeNodesToFlow[id]].getNode(id);
|
||||
return activeFlows[activeNodesToFlow[id]].getNode(id,true);
|
||||
}
|
||||
for (var flowId in activeFlows) {
|
||||
if (activeFlows.hasOwnProperty(flowId)) {
|
||||
node = activeFlows[flowId].getNode(id);
|
||||
node = activeFlows[flowId].getNode(id,true);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
@@ -388,14 +389,14 @@ function stop(type,diff,muteLog) {
|
||||
if (activeFlows.hasOwnProperty(id)) {
|
||||
var flowStateChanged = diff && (diff.added.indexOf(id) !== -1 || diff.removed.indexOf(id) !== -1);
|
||||
log.debug("red/nodes/flows.stop : stopping flow : "+id);
|
||||
promises = promises.concat(activeFlows[id].stop(flowStateChanged?null:stopList,removedList));
|
||||
promises.push(activeFlows[id].stop(flowStateChanged?null:stopList,removedList));
|
||||
if (type === "full" || flowStateChanged || diff.removed.indexOf(id)!==-1) {
|
||||
delete activeFlows[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve(promises).then(function() {
|
||||
return Promise.all(promises).then(function() {
|
||||
for (id in activeNodesToFlow) {
|
||||
if (activeNodesToFlow.hasOwnProperty(id)) {
|
||||
if (!activeFlows[activeNodesToFlow[id]]) {
|
||||
@@ -676,7 +677,7 @@ const flowAPI = {
|
||||
getNode: getNode,
|
||||
handleError: () => false,
|
||||
handleStatus: () => false,
|
||||
getSetting: k => process.env[k]
|
||||
getSetting: k => flowUtil.getEnvVar(k)
|
||||
}
|
||||
|
||||
|
||||
|
@@ -19,6 +19,8 @@ var Log = require("@node-red/util").log;
|
||||
var subflowInstanceRE = /^subflow:(.+)$/;
|
||||
var typeRegistry = require("@node-red/registry");
|
||||
|
||||
var envVarExcludes = {};
|
||||
|
||||
function diffNodes(oldNode,newNode) {
|
||||
if (oldNode == null) {
|
||||
return true;
|
||||
@@ -52,12 +54,8 @@ function mapEnvVarProperties(obj,prop,flow) {
|
||||
} else if (typeof obj[prop] === 'string') {
|
||||
if (obj[prop][0] === "$" && (EnvVarPropertyRE_old.test(v) || EnvVarPropertyRE.test(v)) ) {
|
||||
var envVar = v.substring(2,v.length-1);
|
||||
if (!flow) {
|
||||
obj[prop] = process.env.hasOwnProperty(envVar)?process.env[envVar]:v;
|
||||
} else {
|
||||
var r = flow.getSetting(envVar);
|
||||
obj[prop] = r!==undefined?r:obj[prop];
|
||||
}
|
||||
var r = flow.getSetting(envVar);
|
||||
obj[prop] = r!==undefined?r:obj[prop];
|
||||
}
|
||||
} else {
|
||||
for (var p in v) {
|
||||
@@ -69,7 +67,15 @@ function mapEnvVarProperties(obj,prop,flow) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
init: function(runtime) {
|
||||
envVarExcludes = {};
|
||||
if (runtime.settings.hasOwnProperty('envVarExcludes') && Array.isArray(runtime.settings.envVarExcludes)) {
|
||||
runtime.settings.envVarExcludes.forEach(v => envVarExcludes[v] = true);
|
||||
}
|
||||
},
|
||||
getEnvVar: function(k) {
|
||||
return !envVarExcludes[k]?process.env[k]:undefined
|
||||
},
|
||||
diffNodes: diffNodes,
|
||||
mapEnvVarProperties: mapEnvVarProperties,
|
||||
|
||||
|
@@ -53,6 +53,7 @@ function getGitUser(user) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function Project(path) {
|
||||
this.path = path;
|
||||
this.name = fspath.basename(path);
|
||||
@@ -72,7 +73,7 @@ Project.prototype.load = function () {
|
||||
projectSettings = globalProjectSettings.projects[this.name] || {};
|
||||
}
|
||||
}
|
||||
|
||||
this.paths.root = projectSettings.rootPath || "";
|
||||
this.credentialSecret = projectSettings.credentialSecret;
|
||||
this.git = projectSettings.git || { user:{} };
|
||||
|
||||
@@ -83,14 +84,15 @@ Project.prototype.load = function () {
|
||||
return checkProjectFiles(project).then(function(missingFiles) {
|
||||
project.missingFiles = missingFiles;
|
||||
if (missingFiles.indexOf('package.json') === -1) {
|
||||
project.paths['package.json'] = fspath.join(project.path,"package.json");
|
||||
promises.push(fs.readFile(project.paths['package.json'],"utf8").then(function(content) {
|
||||
// We have a package.json in project.path+project.paths.root+"package.json"
|
||||
project.paths['package.json'] = fspath.join(project.paths.root,"package.json");
|
||||
promises.push(fs.readFile(fspath.join(project.path,project.paths['package.json']),"utf8").then(function(content) {
|
||||
try {
|
||||
project.package = util.parseJSON(content);
|
||||
if (project.package.hasOwnProperty('node-red')) {
|
||||
if (project.package['node-red'].hasOwnProperty('settings')) {
|
||||
project.paths.flowFile = project.package['node-red'].settings.flowFile;
|
||||
project.paths.credentialsFile = project.package['node-red'].settings.credentialsFile;
|
||||
project.paths.flowFile = fspath.join(project.paths.root,project.package['node-red'].settings.flowFile);
|
||||
project.paths.credentialsFile = fspath.join(project.paths.root,project.package['node-red'].settings.credentialsFile);
|
||||
}
|
||||
} else {
|
||||
// TODO: package.json doesn't have a node-red section
|
||||
@@ -101,17 +103,19 @@ Project.prototype.load = function () {
|
||||
project.package = {};
|
||||
}
|
||||
}));
|
||||
if (missingFiles.indexOf('README.md') === -1) {
|
||||
project.paths['README.md'] = fspath.join(project.paths.root,"README.md");
|
||||
promises.push(fs.readFile(fspath.join(project.path,project.paths['README.md']),"utf8").then(function(content) {
|
||||
project.description = content;
|
||||
}));
|
||||
} else {
|
||||
project.description = "";
|
||||
}
|
||||
} else {
|
||||
project.package = {};
|
||||
}
|
||||
if (missingFiles.indexOf('README.md') === -1) {
|
||||
project.paths['README.md'] = fspath.join(project.path,"README.md");
|
||||
promises.push(fs.readFile(project.paths['README.md'],"utf8").then(function(content) {
|
||||
project.description = content;
|
||||
}));
|
||||
} else {
|
||||
project.description = "";
|
||||
}
|
||||
|
||||
// if (missingFiles.indexOf('flow.json') !== -1) {
|
||||
// console.log("MISSING FLOW FILE");
|
||||
// } else {
|
||||
@@ -224,6 +228,7 @@ Project.prototype.parseRemoteBranch = function (remoteBranch) {
|
||||
Project.prototype.isEmpty = function () {
|
||||
return this.empty;
|
||||
};
|
||||
|
||||
Project.prototype.isMerging = function() {
|
||||
return this.merging;
|
||||
}
|
||||
@@ -243,6 +248,7 @@ Project.prototype.update = function (user, data) {
|
||||
var savePackage = false;
|
||||
var flowFilesChanged = false;
|
||||
var credentialSecretChanged = false;
|
||||
var reloadProject = false;
|
||||
|
||||
var globalProjectSettings = settings.get("projects");
|
||||
if (!globalProjectSettings.projects.hasOwnProperty(this.name)) {
|
||||
@@ -250,7 +256,6 @@ Project.prototype.update = function (user, data) {
|
||||
saveSettings = true;
|
||||
}
|
||||
|
||||
|
||||
if (data.credentialSecret && data.credentialSecret !== this.credentialSecret) {
|
||||
var existingSecret = data.currentCredentialSecret;
|
||||
var isReset = data.resetCredentialSecret;
|
||||
@@ -278,6 +283,54 @@ Project.prototype.update = function (user, data) {
|
||||
credentialSecretChanged = true;
|
||||
}
|
||||
|
||||
if (this.missingFiles.indexOf('package.json') !== -1) {
|
||||
if (!data.files || !data.files.package) {
|
||||
// Cannot update a project that doesn't have a known package.json
|
||||
return Promise.reject("Cannot update project with missing package.json");
|
||||
}
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty('files')) {
|
||||
this.package['node-red'] = this.package['node-red'] || { settings: {}};
|
||||
if (data.files.hasOwnProperty('package') && data.files.package !== fspath.join(this.paths.root,"package.json")) {
|
||||
// We have a package file. It could be one that doesn't exist yet,
|
||||
// or it does exist and we need to load it.
|
||||
if (!/package\.json$/.test(data.files.package)) {
|
||||
return Promise.reject("Invalid package file: "+data.files.package)
|
||||
}
|
||||
var root = data.files.package.substring(0,data.files.package.length-12);
|
||||
this.paths.root = root;
|
||||
this.paths['package.json'] = data.files.package;
|
||||
globalProjectSettings.projects[this.name].rootPath = root;
|
||||
saveSettings = true;
|
||||
// 1. check if it exists
|
||||
if (fs.existsSync(fspath.join(this.path,this.paths['package.json']))) {
|
||||
// Load the existing one....
|
||||
} else {
|
||||
var newPackage = defaultFileSet["package.json"](this);
|
||||
fs.writeFileSync(fspath.join(this.path,this.paths['package.json']),newPackage);
|
||||
this.package = JSON.parse(newPackage);
|
||||
}
|
||||
reloadProject = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
|
||||
if (data.files.hasOwnProperty('flow') && this.package['node-red'].settings.flowFile !== data.files.flow.substring(this.paths.root.length)) {
|
||||
this.paths.flowFile = data.files.flow;
|
||||
this.package['node-red'].settings.flowFile = data.files.flow.substring(this.paths.root.length);
|
||||
savePackage = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
if (data.files.hasOwnProperty('credentials') && this.package['node-red'].settings.credentialsFile !== data.files.credentials.substring(this.paths.root.length)) {
|
||||
this.paths.credentialsFile = data.files.credentials;
|
||||
this.package['node-red'].settings.credentialsFile = data.files.credentials.substring(this.paths.root.length);
|
||||
// Don't know if the credSecret is invalid or not so clear the flag
|
||||
delete this.credentialSecretInvalid;
|
||||
savePackage = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty('description')) {
|
||||
saveREADME = true;
|
||||
this.description = data.description;
|
||||
@@ -333,47 +386,32 @@ Project.prototype.update = function (user, data) {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty('files')) {
|
||||
this.package['node-red'] = this.package['node-red'] || { settings: {}};
|
||||
if (data.files.hasOwnProperty('flow') && this.package['node-red'].settings.flowFile !== data.files.flow) {
|
||||
this.paths.flowFile = data.files.flow;
|
||||
this.package['node-red'].settings.flowFile = data.files.flow;
|
||||
savePackage = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
if (data.files.hasOwnProperty('credentials') && this.package['node-red'].settings.credentialsFile !== data.files.credentials) {
|
||||
this.paths.credentialsFile = data.files.credentials;
|
||||
this.package['node-red'].settings.credentialsFile = data.files.credentials;
|
||||
// Don't know if the credSecret is invalid or not so clear the flag
|
||||
delete this.credentialSecretInvalid;
|
||||
|
||||
savePackage = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
}
|
||||
if (saveSettings) {
|
||||
promises.push(settings.set("projects",globalProjectSettings));
|
||||
}
|
||||
if (saveREADME) {
|
||||
promises.push(util.writeFile(this.paths['README.md'], this.description));
|
||||
promises.push(util.writeFile(fspath.join(this.path,this.paths['README.md']), this.description));
|
||||
}
|
||||
if (savePackage) {
|
||||
promises.push(fs.readFile(project.paths['package.json'],"utf8").then(content => {
|
||||
promises.push(fs.readFile(fspath.join(project.path,project.paths['package.json']),"utf8").then(content => {
|
||||
var currentPackage = {};
|
||||
try {
|
||||
currentPackage = util.parseJSON(content);
|
||||
} catch(err) {
|
||||
}
|
||||
this.package = Object.assign(currentPackage,this.package);
|
||||
return util.writeFile(this.paths['package.json'], JSON.stringify(this.package,"",4));
|
||||
return util.writeFile(fspath.join(project.path,this.paths['package.json']), JSON.stringify(this.package,"",4));
|
||||
}));
|
||||
}
|
||||
return when.settle(promises).then(function(res) {
|
||||
return {
|
||||
return when.settle(promises).then(res => {
|
||||
if (reloadProject) {
|
||||
return this.load()
|
||||
}
|
||||
}).then(() => { return {
|
||||
flowFilesChanged: flowFilesChanged,
|
||||
credentialSecretChanged: credentialSecretChanged
|
||||
}
|
||||
})
|
||||
}})
|
||||
};
|
||||
|
||||
Project.prototype.getFiles = function () {
|
||||
@@ -384,12 +422,15 @@ Project.prototype.getFiles = function () {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype.stageFile = function(file) {
|
||||
return gitTools.stageFile(this.path,file);
|
||||
};
|
||||
|
||||
Project.prototype.unstageFile = function(file) {
|
||||
return gitTools.unstageFile(this.path,file);
|
||||
}
|
||||
|
||||
Project.prototype.commit = function(user, options) {
|
||||
var self = this;
|
||||
return gitTools.commit(this.path,options.message,getGitUser(user)).then(function() {
|
||||
@@ -399,9 +440,11 @@ Project.prototype.commit = function(user, options) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Project.prototype.getFileDiff = function(file,type) {
|
||||
return gitTools.getFileDiff(this.path,file,type);
|
||||
}
|
||||
|
||||
Project.prototype.getCommits = function(options) {
|
||||
return gitTools.getCommits(this.path,options).catch(function(err) {
|
||||
if (/bad default revision/i.test(err.message) || /ambiguous argument/i.test(err.message) || /does not have any commits yet/i.test(err.message)) {
|
||||
@@ -414,9 +457,11 @@ Project.prototype.getCommits = function(options) {
|
||||
throw err;
|
||||
})
|
||||
}
|
||||
|
||||
Project.prototype.getCommit = function(sha) {
|
||||
return gitTools.getCommit(this.path,sha);
|
||||
}
|
||||
|
||||
Project.prototype.getFile = function (filePath,treeish) {
|
||||
if (treeish !== "_") {
|
||||
return gitTools.getFile(this.path, filePath, treeish);
|
||||
@@ -424,6 +469,7 @@ Project.prototype.getFile = function (filePath,treeish) {
|
||||
return fs.readFile(fspath.join(this.path,filePath),"utf8");
|
||||
}
|
||||
};
|
||||
|
||||
Project.prototype.revertFile = function (filePath) {
|
||||
var self = this;
|
||||
return gitTools.revertFile(this.path, filePath).then(function() {
|
||||
@@ -431,8 +477,6 @@ Project.prototype.revertFile = function (filePath) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
Project.prototype.status = function(user, includeRemote) {
|
||||
var self = this;
|
||||
|
||||
@@ -459,7 +503,7 @@ Project.prototype.status = function(user, includeRemote) {
|
||||
gitTools.getStatus(self.path),
|
||||
fs.exists(fspath.join(self.path,".git","MERGE_HEAD"))
|
||||
];
|
||||
return when.all(promises).then(function(results) {
|
||||
return Promise.all(promises).then(function(results) {
|
||||
var result = results[0];
|
||||
if (results[1]) {
|
||||
result.merging = true;
|
||||
@@ -615,6 +659,7 @@ Project.prototype.resolveMerge = function (file,resolutions) {
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype.abortMerge = function () {
|
||||
var self = this;
|
||||
return gitTools.abortMerge(this.path).then(function() {
|
||||
@@ -675,12 +720,11 @@ Project.prototype.setBranch = function (branchName, isCreate) {
|
||||
return self.load();
|
||||
})
|
||||
};
|
||||
|
||||
Project.prototype.getBranchStatus = function (branchName) {
|
||||
return gitTools.getBranchStatus(this.path,branchName);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Project.prototype.getRemotes = function (user) {
|
||||
return gitTools.getRemotes(this.path).then(function(remotes) {
|
||||
var result = [];
|
||||
@@ -693,12 +737,14 @@ Project.prototype.getRemotes = function (user) {
|
||||
return {remotes:result};
|
||||
})
|
||||
};
|
||||
|
||||
Project.prototype.addRemote = function(user,remote,options) {
|
||||
var project = this;
|
||||
return gitTools.addRemote(this.path,remote,options).then(function() {
|
||||
return project.loadRemotes()
|
||||
});
|
||||
}
|
||||
|
||||
Project.prototype.updateRemote = function(user,remote,options) {
|
||||
var username;
|
||||
if (!user) {
|
||||
@@ -716,6 +762,7 @@ Project.prototype.updateRemote = function(user,remote,options) {
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
Project.prototype.removeRemote = function(user, remote) {
|
||||
// TODO: if this was the last remote using this url, then remove the authCache
|
||||
// details.
|
||||
@@ -725,7 +772,6 @@ Project.prototype.removeRemote = function(user, remote) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Project.prototype.getFlowFile = function() {
|
||||
// console.log("Project.getFlowFile = ",this.paths.flowFile);
|
||||
if (this.paths.flowFile) {
|
||||
@@ -742,6 +788,7 @@ Project.prototype.getFlowFileBackup = function() {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Project.prototype.getCredentialsFile = function() {
|
||||
// console.log("Project.getCredentialsFile = ",this.paths.credentialsFile);
|
||||
if (this.paths.credentialsFile) {
|
||||
@@ -750,6 +797,7 @@ Project.prototype.getCredentialsFile = function() {
|
||||
return this.paths.credentialsFile;
|
||||
}
|
||||
}
|
||||
|
||||
Project.prototype.getCredentialsFileBackup = function() {
|
||||
return getBackupFilename(this.getCredentialsFile());
|
||||
}
|
||||
@@ -763,10 +811,11 @@ Project.prototype.export = function () {
|
||||
dependencies: this.package.dependencies||{},
|
||||
empty: this.empty,
|
||||
settings: {
|
||||
credentialsEncrypted: (typeof this.credentialSecret === "string"),
|
||||
credentialsEncrypted: (typeof this.credentialSecret === "string") && this.credentialSecret.length > 0,
|
||||
credentialSecretInvalid: this.credentialSecretInvalid
|
||||
},
|
||||
files: {
|
||||
package: this.paths['package.json'],
|
||||
flow: this.paths.flowFile,
|
||||
credentials: this.paths.credentialsFile
|
||||
},
|
||||
@@ -777,7 +826,6 @@ Project.prototype.export = function () {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function getCredentialsFilename(filename) {
|
||||
filename = filename || "undefined";
|
||||
// TODO: DRY - ./index.js
|
||||
@@ -793,7 +841,6 @@ function getBackupFilename(filename) {
|
||||
var ffDir = fspath.dirname(filename);
|
||||
return fspath.join(ffDir,"."+ffName+".backup");
|
||||
}
|
||||
|
||||
function checkProjectExists(projectPath) {
|
||||
return fs.pathExists(projectPath).then(function(exists) {
|
||||
if (!exists) {
|
||||
@@ -805,7 +852,6 @@ function checkProjectExists(projectPath) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createDefaultProject(user, project) {
|
||||
var projectPath = fspath.join(projectsDir,project.name);
|
||||
// Create a basic skeleton of a project
|
||||
@@ -869,15 +915,13 @@ function createDefaultProject(user, project) {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function checkProjectFiles(project) {
|
||||
var projectPath = project.path;
|
||||
var promises = [];
|
||||
var paths = [];
|
||||
for (var file in defaultFileSet) {
|
||||
if (defaultFileSet.hasOwnProperty(file)) {
|
||||
paths.push(file);
|
||||
promises.push(fs.stat(fspath.join(projectPath,file)));
|
||||
promises.push(fs.stat(fspath.join(project.path,project.paths.root,file)));
|
||||
}
|
||||
}
|
||||
return when.settle(promises).then(function(results) {
|
||||
@@ -900,7 +944,6 @@ function checkProjectFiles(project) {
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
function createProject(user, metadata) {
|
||||
var username;
|
||||
if (!user) {
|
||||
@@ -933,6 +976,9 @@ function createProject(user, metadata) {
|
||||
}
|
||||
projects.projects[project] = {};
|
||||
if (metadata.hasOwnProperty('credentialSecret')) {
|
||||
if (metadata.credentialSecret === "") {
|
||||
metadata.credentialSecret = false;
|
||||
}
|
||||
projects.projects[project].credentialSecret = metadata.credentialSecret;
|
||||
}
|
||||
return settings.set('projects',projects);
|
||||
@@ -970,7 +1016,6 @@ function createProject(user, metadata) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function deleteProject(user, projectPath) {
|
||||
return checkProjectExists(projectPath).then(function() {
|
||||
return fs.remove(projectPath).then(function() {
|
||||
@@ -981,14 +1026,12 @@ function deleteProject(user, projectPath) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadProject(projectPath) {
|
||||
return checkProjectExists(projectPath).then(function() {
|
||||
var project = new Project(projectPath);
|
||||
return project.load();
|
||||
});
|
||||
}
|
||||
|
||||
function init(_settings, _runtime) {
|
||||
settings = _settings;
|
||||
runtime = _runtime;
|
||||
|
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var when = require('when');
|
||||
|
||||
var exec = require("../../../../exec");
|
||||
|
||||
var authResponseServer = require('./authServer').ResponseServer;
|
||||
@@ -31,12 +29,12 @@ function runGitCommand(args,cwd,env,emit) {
|
||||
log.trace(gitCommand + JSON.stringify(args));
|
||||
args.unshift("credential.helper=")
|
||||
args.unshift("-c");
|
||||
return exec.run(gitCommand, args, {cwd:cwd, env:env}, emit).then(result => {
|
||||
return exec.run(gitCommand, args, {cwd:cwd, detached:true, env:env}, emit).then(result => {
|
||||
return result.stdout;
|
||||
}).catch(result => {
|
||||
var err = new Error(stderr);
|
||||
var stdout = result.stdout;
|
||||
var stderr = result.stderr;
|
||||
var err = new Error(stderr);
|
||||
err.stdout = stdout;
|
||||
err.stderr = stderr;
|
||||
if (/Connection refused/i.test(stderr)) {
|
||||
@@ -84,8 +82,12 @@ function runGitCommandWithAuth(args,cwd,auth,emit) {
|
||||
commandEnv.NODE_RED_GIT_NODE_PATH = process.execPath;
|
||||
commandEnv.NODE_RED_GIT_SOCK_PATH = rs.path;
|
||||
commandEnv.NODE_RED_GIT_ASKPASS_PATH = path.join(__dirname,"authWriter.js");
|
||||
return runGitCommand(args,cwd,commandEnv,emit).finally(function() {
|
||||
return runGitCommand(args,cwd,commandEnv,emit).then( result => {
|
||||
rs.close();
|
||||
return result;
|
||||
}).catch(err => {
|
||||
rs.close();
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
}
|
||||
@@ -104,8 +106,12 @@ function runGitCommandWithSSHCommand(args,cwd,auth,emit) {
|
||||
// GIT_SSH_COMMAND - added in git 2.3.0
|
||||
commandEnv.GIT_SSH_COMMAND = "ssh -i " + auth.key_path + " -F /dev/null";
|
||||
// console.log('commandEnv:', commandEnv);
|
||||
return runGitCommand(args,cwd,commandEnv,emit).finally(function() {
|
||||
return runGitCommand(args,cwd,commandEnv,emit).then( result => {
|
||||
rs.close();
|
||||
return result;
|
||||
}).catch(err => {
|
||||
rs.close();
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
}
|
||||
@@ -362,7 +368,7 @@ function getBranchStatus(cwd,remoteBranch) {
|
||||
// #commits master behind
|
||||
runGitCommand(['rev-list', '^HEAD',remoteBranch, '--count'],cwd)
|
||||
];
|
||||
return when.all(commands).then(function(results) {
|
||||
return Promise.all(commands).then(function(results) {
|
||||
return {
|
||||
commits: {
|
||||
ahead: parseInt(results[0]),
|
||||
@@ -589,7 +595,7 @@ module.exports = {
|
||||
runGitCommand(['rev-list', 'HEAD', '--count'],cwd),
|
||||
runGitCommand(args,cwd).then(parseLog)
|
||||
];
|
||||
return when.all(commands).then(function(results) {
|
||||
return Promise.all(commands).then(function(results) {
|
||||
var result = results[0];
|
||||
result.count = results[1].length;
|
||||
result.before = before;
|
||||
|
167
packages/node_modules/@node-red/runtime/locales/ko/runtime.json
vendored
Executable file
167
packages/node_modules/@node-red/runtime/locales/ko/runtime.json
vendored
Executable file
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"runtime": {
|
||||
"welcome": "Node-RED에 오신것을 환영합니다.",
|
||||
"version": "__component__ 버전: __version__",
|
||||
"unsupported_version": "__component__는 지원하지 않는 버전입니다. 요구버전: __requires__ 현재버전: __version__",
|
||||
"paths": {
|
||||
"settings": "설정 파일 : __path__",
|
||||
"httpStatic": "HTTP Static : __path__"
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"loading": "팔렛트 노드 읽는 중",
|
||||
"palette-editor": {
|
||||
"disabled": "팔렛트 에디터 사용불가 : 사용자 설정",
|
||||
"npm-not-found": "팔렛트 에디터 사용불가 : npm 명령어가 없습니다.",
|
||||
"npm-too-old": "팔렛트 에디터 사용불가 : npm 버전이 너무 오래되었습니다. 3.x이상의 npm을 사용하세요."
|
||||
},
|
||||
"errors": "__count__개의 노드타입 등록 에러",
|
||||
"errors_plural": "__count__개의 노드타입 등록 에러",
|
||||
"errors-help": "-v 를 실행하여 상세내역을 확인하세요",
|
||||
"missing-modules": "노드모듈이 없습니다:",
|
||||
"node-version-mismatch": "버전이 잘못 되었습니다. 요구버전: __version__ ",
|
||||
"type-already-registered": "'__type__' 은 __module__ 으로 이미 등록되어 있습니다.",
|
||||
"removing-modules": "설정에서 모듈 제거중",
|
||||
"added-types": "노드타입 추가:",
|
||||
"removed-types": "노드타입 제거:",
|
||||
"install": {
|
||||
"invalid": "잘못된 모듈명",
|
||||
"installing": "모듈 설치중: __name__, 버전: __version__",
|
||||
"installed": "모듈이 설치되었습니다: __name__",
|
||||
"install-failed": "설치 실패",
|
||||
"install-failed-long": "__name__ 모듈 설치 실패:",
|
||||
"install-failed-not-found": "$t(install-failed-long) 모듈이 없습니다.",
|
||||
"upgrading": "모듈 업그레이드: __name__ to 버전: __version__",
|
||||
"upgraded": "모듈 업그레이드: __name__. 새 버전을 사용하기 위해 Node-RED를 재시작 합니다.",
|
||||
"upgrade-failed-not-found": "$t(server.install.install-failed-long) 버전이 없습니다.",
|
||||
"uninstalling": "모듈 제거중: __name__",
|
||||
"uninstall-failed": "제거 실패",
|
||||
"uninstall-failed-long": "__name__ 모듈 제거 실패:",
|
||||
"uninstalled": "모듈 제거: __name__"
|
||||
},
|
||||
"unable-to-listen": "__listenpath__에서 listen 할 수 없습니다.",
|
||||
"port-in-use": "에러: 포트 사용중",
|
||||
"uncaught-exception": "Uncaught Exception:",
|
||||
"admin-ui-disabled": "관리 UI 비활성화",
|
||||
"now-running": "__listenpath__에서 서버가 실행중 입니다.",
|
||||
"failed-to-start": "서버시작 실패:",
|
||||
"headless-mode": "headless 모드로 실행중입니다.",
|
||||
"httpadminauth-deprecated": "httpAdminAuth는 더 이상 사용되지 않습니다. adminAuth를 사용하세요."
|
||||
},
|
||||
"api": {
|
||||
"flows": {
|
||||
"error-save": "플로우 저장 에러: __message__",
|
||||
"error-reload": "플로우 새로고침 에러: __message__"
|
||||
},
|
||||
"library": {
|
||||
"error-load-entry": "라이브러리 '__path__'불러오기 에러: __message__",
|
||||
"error-save-entry": "라이브러리 '__path__'저장 에러: __message__",
|
||||
"error-load-flow": "플로우 '__path__'불러오기 에러: __message__",
|
||||
"error-save-flow": "플로우 '__path__'저장 에러: __message__"
|
||||
},
|
||||
"nodes": {
|
||||
"enabled": "노드타입 활성화:",
|
||||
"disabled": "노드타입 비활성화:",
|
||||
"error-enable": "노드 활성화 에러:"
|
||||
}
|
||||
},
|
||||
"comms": {
|
||||
"error": "통신채널 에러: __message__",
|
||||
"error-server": "통신서버 에러: __message__",
|
||||
"error-send": "전송 에러: __message__"
|
||||
},
|
||||
"settings": {
|
||||
"user-not-available": "사용자 설정을 저장할수 없습니다: __message__",
|
||||
"not-available": "설정을 사용할 수 없습니다.",
|
||||
"property-read-only": "'__prop__' 속성은 읽기 전용입니다."
|
||||
},
|
||||
"nodes": {
|
||||
"credentials": {
|
||||
"error": "인증정보 읽어오기 에러: __message__",
|
||||
"error-saving": "인증정보 저장 에러: __message__",
|
||||
"not-registered": "인증정보 '__type__'는 등록되어 있지않습니다.",
|
||||
"system-key-warning": "\n\n---------------------------------------------------------------------\n 시스템에서 생성한 키를 사용하여 플로우 자격증명 파일이 암호화되어 있습니다. \n\n 만일 시스템 생성 키가 어떤 이유로든 손실되면 자격증명파일을\n 복구 할 수 없습니다. 그러한 경우엔 삭제하고 자격증명을 다시 \n 입력해야 합니다.\n\n 'credentialSecret' 옵션을 사용하여 자신의 키를 설정해야 합니다. \n Node-RED는 변경내용을 다음 배포시에 선택한 키를 사용하여 \n 자격증명파일을 다시 암호화합니다.\n---------------------------------------------------------------------\n"
|
||||
},
|
||||
"flows": {
|
||||
"safe-mode": "[안전모드] 플로우가 정지되었습니다. 시작하려면 배포하세요.",
|
||||
"registered-missing": "누락된 노드를 등록합니다: __type__",
|
||||
"error": "플로우 불러오기 에러: __message__",
|
||||
"starting-modified-nodes": "수정된 노드 시작중",
|
||||
"starting-modified-flows": "수정된 플로우 시작중",
|
||||
"starting-flows": "플로우 시작중",
|
||||
"started-modified-nodes": "수정된 노드 시작됨",
|
||||
"started-modified-flows": "수정된 플로우 시작됨",
|
||||
"started-flows": "플로우 시작됨",
|
||||
"stopping-modified-nodes": "수정된 노드 중지중",
|
||||
"stopping-modified-flows": "수정된 플로우 중지중",
|
||||
"stopping-flows": "플로우 중지중",
|
||||
"stopped-modified-nodes": "수정된 노드 중지됨",
|
||||
"stopped-modified-flows": "수정된 플로우 중지됨",
|
||||
"stopped-flows": "플로우 중지됨",
|
||||
"stopped": "중지됨",
|
||||
"stopping-error": "노드 중지 오류: __message__",
|
||||
"added-flow": "플로우 추가: __label__",
|
||||
"updated-flow": "플로우 변경: __label__",
|
||||
"removed-flow": "플로우 삭제: __label__",
|
||||
"missing-types": "누락된 플로우타입이 등록되기를 기다림:",
|
||||
"missing-type-provided": " - __type__ (provided by npm module __module__)",
|
||||
"missing-type-install-1": "누락된 모듈을 설치하려면, 실행:",
|
||||
"missing-type-install-2": "디렉토리에서:"
|
||||
},
|
||||
"flow": {
|
||||
"unknown-type": "알수없는 타입: __type__",
|
||||
"missing-types": "누락된 타입",
|
||||
"error-loop": "메세지 최대 캐치수를 초과했습니다."
|
||||
},
|
||||
"index": {
|
||||
"unrecognised-id": "인식할 수 없는 ID: __id__",
|
||||
"type-in-use": "사용하는 타입: __msg__",
|
||||
"unrecognised-module": "인식할 수 없는 모듈: __module__"
|
||||
},
|
||||
"registry": {
|
||||
"localfilesystem": {
|
||||
"module-not-found": "'__module__' 모듈을 찾을 수 없습니다."
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage": {
|
||||
"index": {
|
||||
"forbidden-flow-name": "올바르지 않은 플로우명"
|
||||
},
|
||||
"localfilesystem": {
|
||||
"user-dir": "사용자 디렉토리: __path__",
|
||||
"flows-file": "플로우 파일 : __path__",
|
||||
"create": "새로운 __type__ 파일 만듭니다.",
|
||||
"empty": "기존 __type__ 파일이 비어있습니다.",
|
||||
"invalid": "기존 __type__ 파일이 json형식이 아닙니다.",
|
||||
"restore": "__type__ 파일을 __path__ 에서 복원합니다.",
|
||||
"restore-fail": "__type__ 파일 복원 실패 : __message__",
|
||||
"fsync-fail": "__path__ 파일 디스크쓰기 실패 : __message__",
|
||||
"projects": {
|
||||
"changing-project": "프로젝트 설정: __project__",
|
||||
"active-project": "선택중인 프로젝트: __project__",
|
||||
"project-not-found": "프로젝트가 없습니다: __project__",
|
||||
"no-active-project": "선택된 프로젝트가 없습니다: 기본 플로우 파일을 사용합니다.",
|
||||
"disabled": "프로젝트가 비활성화 되어있습니다: editorTheme.projects.enabled=false",
|
||||
"disabledNoFlag": "프로젝트가 비활성화 되어있습니다: set editorTheme.projects.enabled=true to enable",
|
||||
"git-not-found": "프로젝트가 비활성화 되어있습니다: git 명령어가 없습니다.",
|
||||
"git-version-old": "프로젝트가 비활성화 되어있습니다: git __version__ 을 지원하지 않습니다. 2.x가 요구됩니다.",
|
||||
"summary": "Node-RED 프로젝트",
|
||||
"readme": "### 설명\n\n 이것은 프로젝트 README.md 파일입니다. 이 파일에는 프로젝트의 설명, \n 이용방법, 그 외 정보를 기재합니다."
|
||||
}
|
||||
}
|
||||
},
|
||||
"context": {
|
||||
"log-store-init": "Context 저장소 : '__name__' [__info__]",
|
||||
"error-loading-module": "context 저장소 불러오기 에러: __message__",
|
||||
"error-loading-module2": "context 저장소 불러오기 에러 '__module__': __message__ ",
|
||||
"error-module-not-defined": "Context 저장소 '__storage__'에 'module'옵션이 지정되지 않았습니다.",
|
||||
"error-invalid-module-name": "context 저장소 이름 에러: '__name__'",
|
||||
"error-invalid-default-module": "기본 context 저장소가 없음: '__storage__'",
|
||||
"unknown-store": "알 수 없는 context 저장소 '__name__' 가 지정되었습니다. 기본 저장소를 사용합니다.",
|
||||
"localfilesystem": {
|
||||
"error-circular": "Context __scope__ 는 지속할 수 없는 순환참조를 포함합니다.",
|
||||
"error-write": "context 저장 에러: __message__"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "0.20.0-beta.4",
|
||||
"@node-red/util": "0.20.0-beta.4",
|
||||
"@node-red/registry": "0.20.2",
|
||||
"@node-red/util": "0.20.2",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.16.4",
|
||||
"fs-extra": "7.0.1",
|
||||
|
44
packages/node_modules/@node-red/util/lib/util.js
vendored
44
packages/node_modules/@node-red/util/lib/util.js
vendored
@@ -413,6 +413,23 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get value of environment variable.
|
||||
* @param {Node} node - accessing node
|
||||
* @param {String} name - name of variable
|
||||
* @return {String} value of env var
|
||||
*/
|
||||
function getSetting(node, name) {
|
||||
if (node && node._flow) {
|
||||
var flow = node._flow;
|
||||
if (flow) {
|
||||
return flow.getSetting(name);
|
||||
}
|
||||
}
|
||||
return process.env[name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a String contains any Environment Variable specifiers and returns
|
||||
* it with their values substituted in place.
|
||||
@@ -420,24 +437,28 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
||||
* For example, if the env var `WHO` is set to `Joe`, the string `Hello ${WHO}!`
|
||||
* will return `Hello Joe!`.
|
||||
* @param {String} value - the string to parse
|
||||
* @param {Node} node - the node evaluating the property
|
||||
* @return {String} The parsed string
|
||||
* @memberof @node-red/util_util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function evaluateEnvProperty(value) {
|
||||
function evaluateEnvProperty(value, node) {
|
||||
var result;
|
||||
if (/^\${[^}]+}$/.test(value)) {
|
||||
// ${ENV_VAR}
|
||||
value = value.substring(2,value.length-1);
|
||||
value = process.env.hasOwnProperty(value)?process.env[value]:""
|
||||
var name = value.substring(2,value.length-1);
|
||||
result = getSetting(node, name);
|
||||
} else if (!/\${\S+}/.test(value)) {
|
||||
// ENV_VAR
|
||||
value = process.env.hasOwnProperty(value)?process.env[value]:""
|
||||
result = getSetting(node, value);
|
||||
} else {
|
||||
// FOO${ENV_VAR}BAR
|
||||
value = value.replace(/\${([^}]+)}/g, function(match, v) {
|
||||
return process.env.hasOwnProperty(v)?process.env[v]:""
|
||||
return value.replace(/\${([^}]+)}/g, function(match, name) {
|
||||
var val = getSetting(node, name);
|
||||
return (val === undefined)?"":val;
|
||||
});
|
||||
}
|
||||
return value;
|
||||
return (result === undefined)?"":result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -513,7 +534,7 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
||||
var expr = prepareJSONataExpression(value,node);
|
||||
result = evaluateJSONataExpression(expr,msg);
|
||||
} else if (type === 'env') {
|
||||
result = evaluateEnvProperty(value);
|
||||
result = evaluateEnvProperty(value, node);
|
||||
}
|
||||
if (callback) {
|
||||
callback(null,result);
|
||||
@@ -540,8 +561,9 @@ function prepareJSONataExpression(value,node) {
|
||||
expr.assign('globalContext',function(val) {
|
||||
return node.context().global.get(val);
|
||||
});
|
||||
expr.assign('env', function(val) {
|
||||
return process.env[val];
|
||||
expr.assign('env', function(name) {
|
||||
var val = getSetting(node, name);
|
||||
return (val ? val : "");
|
||||
})
|
||||
expr.registerFunction('clone', cloneMessage, '<(oa)-:o>');
|
||||
expr._legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(value);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"clone": "2.1.2",
|
||||
"i18next": "13.1.0",
|
||||
"i18next": "14.1.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.6.4",
|
||||
"when": "3.7.8"
|
||||
|
9
packages/node_modules/node-red/lib/red.js
vendored
9
packages/node_modules/node-red/lib/red.js
vendored
@@ -39,6 +39,9 @@ function checkVersion(userSettings) {
|
||||
* This module provides the full Node-RED application, with both the runtime
|
||||
* and editor components built in.
|
||||
*
|
||||
* The API this module exposes allows it to be embedded within another node.js
|
||||
* application.
|
||||
*
|
||||
* @namespace node-red
|
||||
*/
|
||||
module.exports = {
|
||||
@@ -125,7 +128,11 @@ module.exports = {
|
||||
|
||||
/**
|
||||
* This provides access to the internal nodes module of the
|
||||
* runtime.
|
||||
* runtime. The details of this API remain undocumented as they should not
|
||||
* be used directly.
|
||||
*
|
||||
* Most administrative actions should be performed use the runtime api
|
||||
* under [node-red.runtime]{@link node-red.runtime}.
|
||||
*
|
||||
* @memberof node-red
|
||||
*/
|
||||
|
12
packages/node_modules/node-red/package.json
vendored
12
packages/node_modules/node-red/package.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-beta.4",
|
||||
"version": "0.20.2",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,15 +31,15 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "0.20.0-beta.4",
|
||||
"@node-red/runtime": "0.20.0-beta.4",
|
||||
"@node-red/util": "0.20.0-beta.4",
|
||||
"@node-red/nodes": "0.20.0-beta.4",
|
||||
"@node-red/editor-api": "0.20.2",
|
||||
"@node-red/runtime": "0.20.2",
|
||||
"@node-red/util": "0.20.2",
|
||||
"@node-red/nodes": "0.20.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.16.4",
|
||||
"fs-extra": "7.0.1",
|
||||
"node-red-node-email": "1.0.*",
|
||||
"node-red-node-email": "1.*",
|
||||
"node-red-node-feedparser": "^0.1.14",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-sentiment": "^0.1.0",
|
||||
|
26
packages/node_modules/node-red/settings.js
vendored
26
packages/node_modules/node-red/settings.js
vendored
@@ -79,11 +79,12 @@ module.exports = {
|
||||
// lost.
|
||||
//credentialSecret: "a-secret-key",
|
||||
|
||||
// By default, all user data is stored in the Node-RED install directory. To
|
||||
// use a different location, the following property can be used
|
||||
// By default, all user data is stored in a directory called `.node-red` under
|
||||
// the user's home directory. To use a different location, the following
|
||||
// property can be used
|
||||
//userDir: '/home/nol/.node-red/',
|
||||
|
||||
// Node-RED scans the `nodes` directory in the install directory to find nodes.
|
||||
// Node-RED scans the `nodes` directory in the userDir to find local node files.
|
||||
// The following property can be used to specify an additional directory to scan.
|
||||
//nodesDir: '/home/nol/.node-red/nodes',
|
||||
|
||||
@@ -205,18 +206,27 @@ module.exports = {
|
||||
// // - reason: if result is false, the HTTP reason string to return
|
||||
//},
|
||||
|
||||
// Anything in this hash is globally available to all functions.
|
||||
// It is accessed as context.global.
|
||||
// eg:
|
||||
// The following property can be used to seed Global Context with predefined
|
||||
// values. This allows extra node modules to be made available with the
|
||||
// Function node.
|
||||
// For example,
|
||||
// functionGlobalContext: { os:require('os') }
|
||||
// can be accessed in a function block as:
|
||||
// context.global.os
|
||||
|
||||
// global.get("os")
|
||||
functionGlobalContext: {
|
||||
// os:require('os'),
|
||||
// jfive:require("johnny-five"),
|
||||
// j5board:require("johnny-five").Board({repl:false})
|
||||
},
|
||||
// `global.keys()` returns a list of all properties set in global context.
|
||||
// This allows them to be displayed in the Context Sidebar within the editor.
|
||||
// In some circumstances it is not desirable to expose them to the editor. The
|
||||
// following property can be used to hide any property set in `functionGlobalContext`
|
||||
// from being list by `global.keys()`.
|
||||
// By default, the property is set to false to avoid accidental exposure of
|
||||
// their values. Setting this to true will cause the keys to be listed.
|
||||
exportGlobalContextKeys: false,
|
||||
|
||||
|
||||
// Context Storage
|
||||
// The following property can be used to enable context storage. The configuration
|
||||
|
@@ -663,7 +663,7 @@ describe('trigger node', function() {
|
||||
});
|
||||
|
||||
it('should be able to extend the delay (but with no 2nd output)', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:"100", wires:[["n2"]] },
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:"200", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -677,20 +677,25 @@ describe('trigger node', function() {
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
(Date.now() - ss).should.be.greaterThan(149);
|
||||
(Date.now() - ss).should.be.greaterThan(300);
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
done(err);
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
var ss = Date.now();
|
||||
n1.emit("input", {payload:"Hello"});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"Error"});
|
||||
},30);
|
||||
},50);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"Error"});
|
||||
},100);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"World"});
|
||||
},150);
|
||||
},330);
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -28,6 +28,7 @@ var httpProxyNode = require("nr-test-utils").require("@node-red/nodes/core/io/06
|
||||
var hashSum = require("hash-sum");
|
||||
var httpProxy = require('http-proxy');
|
||||
var cookieParser = require('cookie-parser');
|
||||
var multer = require("multer");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red");
|
||||
var fs = require('fs-extra');
|
||||
var auth = require('basic-auth');
|
||||
@@ -118,9 +119,30 @@ describe('HTTP Request Node', function() {
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
|
||||
testApp = express();
|
||||
|
||||
// The fileupload test needs a different set of middleware - so mount
|
||||
// as a separate express instance
|
||||
var fileUploadApp = express();
|
||||
var mp = multer({ storage: multer.memoryStorage() }).any();
|
||||
fileUploadApp.post("/file-upload",function(req,res,next) {
|
||||
mp(req,res,function(err) {
|
||||
req._body = true;
|
||||
next(err);
|
||||
})
|
||||
},bodyParser.json(),function(req,res) {
|
||||
res.json({
|
||||
body: req.body,
|
||||
files: req.files
|
||||
})
|
||||
});
|
||||
testApp.use(fileUploadApp);
|
||||
|
||||
|
||||
|
||||
testApp.use(bodyParser.raw({type:"*/*"}));
|
||||
testApp.use(cookieParser());
|
||||
testApp.use(cookieParser(undefined,{decode:String}));
|
||||
testApp.get('/statusCode204', function(req,res) { res.status(204).end();});
|
||||
testApp.get('/text', function(req, res){ res.send('hello'); });
|
||||
testApp.get('/redirectToText', function(req, res){ res.status(302).set('Location', getTestURL('/text')).end(); });
|
||||
@@ -138,8 +160,7 @@ describe('HTTP Request Node', function() {
|
||||
}, 50);
|
||||
});
|
||||
testApp.get('/checkCookie', function(req, res){
|
||||
var value = req.cookies.data;
|
||||
res.send(value);
|
||||
res.send(req.cookies);
|
||||
});
|
||||
testApp.get('/setCookie', function(req, res){
|
||||
res.cookie('data','hello');
|
||||
@@ -219,6 +240,12 @@ describe('HTTP Request Node', function() {
|
||||
res.cookie('redirectReturn','return1');
|
||||
res.status(200).end();
|
||||
});
|
||||
testApp.get('/getQueryParams', function(req,res) {
|
||||
res.json({
|
||||
query:req.query,
|
||||
url: req.originalUrl
|
||||
});
|
||||
})
|
||||
startServer(function(err) {
|
||||
if (err) {
|
||||
done(err);
|
||||
@@ -237,7 +264,6 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
beforeEach(function() {
|
||||
preEnvHttpProxyLowerCase = process.env.http_proxy;
|
||||
preEnvHttpProxyUpperCase = process.env.HTTP_PROXY;
|
||||
@@ -971,7 +997,31 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should append query params to url - obj', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",paytoqs:true,ret:"obj",url:getTestURL('/getQueryParams')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload',{
|
||||
query:{a:'1',b:'2',c:'3'},
|
||||
url: '/getQueryParams?a=1&b=2&c=3'
|
||||
});
|
||||
msg.should.have.property('statusCode',200);
|
||||
msg.should.have.property('headers');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:{a:1,b:2,c:3}});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('HTTP header', function() {
|
||||
it('should receive cookie', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/setCookie')},
|
||||
@@ -1001,7 +1051,7 @@ describe('HTTP Request Node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload','abc');
|
||||
msg.payload.should.have.property('data','abc');
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
@@ -1012,6 +1062,26 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should send multiple cookies with string', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property('data','abc');
|
||||
msg.payload.should.have.property('foo','bar');
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", cookies:{data:'abc',foo:'bar'}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send cookie with object data', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
@@ -1020,7 +1090,7 @@ describe('HTTP Request Node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload','abc');
|
||||
msg.payload.should.have.property('data','abc');
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
@@ -1031,6 +1101,86 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should send multiple cookies with object data', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property('data','abc');
|
||||
msg.payload.should.have.property('foo','bar');
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", cookies:{data:{value:'abc'},foo:{value:'bar'}}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should encode cookie value', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var value = ';,/?:@ &=+$#';
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property('data',encodeURIComponent(value));
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", cookies:{data:value}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should encode cookie object', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var value = ';,/?:@ &=+$#';
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property('data',encodeURIComponent(value));
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", cookies:{data:{value:value, encode:true}}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not encode cookie when encode option is false', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var value = '!#$%&\'()*+-./:<>?@[]^_`{|}~';
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property('data',value);
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", cookies:{data:{value:value, encode:false}}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send cookie by msg.headers', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
@@ -1039,7 +1189,7 @@ describe('HTTP Request Node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload','abc');
|
||||
msg.payload.should.have.property('data','abc');
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
@@ -1050,6 +1200,26 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should send multiple cookies by msg.headers', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/checkCookie')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property('data','abc');
|
||||
msg.payload.should.have.property('foo','bar');
|
||||
msg.should.have.property('statusCode',200);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", cookies:{boo:'123'}, headers:{'cookie':'data=abc; foo=bar;'}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert all HTTP headers into lower case', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
|
||||
{id:"n2", type:"helper"}];
|
||||
@@ -1497,6 +1667,44 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('file-upload', function() {
|
||||
it('should upload a file', function(done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'POST',ret:'obj',url:getTestURL('/file-upload')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.have.property("body",{"other":"123"});
|
||||
msg.payload.should.have.property("files");
|
||||
msg.payload.files.should.have.length(1);
|
||||
msg.payload.files[0].should.have.property('fieldname','file');
|
||||
msg.payload.files[0].should.have.property('originalname','file.txt');
|
||||
msg.payload.files[0].should.have.property('buffer',{"type":"Buffer","data":[72,101,108,108,111,32,87,111,114,108,100]});
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({
|
||||
headers: {
|
||||
'content-type':'multipart/form-data'
|
||||
},
|
||||
payload: {
|
||||
file: {
|
||||
value: Buffer.from("Hello World"),
|
||||
options: {
|
||||
filename: "file.txt"
|
||||
}
|
||||
},
|
||||
other: 123
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('redirect-cookie', function() {
|
||||
it('should send cookies to the same domain when redirected(no cookies)', function(done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectToSameDomain')},
|
||||
|
@@ -531,8 +531,8 @@ describe('JOIN node', function() {
|
||||
msg.payload.should.have.property("c",true);
|
||||
msg.payload.should.have.property("d");
|
||||
msg.payload.d.should.have.property("e",7);
|
||||
msg.payload.should.have.property("g");
|
||||
msg.payload.g.should.have.property("f",6);
|
||||
// msg.payload.should.have.property("g");
|
||||
// msg.payload.g.should.have.property("f",6);
|
||||
done();
|
||||
}
|
||||
catch(e) { done(e)}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user