Compare commits
365 Commits
0.19.5
...
0.20.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
f309a9d537 | ||
|
a786b37cb9 | ||
|
6a519a30a2 | ||
|
81ae552e69 | ||
|
0ec04a3624 | ||
|
81d5b47fce | ||
|
ed31a0cf15 | ||
|
201d1926bc | ||
|
9ee6655bfa | ||
|
c4beab6b0d | ||
|
34b6643913 | ||
|
98e391b867 | ||
|
19eb8e9a6d | ||
|
43b7aa40c3 | ||
|
747af44fc1 | ||
|
d5ef428edd | ||
|
5fa4d227b8 | ||
|
cc7e3b0c26 | ||
|
473a2ae275 | ||
|
7f5d47f39d | ||
|
6031f146aa | ||
|
020a469f3b | ||
|
091de3aa66 | ||
|
b837f7608c | ||
|
afe9367bac | ||
|
9bd9023cb6 | ||
|
8502cf8498 | ||
|
33dade0584 | ||
|
84cc2ad0fa | ||
|
dc2d3bc7c0 | ||
|
64df557423 | ||
|
715cc77e76 | ||
|
b80d1af3d7 | ||
|
f05f534fd2 | ||
|
c0837ead0e | ||
|
a1f135bd66 | ||
|
978f4ecc58 | ||
|
46a8d96997 | ||
|
c283224000 | ||
|
a6ef755139 | ||
|
29a257d17a | ||
|
368b76a183 | ||
|
8bb861124d | ||
|
2f884ec778 | ||
|
8c561e92c8 | ||
|
633b9180d7 | ||
|
0e2d0e1b6f | ||
|
ea4d65ceee | ||
|
d47ac84d2e | ||
|
a97759aa35 | ||
|
3fcfd4abdd | ||
|
6d771da9a9 | ||
|
6201247875 | ||
|
8c367bcc53 | ||
|
8198132ca7 | ||
|
cf3b4e9e63 | ||
|
987dbf8a92 | ||
|
acf8c9bc4a | ||
|
7173895d36 | ||
|
43530d4a5f | ||
|
fefabef9ee | ||
|
0dd40a941b | ||
|
24b6670bc4 | ||
|
76661abbf5 | ||
|
e9dc9eff9b | ||
|
2f160743bc | ||
|
98616e772c | ||
|
bc014fec9b | ||
|
732598d9d2 | ||
|
2979acd5b8 | ||
|
fd20cd524e | ||
|
7b80ae42e1 | ||
|
b7012674c6 | ||
|
c76bd39280 | ||
|
09cd710f66 | ||
|
d9aadf9d98 | ||
|
86716b5ffb | ||
|
96e3aab3b4 | ||
|
72c78fe3ad | ||
|
abe746020b | ||
|
8e1c15419c | ||
|
ee47646cf7 | ||
|
32d9acdaa5 | ||
|
4eb3bd496b | ||
|
3c4f4d27d6 | ||
|
2060af8a92 | ||
|
21bf74a467 | ||
|
677833a277 | ||
|
0b5e4f2dd7 | ||
|
06a1f30350 | ||
|
c1ff241550 | ||
|
5717f75eac | ||
|
6b3b68a4e5 | ||
|
8bda2d0add | ||
|
bc02c9573c | ||
|
8167608f04 | ||
|
514e31aef9 | ||
|
20a31a6d38 | ||
|
4f0aa1bc02 | ||
|
be0ef6e594 | ||
|
93a8dbd31a | ||
|
cf931e8ddf | ||
|
510bfbf268 | ||
|
2f93bb969b | ||
|
27365c9f7b | ||
|
b1d2e188f5 | ||
|
e4f67df2a1 | ||
|
e094ea3d2a | ||
|
7515b745b5 | ||
|
0e902a7e71 | ||
|
2dfb443625 | ||
|
e6e7747ae1 | ||
|
d80ea6c0f5 | ||
|
ac6e3988a8 | ||
|
bfd98f3767 | ||
|
cc8bc1339f | ||
|
542d1dc600 | ||
|
1c66c88f95 | ||
|
dc880c672a | ||
|
073f38c68c | ||
|
6a6d13b075 | ||
|
9bb7e72c69 | ||
|
7436e01188 | ||
|
3d272d0f10 | ||
|
ee66a12dad | ||
|
47de85b012 | ||
|
f85b63a972 | ||
|
e630919ef8 | ||
|
2e3fd49b40 | ||
|
dd54af2c08 | ||
|
737bf411ff | ||
|
5070b1a6b5 | ||
|
c849da92cf | ||
|
6a4e7201fe | ||
|
ffa6dea452 | ||
|
30c1d31a99 | ||
|
6934a2d5c3 | ||
|
b9906ced9a | ||
|
5500b4fe35 | ||
|
2353f12cd6 | ||
|
1b8cab0f58 | ||
|
869c1d4ea4 | ||
|
9b938195a8 | ||
|
bb3c52821a | ||
|
81c8ae95e2 | ||
|
6098570ab7 | ||
|
d033c24fe5 | ||
|
4995e52dd6 | ||
|
c0d8f904b3 | ||
|
8dba0dac9e | ||
|
d0bf4a5329 | ||
|
7b28ba6078 | ||
|
e6466c3c3a | ||
|
d96d3064d6 | ||
|
d4589ed7e3 | ||
|
5cfc52ea18 | ||
|
3fcacd8339 | ||
|
49fe13f22f | ||
|
4d27ba1bda | ||
|
b715ac8bf4 | ||
|
d96049416f | ||
|
1c4df785fd | ||
|
8f94c5efeb | ||
|
7cffa1ece7 | ||
|
1ac18d7b33 | ||
|
1111d2518b | ||
|
ba7416450e | ||
|
3b02d36acb | ||
|
c2aa9a5337 | ||
|
70fb181b7b | ||
|
e64f4e3f39 | ||
|
e4d518749f | ||
|
7dcca2c907 | ||
|
4a027b8a79 | ||
|
c2c6e6080e | ||
|
09abec15b1 | ||
|
33d0d12bc8 | ||
|
f488869635 | ||
|
6382564727 | ||
|
7476b4c7db | ||
|
daf3e6a47a | ||
|
5bd3d12c7b | ||
|
c9db74ebca | ||
|
f8a88cc1a4 | ||
|
4a081bf125 | ||
|
8a68a3e861 | ||
|
7a9dd9ad9c | ||
|
6c01d0f9d8 | ||
|
45a53ac168 | ||
|
dabb2790c9 | ||
|
c66c5ea53c | ||
|
0a98ba6985 | ||
|
bb8e491856 | ||
|
5590d31336 | ||
|
dc7e48dc53 | ||
|
371d357218 | ||
|
f22960ad59 | ||
|
34ead436b0 | ||
|
808d5a75ae | ||
|
55e897faac | ||
|
5a5dda21e4 | ||
|
f085655daa | ||
|
9751089807 | ||
|
b2516117f5 | ||
|
2816b3edae | ||
|
242398c724 | ||
|
289583325d | ||
|
0f793ebd65 | ||
|
ce014044ea | ||
|
1064e531f0 | ||
|
dc3128fb3e | ||
|
d40aa7260f | ||
|
fc8c4063f2 | ||
|
f204c77ba3 | ||
|
7a8545273c | ||
|
c13e79e9c3 | ||
|
a20eaf852f | ||
|
84a6a5235e | ||
|
8235b7b96d | ||
|
0376e0d711 | ||
|
6bd0682e8c | ||
|
e24c22f9be | ||
|
f4ca8cd738 | ||
|
422109868d | ||
|
bcc7834650 | ||
|
1161e4f6c1 | ||
|
14435c24ac | ||
|
22ede79799 | ||
|
6cb3699ee9 | ||
|
6c65d3830e | ||
|
cdcf39fe82 | ||
|
71403e5acd | ||
|
3d70bc722a | ||
|
b2f50da322 | ||
|
2a50c66df8 | ||
|
8de47c0a6e | ||
|
023391e22a | ||
|
a4ddfd404f | ||
|
7307e558cb | ||
|
47356f5221 | ||
|
c6f8950b64 | ||
|
071f4eacde | ||
|
f96bdc578e | ||
|
114420e8fd | ||
|
ba49b2c681 | ||
|
5391fc962a | ||
|
d6211af5bd | ||
|
ef114e31c2 | ||
|
fd74a03479 | ||
|
428bf634e9 | ||
|
8789d983ed | ||
|
10faa96bcf | ||
|
42d31b9ee6 | ||
|
c9dc9b4fe9 | ||
|
f13e02a1a9 | ||
|
d887ab126b | ||
|
1a7868159a | ||
|
c6a1c8e8c4 | ||
|
fba339f666 | ||
|
09d41a9708 | ||
|
4630a162af | ||
|
fde157ff50 | ||
|
51f875c02d | ||
|
f0957c838f | ||
|
f5bebef37f | ||
|
80a15089b4 | ||
|
8edf399631 | ||
|
d5ffd1432f | ||
|
e73bf03615 | ||
|
665fe0e01e | ||
|
a866aa9c18 | ||
|
d9089b798c | ||
|
d34ebd4d1b | ||
|
716aa74004 | ||
|
2aae76c9bc | ||
|
5fc3ca0e23 | ||
|
5bb27109bf | ||
|
7406ab6017 | ||
|
f30ff7a2fd | ||
|
c102828a99 | ||
|
cb0e631b85 | ||
|
62b2adab78 | ||
|
0529eed0c9 | ||
|
8c169dc82b | ||
|
195342f7db | ||
|
cfaaef7860 | ||
|
e939d5e96e | ||
|
9f4628cf0a | ||
|
ec4d24af91 | ||
|
51373f59e2 | ||
|
6cc56879d3 | ||
|
da89460830 | ||
|
9e006d42bb | ||
|
4c02bab4ee | ||
|
5800ed41f1 | ||
|
18b5b4901f | ||
|
368418cf56 | ||
|
3e6cadf3d8 | ||
|
0c5a76b391 | ||
|
bf1afcfe8a | ||
|
2980818f0d | ||
|
9da58dbaf0 | ||
|
55d71659f8 | ||
|
8d5b546763 | ||
|
19c9707d62 | ||
|
79e004a040 | ||
|
48308db45b | ||
|
3f37e96f78 | ||
|
4e21a5e557 | ||
|
19fa69811b | ||
|
0ddb4c625d | ||
|
36dc1d2f97 | ||
|
11fa2cb35d | ||
|
546f07156f | ||
|
7e7117632d | ||
|
954226da0d | ||
|
38a1291c5b | ||
|
998bf92ad4 | ||
|
974ba40f28 | ||
|
e57d8ba0ef | ||
|
6b79c6135f | ||
|
a747d8c2d5 | ||
|
a3aec6b939 | ||
|
bba57f8d2b | ||
|
4312a01707 | ||
|
ecd8f97d8b | ||
|
06abe63fb1 | ||
|
9d507b09ca | ||
|
9c4a712dc7 | ||
|
b14a0e0dde | ||
|
e982f5076f | ||
|
42188b9f49 | ||
|
50e2dcbcd5 | ||
|
6104bb98f1 | ||
|
0835fdd0d1 | ||
|
522360dcb7 | ||
|
979713c4db | ||
|
e41d5c249f | ||
|
f82a779817 | ||
|
df8a8ea204 | ||
|
8957d33e49 | ||
|
28fe1e4c8f | ||
|
0c7f4e2168 | ||
|
b22956bd99 | ||
|
42516206d9 | ||
|
fc4edde6e6 | ||
|
54cc04fd96 | ||
|
80062b6a62 | ||
|
99af79fcf3 | ||
|
11d87205d7 | ||
|
5866d414ce | ||
|
9a972b0b8a | ||
|
e6aeeea8c1 | ||
|
5d064aa1d7 | ||
|
34832d5942 | ||
|
e3b1179a21 | ||
|
f94a36613c | ||
|
efc3cc24f4 | ||
|
b47f8aaf70 | ||
|
94ca4607bc | ||
|
2dab1d3e6e | ||
|
825b0fb22f | ||
|
1cdb039ea2 | ||
|
7409cb3abb | ||
|
e8e8f70c27 |
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/packages/node_modules/** linguist-generated=false
|
5
.gitignore
vendored
@@ -17,3 +17,8 @@ node_modules
|
||||
public
|
||||
locales/zz-ZZ
|
||||
nodes/core/locales/zz-ZZ
|
||||
!packages/node_modules
|
||||
packages/node_modules/@node-red/editor-client/public
|
||||
!test/**/node_modules
|
||||
docs
|
||||
!packages/node_modules/**/docs
|
||||
|
@@ -1,5 +1,4 @@
|
||||
/Gruntfile.js
|
||||
/.git/*
|
||||
/lib/*
|
||||
*.backup
|
||||
/public/*
|
||||
|
@@ -1,7 +0,0 @@
|
||||
.settings
|
||||
.jshintignore
|
||||
.jshintrc
|
||||
.project
|
||||
.tern-project
|
||||
.travis.yml
|
||||
.git
|
@@ -8,5 +8,3 @@ matrix:
|
||||
before_script:
|
||||
- npm install -g istanbul coveralls
|
||||
- node_js: "8"
|
||||
- node_js: "6"
|
||||
- node_js: "4"
|
||||
|
137
CHANGELOG.md
@@ -1,3 +1,140 @@
|
||||
#### 0.20.0-beta.3: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Update palette manager view properly when module updated
|
||||
- Add TreeList common widget
|
||||
- Fix visual jump when opening Comment editor on Safari Part of #2008
|
||||
- Fix vertical align of markdown editor in Safari Fixes #2008
|
||||
- Avoid marking node as changed if label state is default Fixes #2009
|
||||
- Highlight port on node hover while joining
|
||||
- Support drag-wiring of link nodes
|
||||
- Allow TypeSearch to include a filter option
|
||||
- Improve diff colouring
|
||||
- Allow sections to toggle in 2-element stack
|
||||
- Add support for ${} env var syntax when skipping validation Closes #1980
|
||||
- i18 support for markdown editor tooltip
|
||||
- Add RED.editor.registerTypeEditor for custom type editors
|
||||
- Tidy up markdown toolbar handling across all editors
|
||||
- Added validation while export into library
|
||||
- Reuse notification boxes rather than stack multiple of the same type
|
||||
- Make ssh key dialog accessible when opened from new proj dialog
|
||||
|
||||
Runtime
|
||||
|
||||
- Bump JSONata to 1.6.4 Fixes #2023
|
||||
- Add audit logging to admin api
|
||||
- Fix failure of RED.require #2010
|
||||
- Allow oauth strategy callback method to be customised Closes #1998
|
||||
- Ensure fs context cache is flushed on close Fixes #2001
|
||||
- Fix library Buffer( to Buffer.alloc( for node 10
|
||||
- Catch file-not-found on startup when non-existant flow file specified
|
||||
- Actively expire login sesssions and notify user
|
||||
- Add quotation marks for basic auth challenge #1976
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: remove promises to improve performance
|
||||
- Debug: add ability to apply JSONata expression to message
|
||||
- Join: remove promises to improve performance
|
||||
- JSON: delete msg.schema before sending msg to avoid conflicts
|
||||
- Link: update UI to use common TreeList widget
|
||||
- Switch: remove promises to improve performance
|
||||
|
||||
#### 0.20.0-beta.2: Beta Release
|
||||
|
||||
- Split Node-RED internals into multiple sub-modules
|
||||
|
||||
Editor
|
||||
|
||||
- Allow the editor to use a custom admin api url root
|
||||
- Improve performance of Flow Diff dialog - @TothiViseo #1989
|
||||
- Add 'open project' option to Projects Welcome dialog
|
||||
- Add 'type already registered' check in palette editor
|
||||
- Handle missing tab.disabled property
|
||||
- Handle missing wires prop and string x/y props on import
|
||||
- Add RED.notifications.hide flag - for UI testing
|
||||
- Improve alignment of node label edit inputs
|
||||
- Show arrow-in node when invalid font-awesome icon name was specified for default icon
|
||||
- Add ability to delete context values from sidebar
|
||||
- Allow copy-to-clipboard copy whole tabs
|
||||
- Make disabled flows more obvious in editor
|
||||
- Allow import/export from file in editor
|
||||
- Allow config nodes to be selected in sidebar and deleted
|
||||
- Show port label of subflow with input port
|
||||
- Support ctrl-click selection of flow tabs
|
||||
- Allow left-hand node button to act as toggle
|
||||
- Support dbl-click in tab bar to add new flow in position
|
||||
- Fix duplicate subflow detection on import
|
||||
- Add import notification with info on what has been imported Closes #1862
|
||||
- Show error details when trying to import invalid json
|
||||
- Show default icon when non-existent font-awesome icon was specified
|
||||
- Add configurable option for showing node label
|
||||
- Avoid http redirects as Safari doesn't reuse Auth header Fixes #1903
|
||||
- Tidy up ace tooltip styling
|
||||
- Add event log to editor
|
||||
- Add tooltips to multiple editor elements
|
||||
- Allow palette to be hidden
|
||||
- Add node module into to sidebar and palette popover
|
||||
- Mark all newly imported nodes as changed
|
||||
- Allow a node label to be hidden
|
||||
- Add markdown formatting toolbar
|
||||
- Add markdown toolbar to various editors
|
||||
- Fix i18n handling for ja-JP locale on Safari/MacOS
|
||||
- Add node body tooltip
|
||||
- Decrease opacity of flow-navigator
|
||||
- Update tooltip style
|
||||
- Update ACE to 1.4.1-src-min-noconflict
|
||||
- Cache node locales by language
|
||||
- Show icon element with either icon image or fa-icon
|
||||
- Added font-awesome icons to user defined icon
|
||||
- Update info side bar with node description section
|
||||
- One-click search of config node users
|
||||
- Redesign node edit dialog to tabbed style
|
||||
- Add 'restart flows' option to deploy menu
|
||||
- Add node description property UI
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- Allow a project to be loaded from cmdline
|
||||
- Handle lookup of undefined property in Global context Fixes #1978
|
||||
- Refuse to enable Manage Palette if npm too old
|
||||
- Remove restriction on upgrading non-local modules
|
||||
- Remove deprecated Buffer constructor usage Fixes #1709
|
||||
- Update httpServerOptions doc in settings.js
|
||||
- Exclude non-testable .js files from the unit tests
|
||||
- Add --safe mode flag to allow starting without flows running
|
||||
- Add setting-defined accessToken for automated access to the adminAPI - #1789
|
||||
|
||||
Nodes
|
||||
|
||||
- Move all core node EN help to their own locale files - #1990
|
||||
- CSV: better regex for number detection
|
||||
- Debug: hide button if not configured to send to sidebar
|
||||
- Delay: report queue activity when in by-topic mode
|
||||
- Delay: add msg.flush mode
|
||||
- Exec: Preserve existing properties on msg object
|
||||
- File: remove CR/LF from incoming filename
|
||||
- Function: create custom ace javascript mode to handle ES6 Fixes #1911
|
||||
- Function: add env.get
|
||||
- HTTP Request: Add http-proxy config #1913
|
||||
- HTTP Request: add msg.redirectList to output
|
||||
- HTTP Request: add msg.requestTimeout option for per-message setting - @natcl #1959
|
||||
- MQTT: add auto-detect and base64 output to mqtt node Fixes #1912 - @DurandA
|
||||
- MQTT: only unsubscribe node that is being removed
|
||||
- Sentiment: move to node-red-node-sentiment
|
||||
- Switch: add missing edit dialog icon
|
||||
- Tail: move to node-red-node-tail
|
||||
- TCPGet: clear status if user changes target per message
|
||||
- Template: tidy up edit dialog
|
||||
- UDP: more resilient binding to correct port for udp, give input side priority
|
||||
- Split/Join: add msg.reset to info panel
|
||||
- Split/Join: reset join without sending part array
|
||||
- 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.5: Maintenance Release
|
||||
|
||||
- Recognize pip installs of RPi.GPIO (#1934)
|
||||
|
368
Gruntfile.js
@@ -42,7 +42,7 @@ module.exports = function(grunt) {
|
||||
reporter: 'spec'
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
webdriver: {
|
||||
@@ -57,10 +57,11 @@ module.exports = function(grunt) {
|
||||
ignoreLeaks: false,
|
||||
ui: 'bdd',
|
||||
reportFormats: ['lcov','html'],
|
||||
print: 'both'
|
||||
print: 'both',
|
||||
istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
|
||||
},
|
||||
all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
jshint: {
|
||||
@@ -80,16 +81,14 @@ module.exports = function(grunt) {
|
||||
all: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js',
|
||||
'nodes/core/*/*.js',
|
||||
'editor/js/**/*.js'
|
||||
'packages/**/*.js'
|
||||
],
|
||||
core: {
|
||||
files: {
|
||||
src: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js'
|
||||
'packages/**/*.js',
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -120,81 +119,85 @@ module.exports = function(grunt) {
|
||||
src: [
|
||||
// Ensure editor source files are concatenated in
|
||||
// the right order
|
||||
"editor/js/red.js",
|
||||
"editor/js/events.js",
|
||||
"editor/js/i18n.js",
|
||||
"editor/js/settings.js",
|
||||
"editor/js/user.js",
|
||||
"editor/js/comms.js",
|
||||
"editor/js/text/bidi.js",
|
||||
"editor/js/text/format.js",
|
||||
"editor/js/ui/state.js",
|
||||
"editor/js/nodes.js",
|
||||
"editor/js/history.js",
|
||||
"editor/js/validators.js",
|
||||
"editor/js/ui/utils.js",
|
||||
"editor/js/ui/common/editableList.js",
|
||||
"editor/js/ui/common/checkboxSet.js",
|
||||
"editor/js/ui/common/menu.js",
|
||||
"editor/js/ui/common/panels.js",
|
||||
"editor/js/ui/common/popover.js",
|
||||
"editor/js/ui/common/searchBox.js",
|
||||
"editor/js/ui/common/tabs.js",
|
||||
"editor/js/ui/common/stack.js",
|
||||
"editor/js/ui/common/typedInput.js",
|
||||
"editor/js/ui/actions.js",
|
||||
"editor/js/ui/deploy.js",
|
||||
"editor/js/ui/diff.js",
|
||||
"editor/js/ui/keyboard.js",
|
||||
"editor/js/ui/workspaces.js",
|
||||
"editor/js/ui/view.js",
|
||||
"editor/js/ui/view-navigator.js",
|
||||
"editor/js/ui/sidebar.js",
|
||||
"editor/js/ui/palette.js",
|
||||
"editor/js/ui/tab-info.js",
|
||||
"editor/js/ui/tab-config.js",
|
||||
"editor/js/ui/tab-context.js",
|
||||
"editor/js/ui/palette-editor.js",
|
||||
"editor/js/ui/editor.js",
|
||||
"editor/js/ui/editors/*.js",
|
||||
"editor/js/ui/tray.js",
|
||||
"editor/js/ui/clipboard.js",
|
||||
"editor/js/ui/library.js",
|
||||
"editor/js/ui/notifications.js",
|
||||
"editor/js/ui/search.js",
|
||||
"editor/js/ui/typeSearch.js",
|
||||
"editor/js/ui/subflow.js",
|
||||
"editor/js/ui/userSettings.js",
|
||||
"editor/js/ui/projects/projects.js",
|
||||
"editor/js/ui/projects/projectSettings.js",
|
||||
"editor/js/ui/projects/projectUserSettings.js",
|
||||
"editor/js/ui/projects/tab-versionControl.js",
|
||||
"editor/js/ui/touch/radialMenu.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/red.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/events.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/user.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/comms.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/text/format.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/nodes.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/history.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js"
|
||||
],
|
||||
dest: "public/red/red.js"
|
||||
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
|
||||
},
|
||||
vendor: {
|
||||
files: {
|
||||
"public/vendor/vendor.js": [
|
||||
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||
"editor/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"editor/vendor/marked/marked.min.js",
|
||||
"editor/vendor/d3/d3.v3.min.js",
|
||||
"editor/vendor/i18next/i18next.min.js"
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js"
|
||||
],
|
||||
"public/vendor/vendor.css": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
|
||||
// TODO: resolve relative resource paths in
|
||||
// bootstrap/FA/jquery
|
||||
],
|
||||
"public/vendor/jsonata/jsonata.min.js": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/jsonata/jsonata.min.js": [
|
||||
"node_modules/jsonata/jsonata-es5.min.js",
|
||||
"editor/vendor/jsonata/formatter.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js"
|
||||
],
|
||||
"public/vendor/ace/worker-jsonata.js": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
|
||||
"node_modules/jsonata/jsonata-es5.min.js",
|
||||
"editor/vendor/jsonata/worker-jsonata.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -202,10 +205,10 @@ module.exports = function(grunt) {
|
||||
uglify: {
|
||||
build: {
|
||||
files: {
|
||||
'public/red/red.min.js': 'public/red/red.js',
|
||||
'public/red/main.min.js': 'public/red/main.js',
|
||||
'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js',
|
||||
'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -215,50 +218,50 @@ module.exports = function(grunt) {
|
||||
outputStyle: 'compressed'
|
||||
},
|
||||
files: [{
|
||||
dest: 'public/red/style.min.css',
|
||||
src: 'editor/sass/style.scss'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss'
|
||||
},
|
||||
{
|
||||
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
|
||||
src: 'editor/vendor/bootstrap/css/bootstrap.css'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/bootstrap/css/bootstrap.min.css',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/css/bootstrap.css'
|
||||
}]
|
||||
}
|
||||
},
|
||||
jsonlint: {
|
||||
messages: {
|
||||
src: [
|
||||
'nodes/core/locales/en-US/messages.json',
|
||||
'red/api/locales/en-US/editor.json',
|
||||
'red/runtime/locales/en-US/runtime.json'
|
||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
||||
]
|
||||
},
|
||||
keymaps: {
|
||||
src: [
|
||||
'editor/js/keymap.json'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
||||
]
|
||||
}
|
||||
},
|
||||
attachCopyright: {
|
||||
js: {
|
||||
src: [
|
||||
'public/red/red.min.js',
|
||||
'public/red/main.min.js'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js'
|
||||
]
|
||||
},
|
||||
css: {
|
||||
src: [
|
||||
'public/red/style.min.css'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/style.min.css'
|
||||
]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
build: {
|
||||
src: [
|
||||
"public/red",
|
||||
"public/index.html",
|
||||
"public/favicon.ico",
|
||||
"public/icons",
|
||||
"public/vendor"
|
||||
"packages/node_modules/@node-red/editor-client/public/red",
|
||||
"packages/node_modules/@node-red/editor-client/public/index.html",
|
||||
"packages/node_modules/@node-red/editor-client/public/favicon.ico",
|
||||
"packages/node_modules/@node-red/editor-client/public/icons",
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor"
|
||||
]
|
||||
},
|
||||
release: {
|
||||
@@ -270,27 +273,27 @@ module.exports = function(grunt) {
|
||||
watch: {
|
||||
js: {
|
||||
files: [
|
||||
'editor/js/**/*.js'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
|
||||
],
|
||||
tasks: ['copy:build','concat','uglify','attachCopyright:js']
|
||||
},
|
||||
sass: {
|
||||
files: [
|
||||
'editor/sass/**/*.scss'
|
||||
'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss'
|
||||
],
|
||||
tasks: ['sass','attachCopyright:css']
|
||||
},
|
||||
json: {
|
||||
files: [
|
||||
'nodes/core/locales/en-US/messages.json',
|
||||
'red/api/locales/en-US/editor.json',
|
||||
'red/runtime/locales/en-US/runtime.json'
|
||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
||||
],
|
||||
tasks: ['jsonlint:messages']
|
||||
},
|
||||
keymaps: {
|
||||
files: [
|
||||
'editor/js/keymap.json'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
||||
],
|
||||
tasks: ['jsonlint:keymaps','copy:build']
|
||||
},
|
||||
@@ -305,12 +308,13 @@ module.exports = function(grunt) {
|
||||
nodemon: {
|
||||
/* uses .nodemonignore */
|
||||
dev: {
|
||||
script: 'red.js',
|
||||
script: 'packages/node_modules/node-red/red.js',
|
||||
options: {
|
||||
args: nodemonArgs,
|
||||
ext: 'js,html,json',
|
||||
watch: [
|
||||
'red','nodes'
|
||||
'packages/node_modules',
|
||||
'!packages/node_modules/@node-red/editor-client'
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -329,21 +333,21 @@ module.exports = function(grunt) {
|
||||
build: {
|
||||
files:[
|
||||
{
|
||||
src: 'editor/js/main.js',
|
||||
dest: 'public/red/main.js'
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/js/main.js',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js'
|
||||
},
|
||||
{
|
||||
src: 'editor/js/keymap.json',
|
||||
dest: 'public/red/keymap.json'
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/images',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/images',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/red/images/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/images/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/vendor',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/vendor',
|
||||
src: [
|
||||
'ace/**',
|
||||
//'bootstrap/css/**',
|
||||
@@ -352,46 +356,35 @@ module.exports = function(grunt) {
|
||||
'font-awesome/**'
|
||||
],
|
||||
expand: true,
|
||||
dest: 'public/vendor/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/icons',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/icons/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/icons/'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
src: ['editor/index.html','editor/favicon.ico'],
|
||||
dest: 'public/',
|
||||
src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'],
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/',
|
||||
flatten: true
|
||||
},
|
||||
{
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'public/red/about'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
|
||||
},
|
||||
{
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'packages/node_modules/node-red/'
|
||||
},
|
||||
{
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
|
||||
}
|
||||
]
|
||||
},
|
||||
release: {
|
||||
files: [{
|
||||
mode: true,
|
||||
expand: true,
|
||||
src: [
|
||||
'*.md',
|
||||
'LICENSE',
|
||||
'package.json',
|
||||
'settings.js',
|
||||
'red.js',
|
||||
'lib/.gitignore',
|
||||
'nodes/*.demo',
|
||||
'nodes/core/**',
|
||||
'red/**',
|
||||
'public/**',
|
||||
'editor/templates/**',
|
||||
'bin/**'
|
||||
],
|
||||
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
|
||||
}]
|
||||
}
|
||||
},
|
||||
chmod: {
|
||||
@@ -400,19 +393,89 @@ module.exports = function(grunt) {
|
||||
},
|
||||
release: {
|
||||
src: [
|
||||
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'),
|
||||
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh')
|
||||
"packages/node_modules/@node-red/nodes/core/hardware/nrgpio",
|
||||
"packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh"
|
||||
]
|
||||
}
|
||||
},
|
||||
'npm-command': {
|
||||
options: {
|
||||
cmd: "pack",
|
||||
cwd: "<%= paths.dist %>/modules"
|
||||
},
|
||||
'node-red': { options: { args: [__dirname+'/packages/node_modules/node-red'] } },
|
||||
'@node-red/editor-api': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-api'] } },
|
||||
'@node-red/editor-client': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-client'] } },
|
||||
'@node-red/nodes': { options: { args: [__dirname+'/packages/node_modules/@node-red/nodes'] } },
|
||||
'@node-red/registry': { options: { args: [__dirname+'/packages/node_modules/@node-red/registry'] } },
|
||||
'@node-red/runtime': { options: { args: [__dirname+'/packages/node_modules/@node-red/runtime'] } },
|
||||
'@node-red/util': { options: { args: [__dirname+'/packages/node_modules/@node-red/util'] } }
|
||||
|
||||
|
||||
},
|
||||
mkdir: {
|
||||
release: {
|
||||
options: {
|
||||
create: ['<%= paths.dist %>/modules']
|
||||
},
|
||||
},
|
||||
},
|
||||
compress: {
|
||||
release: {
|
||||
options: {
|
||||
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
|
||||
},
|
||||
expand: true,
|
||||
cwd: '<%= paths.dist %>/',
|
||||
src: ['node-red-<%= pkg.version %>/**']
|
||||
cwd: 'packages/node_modules/',
|
||||
src: [
|
||||
'**',
|
||||
'!@node-red/editor-client/src/**'
|
||||
]
|
||||
}
|
||||
},
|
||||
jsdoc : {
|
||||
modules: {
|
||||
src: [
|
||||
'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',
|
||||
'packages/node_modules/@node-red/runtime/lib/events.js',
|
||||
'packages/node_modules/@node-red/util/**/*.js',
|
||||
],
|
||||
options: {
|
||||
destination: 'docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
},
|
||||
editor: {
|
||||
src: [
|
||||
'packages/node_modules/@node-red/editor-client/src/js'
|
||||
],
|
||||
options: {
|
||||
destination: 'packages/node_modules/@node-red/editor-client/docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
jsdoc2md: {
|
||||
runtimeAPI: {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: [
|
||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/events.js'
|
||||
],
|
||||
dest: 'packages/node_modules/@node-red/runtime/docs/api.md'
|
||||
},
|
||||
nodeREDUtil: {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: 'packages/node_modules/@node-red/util/**/*.js',
|
||||
dest: 'packages/node_modules/@node-red/util/docs/api.md'
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -432,6 +495,10 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-jsonlint');
|
||||
grunt.loadNpmTasks('grunt-mocha-istanbul');
|
||||
grunt.loadNpmTasks('grunt-webdriver');
|
||||
grunt.loadNpmTasks('grunt-jsdoc');
|
||||
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
|
||||
grunt.loadNpmTasks('grunt-npm-command');
|
||||
grunt.loadNpmTasks('grunt-mkdir');
|
||||
|
||||
grunt.registerMultiTask('attachCopyright', function() {
|
||||
var files = this.data.src;
|
||||
@@ -473,6 +540,18 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('verifyPackageDependencies', function() {
|
||||
var done = this.async();
|
||||
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
|
||||
verifyDependencies().then(function(failures) {
|
||||
if (failures.length > 0) {
|
||||
failures.forEach(f => grunt.log.error(f));
|
||||
grunt.fail.fatal("Failed to verify package dependencies");
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask('setDevEnv',
|
||||
'Sets NODE_ENV=development so non-minified assets are used',
|
||||
function () {
|
||||
@@ -481,7 +560,7 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','jshint:editor','mocha_istanbul:all']);
|
||||
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
@@ -509,9 +588,18 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('release',
|
||||
'Create distribution zip file',
|
||||
['build','clean:release','copy:release','chmod:release','compress:release']);
|
||||
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules']);
|
||||
|
||||
grunt.registerTask('pack-modules',
|
||||
'Create module pack files for release',
|
||||
['mkdir:release','npm-command']);
|
||||
|
||||
|
||||
grunt.registerTask('coverage',
|
||||
'Run Istanbul code test coverage task',
|
||||
['build','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('docs',
|
||||
'Generates API documentation',
|
||||
['jsdoc','jsdoc2md']);
|
||||
};
|
||||
|
@@ -44,9 +44,6 @@ If you want to run the latest code from git, here's how to get started:
|
||||
4. Run
|
||||
|
||||
npm start
|
||||
or
|
||||
|
||||
node red.js
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
RED.panels = (function() {
|
||||
|
||||
function createPanel(options) {
|
||||
var container = options.container || $("#"+options.id);
|
||||
var children = container.children();
|
||||
if (children.length !== 2) {
|
||||
throw new Error("Container must have exactly two children");
|
||||
}
|
||||
|
||||
container.addClass("red-ui-panels");
|
||||
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
|
||||
var startPosition;
|
||||
var panelHeights = [];
|
||||
var modifiedHeights = false;
|
||||
var panelRatio;
|
||||
|
||||
separator.draggable({
|
||||
axis: "y",
|
||||
containment: container,
|
||||
scroll: false,
|
||||
start:function(event,ui) {
|
||||
var height = container.height();
|
||||
startPosition = ui.position.top;
|
||||
panelHeights = [$(children[0]).height(),$(children[1]).height()];
|
||||
},
|
||||
drag: function(event,ui) {
|
||||
var height = container.height();
|
||||
var delta = ui.position.top-startPosition;
|
||||
var newHeights = [panelHeights[0]+delta,panelHeights[1]-delta];
|
||||
$(children[0]).height(newHeights[0]);
|
||||
$(children[1]).height(newHeights[1]);
|
||||
if (options.resize) {
|
||||
options.resize(newHeights[0],newHeights[1]);
|
||||
}
|
||||
ui.position.top -= delta;
|
||||
panelRatio = newHeights[0]/height;
|
||||
},
|
||||
stop:function(event,ui) {
|
||||
modifiedHeights = true;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
resize: function(height) {
|
||||
var panelHeights = [$(children[0]).height(),$(children[1]).height()];
|
||||
container.height(height);
|
||||
if (modifiedHeights) {
|
||||
var topPanelHeight = panelRatio*height;
|
||||
var bottomPanelHeight = height - topPanelHeight - 48;
|
||||
panelHeights = [topPanelHeight,bottomPanelHeight];
|
||||
$(children[0]).height(panelHeights[0]);
|
||||
$(children[1]).height(panelHeights[1]);
|
||||
}
|
||||
if (options.resize) {
|
||||
options.resize(panelHeights[0],panelHeights[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
create: createPanel
|
||||
}
|
||||
})();
|
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.popover = (function() {
|
||||
var deltaSizes = {
|
||||
"default": {
|
||||
top: 10,
|
||||
leftRight: 17,
|
||||
leftLeft: 25,
|
||||
leftBottom: 8,
|
||||
},
|
||||
"small": {
|
||||
top: 5,
|
||||
leftRight: 17,
|
||||
leftLeft: 16,
|
||||
leftBottom: 3,
|
||||
}
|
||||
}
|
||||
function createPopover(options) {
|
||||
var target = options.target;
|
||||
var direction = options.direction || "right";
|
||||
var trigger = options.trigger;
|
||||
var content = options.content;
|
||||
var delay = options.delay;
|
||||
var autoClose = options.autoClose;
|
||||
var width = options.width||"auto";
|
||||
var size = options.size||"default";
|
||||
if (!deltaSizes[size]) {
|
||||
throw new Error("Invalid RED.popover size value:",size);
|
||||
}
|
||||
|
||||
var timer = null;
|
||||
var active;
|
||||
var div;
|
||||
|
||||
var openPopup = function(instant) {
|
||||
if (active) {
|
||||
div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>');
|
||||
if (size !== "default") {
|
||||
div.addClass("red-ui-popover-size-"+size);
|
||||
}
|
||||
if (typeof content === 'function') {
|
||||
var result = content.call(res);
|
||||
if (result === null) {
|
||||
return;
|
||||
}
|
||||
if (typeof result === 'string') {
|
||||
div.text(result);
|
||||
} else {
|
||||
div.append(result);
|
||||
}
|
||||
} else {
|
||||
div.html(content);
|
||||
}
|
||||
if (width !== "auto") {
|
||||
div.width(width);
|
||||
}
|
||||
div.appendTo("body");
|
||||
|
||||
var targetPos = target.offset();
|
||||
var targetWidth = target.outerWidth();
|
||||
var targetHeight = target.outerHeight();
|
||||
var divHeight = div.height();
|
||||
var divWidth = div.width();
|
||||
if (direction === 'right') {
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight});
|
||||
} else if (direction === 'left') {
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth});
|
||||
} else if (direction === 'bottom') {
|
||||
div.css({top: targetPos.top+targetHeight+deltaSizes[size].top,left:targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom});
|
||||
}
|
||||
if (instant) {
|
||||
div.show();
|
||||
} else {
|
||||
div.fadeIn("fast");
|
||||
}
|
||||
}
|
||||
}
|
||||
var closePopup = function(instant) {
|
||||
if (!active) {
|
||||
if (div) {
|
||||
if (instant) {
|
||||
$(this).remove();
|
||||
} else {
|
||||
div.fadeOut("fast",function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
div = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trigger === 'hover') {
|
||||
target.on('mouseenter',function(e) {
|
||||
clearTimeout(timer);
|
||||
active = true;
|
||||
timer = setTimeout(openPopup,delay.show);
|
||||
});
|
||||
target.on('mouseleave', function(e) {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
active = false;
|
||||
setTimeout(closePopup,delay.hide);
|
||||
});
|
||||
} else if (trigger === 'click') {
|
||||
target.click(function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
active = !active;
|
||||
if (!active) {
|
||||
closePopup();
|
||||
} else {
|
||||
openPopup();
|
||||
}
|
||||
});
|
||||
} else if (autoClose) {
|
||||
setTimeout(function() {
|
||||
active = false;
|
||||
closePopup();
|
||||
},autoClose);
|
||||
}
|
||||
var res = {
|
||||
setContent: function(_content) {
|
||||
content = _content;
|
||||
return res;
|
||||
},
|
||||
open: function (instant) {
|
||||
active = true;
|
||||
openPopup(instant);
|
||||
return res;
|
||||
},
|
||||
close: function (instant) {
|
||||
active = false;
|
||||
closePopup(instant);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
create: createPopover,
|
||||
tooltip: function(target,content) {
|
||||
RED.popover.create({
|
||||
target:target,
|
||||
trigger: "hover",
|
||||
size: "small",
|
||||
direction: "bottom",
|
||||
content: content,
|
||||
delay: { show: 550, hide: 10 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.editor.types._markdown = (function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_markdown"><div class="form-row" id="node-input-markdown-title" style="margin-bottom: 3px; text-align: right;"></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-markdown"></div></div></script>';
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
$(template).appendTo(document.body);
|
||||
},
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onComplete = options.complete;
|
||||
var type = "_markdown"
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(expressionEditor.getValue());
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0;i<rows.size();i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
expressionEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-markdown',
|
||||
value: value,
|
||||
mode:"ace/mode/markdown"
|
||||
});
|
||||
if (options.header) {
|
||||
options.header.appendTo(tray.find('#node-input-markdown-title'));
|
||||
}
|
||||
|
||||
dialogForm.i18n();
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
|
||||
}
|
||||
}
|
||||
})();
|
@@ -1,8 +0,0 @@
|
||||
.ace_gutter {
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.ace_scroller {
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
#notifications {
|
||||
z-index: 100;
|
||||
width: 500px;
|
||||
margin-left: -250px;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
}
|
||||
.notification {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 4px;
|
||||
box-shadow: 0 1px 1px 1px rgba(0,0,0, 0.15);
|
||||
background-color: #fff;
|
||||
color: #666;
|
||||
border: 1px solid #325C80;
|
||||
border-left-width: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.notification p:first-child {
|
||||
font-size: 1.1em;
|
||||
font-weight: 400;
|
||||
}
|
||||
.notification a {
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-success {
|
||||
border-color: #4B8400;
|
||||
}
|
||||
.notification-warning {
|
||||
border-color: #D74108;
|
||||
}
|
||||
.notification-error {
|
||||
border-color: #AD1625;
|
||||
}
|
14
editor/vendor/ace/ace.js
vendored
5
editor/vendor/ace/ext-language_tools.js
vendored
5
editor/vendor/ace/ext-searchbox.js
vendored
1
editor/vendor/ace/mode-css.js
vendored
1
editor/vendor/ace/mode-handlebars.js
vendored
1
editor/vendor/ace/mode-html.js
vendored
1
editor/vendor/ace/mode-javascript.js
vendored
1
editor/vendor/ace/mode-markdown.js
vendored
1
editor/vendor/ace/mode-python.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/mode/python_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield|async|await",t="True|False|None|NotImplemented|Ellipsis|__debug__",n="abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern",r=this.createKeywordMapper({"invalid.deprecated":"debugger","support.function":n,"constant.language":t,keyword:e},"identifier"),i="(?:r|u|ur|R|U|UR|Ur|uR)?",s="(?:(?:[1-9]\\d*)|(?:0))",o="(?:0[oO]?[0-7]+)",u="(?:0[xX][\\dA-Fa-f]+)",a="(?:0[bB][01]+)",f="(?:"+s+"|"+o+"|"+u+"|"+a+")",l="(?:[eE][+-]?\\d+)",c="(?:\\.\\d+)",h="(?:\\d+)",p="(?:(?:"+h+"?"+c+")|(?:"+h+"\\.))",d="(?:(?:"+p+"|"+h+")"+l+")",v="(?:"+d+"|"+p+")",m="\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})";this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"string",regex:i+'"{3}',next:"qqstring3"},{token:"string",regex:i+'"(?=.)',next:"qqstring"},{token:"string",regex:i+"'{3}",next:"qstring3"},{token:"string",regex:i+"'(?=.)",next:"qstring"},{token:"constant.numeric",regex:"(?:"+v+"|\\d+)[jJ]\\b"},{token:"constant.numeric",regex:v},{token:"constant.numeric",regex:f+"[lL]\\b"},{token:"constant.numeric",regex:f+"\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\[\\(\\{]"},{token:"paren.rparen",regex:"[\\]\\)\\}]"},{token:"text",regex:"\\s+"}],qqstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:'"{3}',next:"start"},{defaultToken:"string"}],qstring3:[{token:"constant.language.escape",regex:m},{token:"string",regex:"'{3}",next:"start"},{defaultToken:"string"}],qqstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"start"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:m},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"start"},{defaultToken:"string"}]}};r.inherits(s,i),t.PythonHighlightRules=s}),ace.define("ace/mode/folding/pythonic",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=t.FoldMode=function(e){this.foldingStartMarker=new RegExp("([\\[{])(?:\\s*)$|("+e+")(?:\\s*)(?:#.*)?$")};r.inherits(s,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i)return i[1]?this.openingBracketBlock(e,i[1],n,i.index):i[2]?this.indentationBlock(e,n,i.index+i[2].length):this.indentationBlock(e,n)}}.call(s.prototype)}),ace.define("ace/mode/python",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/python_highlight_rules","ace/mode/folding/pythonic","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./python_highlight_rules").PythonHighlightRules,o=e("./folding/pythonic").FoldMode,u=e("../range").Range,a=function(){this.HighlightRules=s,this.foldingRules=new o("\\:"),this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart="#",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*[\{\(\[:]\s*$/);o&&(r+=n)}return r};var e={pass:1,"return":1,raise:1,"break":1,"continue":1};this.checkOutdent=function(t,n,r){if(r!=="\r\n"&&r!=="\r"&&r!=="\n")return!1;var i=this.getTokenizer().getLineTokens(n.trim(),t).tokens;if(!i)return!1;do var s=i.pop();while(s&&(s.type=="comment"||s.type=="text"&&s.value.match(/^\s+$/)));return s?s.type=="keyword"&&e[s.value]:!1},this.autoOutdent=function(e,t,n){n+=1;var r=this.$getIndent(t.getLine(n)),i=t.getTabString();r.slice(-i.length)==i&&t.remove(new u(n,r.length-i.length,n,r.length))},this.$id="ace/mode/python"}.call(a.prototype),t.Mode=a})
|
1
editor/vendor/ace/mode-swift.js
vendored
1
editor/vendor/ace/snippets/handlebars.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/handlebars",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="handlebars"})
|
1
editor/vendor/ace/snippets/json.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"})
|
1
editor/vendor/ace/snippets/properties.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/properties",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="properties"})
|
1
editor/vendor/ace/snippets/swift.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/swift",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="swift"})
|
1
editor/vendor/ace/snippets/text.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/text",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="text"})
|
1
editor/vendor/ace/snippets/yaml.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/yaml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="yaml"})
|
1
editor/vendor/ace/worker-html.js
vendored
1
editor/vendor/ace/worker-javascript.js
vendored
1
editor/vendor/ace/worker-json.js
vendored
26
jsdoc.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"opts": {
|
||||
"template": "./node_modules/jsdoc-nr-template",
|
||||
"destination": "./docs",
|
||||
"recurse": true
|
||||
},
|
||||
"tags": {
|
||||
"allowUnknownTags": false,
|
||||
"dictionaries": ["jsdoc"]
|
||||
},
|
||||
"source": {
|
||||
"_include": [
|
||||
"./packages/node_modules/@node-red/runtime/lib/api"
|
||||
]
|
||||
},
|
||||
"templates": {
|
||||
"systemName": "Node-RED Runtime API",
|
||||
"theme":"yeti",
|
||||
"footer": "",
|
||||
"copyright": "Released under the Apache License v2.0",
|
||||
"default": {
|
||||
"outputSourceFiles": false
|
||||
}
|
||||
},
|
||||
"plugins": ["plugins/markdown"]
|
||||
}
|
1
lib/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*
|
@@ -1,57 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="sentiment">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
</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">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>Analyses the chosen property, default <code>payload</code>, and adds a <code>sentiment</code> object.</p>
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">object</span></dt>
|
||||
<dd>contains the resulting AFINN-111 sentiment.</dd>
|
||||
<dt>sentiment.score <span class="property-type">number</span></dt>
|
||||
<dd>the sentiment score.</dd>
|
||||
</dl>
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">object</span></dt>
|
||||
<dd>an object of word score overrides can be supplied - <code>{ word:score,... }</code>.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>A score greater than zero is positive and less than zero is negative.</p>
|
||||
<p>The score typically ranges from -5 to +5, but can go higher and lower.</p>
|
||||
<p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('sentiment',{
|
||||
category: 'analysis-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"sentiment";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if (this.property === undefined) {
|
||||
$("#node-input-property").val("payload");
|
||||
}
|
||||
$("#node-input-property").typedInput({default:'msg',types:['msg']});
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -1,23 +0,0 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var sentiment = require('sentiment');
|
||||
|
||||
function SentimentNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.property = n.property||"payload";
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var value = RED.util.getMessageProperty(msg,node.property);
|
||||
if (value !== undefined) {
|
||||
sentiment(value, msg.overrides || null, function (err, result) {
|
||||
msg.sentiment = result;
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
else { node.send(msg); } // If no matching property - just pass it on.
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("sentiment",SentimentNode);
|
||||
}
|
@@ -1,319 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="link in">
|
||||
<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">
|
||||
</div>
|
||||
<div class="form-row node-input-link-row"></div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="link out">
|
||||
<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">
|
||||
</div>
|
||||
<div class="form-row node-input-link-row"></div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="link in">
|
||||
<p>Create virtual wires between flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>The node can be connected to any <code>link out</code> node that exists on any tab.
|
||||
Once connected, they behave as if they were wired together.</p>
|
||||
<p>The wires between link nodes are only displayed when a link node is selected.
|
||||
If there are any wires to other tabs, a virtual node is shown that can be clicked
|
||||
on to jump to the appropriate tab.</p>
|
||||
<p><b>Note: </b>Links cannot be created going into, or out of, a subflow.</p>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="link out">
|
||||
<p>Create virtual wires between flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>The node can be connected to any <code>link in</code> node that exists on any tab.
|
||||
Once connected, they behave as if they were wired together.</p>
|
||||
<p>The wires between link nodes are only displayed when a link node is selected.
|
||||
If there are any wires to other tabs, a virtual node is show that can be clicked
|
||||
on to jump to the appropriate tab.</p>
|
||||
<p><b>Note: </b>Links cannot be created going into, or out of, a subflow.</p>
|
||||
</script>
|
||||
<style>
|
||||
#node-input-link-container {
|
||||
position: relative;
|
||||
}
|
||||
#node-input-link-container li {
|
||||
padding: 2px 5px;
|
||||
background: none;
|
||||
font-size: 0.8em;
|
||||
margin:0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#node-input-link-container li label {
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#node-input-link-container li label input {
|
||||
vertical-align: top;
|
||||
width:15px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
#node-input-link-container li:hover,
|
||||
#node-input-link-container li:hover .node-input-target-node-sublabel {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.node-input-link-node-sublabel {
|
||||
position:absolute;
|
||||
right: 0px;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
|
||||
function sortNodeList(nodeList,sortOn,sortOnSecond) {
|
||||
var currentSort = nodeList.data('currentSort');
|
||||
var currentSortOrder = nodeList.data('currentSortOrder');
|
||||
|
||||
if (!currentSort) {
|
||||
currentSort = sortOn;
|
||||
currentSortOrder = 'a';
|
||||
} else {
|
||||
if (currentSort === sortOn) {
|
||||
currentSortOrder = (currentSortOrder === 'a'?'d':'a');
|
||||
} else {
|
||||
currentSortOrder = 'a';
|
||||
}
|
||||
currentSort = sortOn;
|
||||
}
|
||||
nodeList.data('currentSort',currentSort);
|
||||
nodeList.data('currentSortOrder',currentSortOrder);
|
||||
|
||||
$("#node-input-link-container-div .fa").hide();
|
||||
$(".node-input-link-sort-"+currentSort+"-"+currentSortOrder).show();
|
||||
|
||||
|
||||
var items = nodeList.find("li").get();
|
||||
items.sort(function(a,b) {
|
||||
var labelA = $(a).find(".node-input-link-node-"+currentSort).text().toLowerCase();
|
||||
var labelB = $(b).find(".node-input-link-node-"+currentSort).text().toLowerCase();
|
||||
if (labelA < labelB) { return currentSortOrder==='a'?-1:1; }
|
||||
if (labelA > labelB) { return currentSortOrder==='a'?1:-1; }
|
||||
|
||||
if (sortOnSecond) {
|
||||
labelA = $(a).find(".node-input-link-node-"+sortOnSecond).text().toLowerCase();
|
||||
labelB = $(b).find(".node-input-link-node-"+sortOnSecond).text().toLowerCase();
|
||||
if (labelA < labelB) { return currentSortOrder==='a'?-1:1; }
|
||||
if (labelA > labelB) { return currentSortOrder==='a'?1:-1; }
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
$.each(items, function(i, li) {
|
||||
nodeList.append(li);
|
||||
});
|
||||
}
|
||||
function onEditPrepare(node,targetType) {
|
||||
if (!node.links) {
|
||||
node.links = [];
|
||||
}
|
||||
node.oldLinks = [];
|
||||
|
||||
$('<div id="node-input-link-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;">'+
|
||||
' <div style="display: inline-block;margin-left: 5px;"><a id="node-input-link-sort-label" href="#" data-i18n="[title]node-red:link.label.sortByLabel"><span data-i18n="node-red:link.label.node">name</span> <i class="node-input-link-sort-label-a fa fa-caret-down"></i><i class="node-input-link-sort-label-d fa fa-caret-up"></i></a></div>'+
|
||||
' <div style="position: absolute; right: 10px; width: 50px; display: inline-block; text-align: right;"><a id="node-input-link-sort-type" href="#" data-i18n="[title]node-red:link.label.sortByFlow"><i class="node-input-link-sort-sublabel-a fa fa-caret-down"></i><i class="node-input-link-sort-sublabel-d fa fa-caret-up"></i> <span data-i18n="node-red:link.label.type">flow</span></a></div>'+
|
||||
' </div>'+
|
||||
' <div style="background: #fbfbfb; box-sizing: border-box; position:absolute; top:20px;bottom:0;left:0px;right:0px; overflow-y: scroll; overflow-x: hidden;">'+
|
||||
' <ul id="node-input-link-container" style=" list-style-type:none; margin: 0;"></ul>'+
|
||||
' </div>'+
|
||||
'</div>').appendTo('.node-input-link-row');
|
||||
|
||||
var nodeList = $("#node-input-link-container");
|
||||
var candidateNodes = RED.nodes.filterNodes({type:targetType});
|
||||
var inSubflow = !!RED.nodes.subflow(node.z);
|
||||
candidateNodes.forEach(function(n) {
|
||||
if (inSubflow) {
|
||||
if (n.z !== node.z) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!!RED.nodes.subflow(n.z)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var isChecked = false;
|
||||
|
||||
isChecked = (node.links.indexOf(n.id) !== -1) || (n.links||[]).indexOf(node.id) !== -1;
|
||||
|
||||
if (isChecked) {
|
||||
node.oldLinks.push(n.id);
|
||||
}
|
||||
|
||||
var container = $('<li/>',{class:"node-input-link-node"});
|
||||
var row = $('<label/>',{for:"node-input-link-node-"+n.id}).appendTo(container);
|
||||
$('<input>',{type:"checkbox",class:"node-input-link-node-checkbox",id:"node-input-link-node-"+n.id})
|
||||
.data('node-id',n.id)
|
||||
.prop('checked', isChecked)
|
||||
.appendTo(row);
|
||||
container.on('mouseover',function(e) {
|
||||
n.highlighted = true;
|
||||
n.dirty = true;
|
||||
RED.view.redraw();
|
||||
});
|
||||
container.on('mouseout',function(e) {
|
||||
n.highlighted = false;
|
||||
n.dirty = true;
|
||||
RED.view.redraw();
|
||||
});
|
||||
var labelSpan = $('<span>');
|
||||
var label = n.name||n.id;
|
||||
var sublabel;
|
||||
var tab = RED.nodes.workspace(n.z);
|
||||
if (tab) {
|
||||
sublabel = tab.label||tab.id;
|
||||
} else {
|
||||
tab = RED.nodes.subflow(n.z);
|
||||
sublabel = "subflow : "+tab.name;
|
||||
}
|
||||
$('<span>',{class:"node-input-link-node-label",style:"white-space:nowrap"}).text(label).appendTo(row);
|
||||
if (sublabel) {
|
||||
$('<span>',{class:"node-input-link-node-sublabel"}).text(sublabel).appendTo(row);
|
||||
}
|
||||
container.appendTo(nodeList);
|
||||
});
|
||||
|
||||
sortNodeList(nodeList,'sublabel','label');
|
||||
|
||||
$("#node-input-link-sort-label").click(function(e) {
|
||||
e.preventDefault();
|
||||
sortNodeList(nodeList,'label');
|
||||
});
|
||||
|
||||
$("#node-input-link-sort-type").click(function(e) {
|
||||
e.preventDefault();
|
||||
sortNodeList(nodeList,'sublabel');
|
||||
});
|
||||
}
|
||||
|
||||
function resizeNodeList() {
|
||||
var rows = $("#dialog-form>div:not(.node-input-link-row)");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0;i<rows.size();i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
var editorRow = $("#dialog-form>div.node-input-link-row");
|
||||
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-link-container-div").css("height",height+"px");
|
||||
}
|
||||
|
||||
function onEditSave(node) {
|
||||
node.links = [];
|
||||
$(".node-input-link-node-checkbox").each(function(n) {
|
||||
if ($(this).prop("checked")) {
|
||||
node.links.push($(this).data('node-id'));
|
||||
}
|
||||
});
|
||||
node.oldLinks.sort();
|
||||
node.links.sort();
|
||||
var nodeMap = {};
|
||||
var length = Math.max(node.oldLinks.length,node.links.length);
|
||||
for (var i=0;i<length;i++) {
|
||||
if (i<node.oldLinks.length) {
|
||||
nodeMap[node.oldLinks[i]] = nodeMap[node.oldLinks[i]]||{};
|
||||
nodeMap[node.oldLinks[i]].old = true;
|
||||
}
|
||||
if (i<node.links.length) {
|
||||
nodeMap[node.links[i]] = nodeMap[node.links[i]]||{};
|
||||
nodeMap[node.links[i]].new = true;
|
||||
}
|
||||
}
|
||||
var n;
|
||||
for (var id in nodeMap) {
|
||||
if (nodeMap.hasOwnProperty(id)) {
|
||||
n = RED.nodes.node(id);
|
||||
if (n) {
|
||||
if (nodeMap[id].old && !nodeMap[id].new) {
|
||||
// Removed id
|
||||
i = n.links.indexOf(node.id);
|
||||
if (i > -1) {
|
||||
n.links.splice(i,1);
|
||||
}
|
||||
} else if (!nodeMap[id].old && nodeMap[id].new) {
|
||||
// Added id
|
||||
i = n.links.indexOf(id);
|
||||
if (i === -1) {
|
||||
n.links.push(node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAdd() {
|
||||
for (var i=0;i<this.links.length;i++) {
|
||||
var n = RED.nodes.node(this.links[i]);
|
||||
if (n && n.links.indexOf(this.id) === -1) {
|
||||
n.links.push(this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType('link in',{
|
||||
category: 'input',
|
||||
color:"#ddd",//"#87D8CF",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
links: { value: [] }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "link-out.png",
|
||||
outputLabels: function(i) {
|
||||
return this.name||this._("link.linkIn");
|
||||
},
|
||||
label: function() {
|
||||
return this.name||this._("link.linkIn");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
onEditPrepare(this,"link out");
|
||||
},
|
||||
oneditsave: function() {
|
||||
onEditSave(this);
|
||||
},
|
||||
onadd: onAdd,
|
||||
oneditresize: resizeNodeList
|
||||
});
|
||||
|
||||
RED.nodes.registerType('link out',{
|
||||
category: 'output',
|
||||
color:"#ddd",//"#87D8CF",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
links: { value: []}
|
||||
},
|
||||
align:"right",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "link-out.png",
|
||||
inputLabels: function(i) {
|
||||
return this.name||this._("link.linkOut");
|
||||
},
|
||||
label: function() {
|
||||
return this.name||this._("link.linkOut");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
onEditPrepare(this,"link in");
|
||||
},
|
||||
oneditsave: function() {
|
||||
onEditSave(this);
|
||||
},
|
||||
onadd: onAdd,
|
||||
oneditresize: resizeNodeList
|
||||
});
|
||||
})();
|
||||
</script>
|
@@ -1,159 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var util = require("util");
|
||||
var mqtt = require("./mqtt");
|
||||
var settings = require(process.env.NODE_RED_HOME+"/red/red").settings;
|
||||
|
||||
util.log("[warn] nodes/core/io/lib/mqttConnectionPool.js is deprecated and will be removed in a future release of Node-RED. Please report this usage to the Node-RED mailing list.");
|
||||
|
||||
var connections = {};
|
||||
|
||||
function matchTopic(ts,t) {
|
||||
if (ts == "#") {
|
||||
return true;
|
||||
}
|
||||
var re = new RegExp("^"+ts.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
|
||||
return re.test(t);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: function(broker,port,clientid,username,password,will) {
|
||||
var id = "["+(username||"")+":"+(password||"")+"]["+(clientid||"")+"]@"+broker+":"+port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var uid = (1+Math.random()*4294967295).toString(16);
|
||||
var client = mqtt.createClient(port,broker);
|
||||
client.uid = uid;
|
||||
client.setMaxListeners(0);
|
||||
var options = {keepalive:15};
|
||||
options.clientId = clientid || 'mqtt_' + (1+Math.random()*4294967295).toString(16);
|
||||
options.username = username;
|
||||
options.password = password;
|
||||
options.will = will;
|
||||
var queue = [];
|
||||
var subscriptions = {};
|
||||
var connecting = false;
|
||||
var obj = {
|
||||
_instances: 0,
|
||||
publish: function(msg) {
|
||||
if (client.isConnected()) {
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
} else {
|
||||
if (!connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
queue.push(msg);
|
||||
}
|
||||
},
|
||||
subscribe: function(topic,qos,callback,ref) {
|
||||
ref = ref||0;
|
||||
subscriptions[topic] = subscriptions[topic]||{};
|
||||
|
||||
var sub = {
|
||||
topic:topic,
|
||||
qos:qos,
|
||||
handler:function(mtopic,mpayload,mqos,mretain) {
|
||||
if (matchTopic(topic,mtopic)) {
|
||||
callback(mtopic,mpayload,mqos,mretain);
|
||||
}
|
||||
},
|
||||
ref: ref
|
||||
};
|
||||
subscriptions[topic][ref] = sub;
|
||||
client.on('message',sub.handler);
|
||||
if (client.isConnected()) {
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
},
|
||||
unsubscribe: function(topic,ref) {
|
||||
ref = ref||0;
|
||||
var sub = subscriptions[topic];
|
||||
if (sub) {
|
||||
if (sub[ref]) {
|
||||
client.removeListener('message',sub[ref].handler);
|
||||
delete sub[ref];
|
||||
}
|
||||
if (Object.keys(sub).length == 0) {
|
||||
delete subscriptions[topic];
|
||||
client.unsubscribe(topic);
|
||||
}
|
||||
}
|
||||
},
|
||||
on: function(a,b){
|
||||
client.on(a,b);
|
||||
},
|
||||
once: function(a,b){
|
||||
client.once(a,b);
|
||||
},
|
||||
connect: function() {
|
||||
if (client && !client.isConnected() && !connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
},
|
||||
disconnect: function(ref) {
|
||||
|
||||
this._instances -= 1;
|
||||
if (this._instances == 0) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
delete connections[id];
|
||||
}
|
||||
},
|
||||
isConnected: function() {
|
||||
return client.isConnected();
|
||||
}
|
||||
};
|
||||
client.on('connect',function() {
|
||||
if (client) {
|
||||
util.log('[mqtt] ['+uid+'] connected to broker tcp://'+broker+':'+port);
|
||||
connecting = false;
|
||||
for (var s in subscriptions) {
|
||||
var topic = s;
|
||||
var qos = 0;
|
||||
for (var r in subscriptions[s]) {
|
||||
qos = Math.max(qos,subscriptions[s][r].qos);
|
||||
}
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
//console.log("connected - publishing",queue.length,"messages");
|
||||
while(queue.length) {
|
||||
var msg = queue.shift();
|
||||
//console.log(msg);
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
}
|
||||
}
|
||||
});
|
||||
client.on('connectionlost', function(err) {
|
||||
util.log('[mqtt] ['+uid+'] connection lost to broker tcp://'+broker+':'+port);
|
||||
connecting = false;
|
||||
setTimeout(function() {
|
||||
obj.connect();
|
||||
}, settings.mqttReconnectTime||5000);
|
||||
});
|
||||
client.on('disconnect', function() {
|
||||
connecting = false;
|
||||
util.log('[mqtt] ['+uid+'] disconnected from broker tcp://'+broker+':'+port);
|
||||
});
|
||||
|
||||
return obj
|
||||
}();
|
||||
}
|
||||
connections[id]._instances += 1;
|
||||
return connections[id];
|
||||
}
|
||||
};
|
@@ -1,35 +0,0 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>指定したプロパティ(デフォルトは<code>payload</code>)を分析し、<code>sentiment</code>オブジェクトを追加します。</p>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>AFINN-111による感情分析の結果</dd>
|
||||
<dt>sentiment.score <span class="property-type">数値</span></dt>
|
||||
<dd>感情分析スコア</dd>
|
||||
</dl>
|
||||
<h3>入力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>単語スコアの上書きをするためのオブジェクト - <code>{ word:score,... }</code></dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>ゼロ以上のスコアはポジティブ、ゼロ以下はネガティブを意味します。</p>
|
||||
<p>スコアの範囲は通常-5から+5ですが、より大きかったり小さかったりすることもあります。</p>
|
||||
<p>詳細は<a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>を参照してください。</p>
|
||||
</script>
|
@@ -1,330 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function ChangeNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
var node = this;
|
||||
|
||||
this.rules = n.rules;
|
||||
var rule;
|
||||
if (!this.rules) {
|
||||
rule = {
|
||||
t:(n.action=="replace"?"set":n.action),
|
||||
p:n.property||""
|
||||
}
|
||||
|
||||
if ((rule.t === "set")||(rule.t === "move")) {
|
||||
rule.to = n.to||"";
|
||||
} else if (rule.t === "change") {
|
||||
rule.from = n.from||"";
|
||||
rule.to = n.to||"";
|
||||
rule.re = (n.reg===null||n.reg);
|
||||
}
|
||||
this.rules = [rule];
|
||||
}
|
||||
|
||||
var valid = true;
|
||||
for (var i=0;i<this.rules.length;i++) {
|
||||
rule = this.rules[i];
|
||||
// Migrate to type-aware rules
|
||||
if (!rule.pt) {
|
||||
rule.pt = "msg";
|
||||
}
|
||||
if (rule.t === "change" && rule.re) {
|
||||
rule.fromt = 're';
|
||||
delete rule.re;
|
||||
}
|
||||
if (rule.t === "set" && !rule.tot) {
|
||||
if (rule.to.indexOf("msg.") === 0 && !rule.tot) {
|
||||
rule.to = rule.to.substring(4);
|
||||
rule.tot = "msg";
|
||||
}
|
||||
}
|
||||
if (!rule.tot) {
|
||||
rule.tot = "str";
|
||||
}
|
||||
if (!rule.fromt) {
|
||||
rule.fromt = "str";
|
||||
}
|
||||
if (rule.t === "change" && rule.fromt !== 'msg' && rule.fromt !== 'flow' && rule.fromt !== 'global') {
|
||||
rule.fromRE = rule.from;
|
||||
if (rule.fromt !== 're') {
|
||||
rule.fromRE = rule.fromRE.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
}
|
||||
try {
|
||||
rule.fromRE = new RegExp(rule.fromRE, "g");
|
||||
} catch (e) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-from",{error:e.message}));
|
||||
}
|
||||
}
|
||||
if (rule.tot === 'num') {
|
||||
rule.to = Number(rule.to);
|
||||
} else if (rule.tot === 'json' || rule.tot === 'bin') {
|
||||
try {
|
||||
// check this is parsable JSON
|
||||
JSON.parse(rule.to);
|
||||
} catch(e2) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-json"));
|
||||
}
|
||||
} else if (rule.tot === 'bool') {
|
||||
rule.to = /^true$/i.test(rule.to);
|
||||
} else if (rule.tot === 'jsonata') {
|
||||
try {
|
||||
rule.to = RED.util.prepareJSONataExpression(rule.to,this);
|
||||
} catch(e) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
|
||||
}
|
||||
} else if (rule.tot === 'env') {
|
||||
rule.to = RED.util.evaluateNodeProperty(rule.to,'env');
|
||||
}
|
||||
}
|
||||
|
||||
function getToValue(msg,rule) {
|
||||
var value = rule.to;
|
||||
if (rule.tot === 'json') {
|
||||
value = JSON.parse(rule.to);
|
||||
} else if (rule.tot === 'bin') {
|
||||
value = Buffer.from(JSON.parse(rule.to))
|
||||
}
|
||||
if (rule.tot === "msg") {
|
||||
value = RED.util.getMessageProperty(msg,rule.to);
|
||||
} else if ((rule.tot === 'flow') ||
|
||||
(rule.tot === 'global')) {
|
||||
return new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(rule.to, rule.tot, node, msg, (err,value) => {
|
||||
if (err) {
|
||||
resolve(undefined);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (rule.tot === 'date') {
|
||||
value = Date.now();
|
||||
} else if (rule.tot === 'jsonata') {
|
||||
return new Promise((resolve,reject) => {
|
||||
RED.util.evaluateJSONataExpression(rule.to,msg, (err, value) => {
|
||||
if (err) {
|
||||
reject(RED._("change.errors.invalid-expr",{error:err.message}))
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
function getFromValue(msg,rule) {
|
||||
var fromValue;
|
||||
var fromType;
|
||||
var fromRE;
|
||||
if (rule.t === 'change') {
|
||||
if (rule.fromt === 'msg' || rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||
return new Promise((resolve,reject) => {
|
||||
if (rule.fromt === "msg") {
|
||||
resolve(RED.util.getMessageProperty(msg,rule.from));
|
||||
} else if (rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||
var contextKey = RED.util.parseContextStore(rule.from);
|
||||
node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(fromValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then(fromValue => {
|
||||
if (typeof fromValue === 'number' || fromValue instanceof Number) {
|
||||
fromType = 'num';
|
||||
} else if (typeof fromValue === 'boolean') {
|
||||
fromType = 'bool'
|
||||
} else if (fromValue instanceof RegExp) {
|
||||
fromType = 're';
|
||||
fromRE = fromValue;
|
||||
} else if (typeof fromValue === 'string') {
|
||||
fromType = 'str';
|
||||
fromRE = fromValue.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
try {
|
||||
fromRE = new RegExp(fromRE, "g");
|
||||
} catch (e) {
|
||||
return Promise.reject(new Error(RED._("change.errors.invalid-from",{error:e.message})));
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(new Error(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)})));
|
||||
}
|
||||
return {
|
||||
fromType,
|
||||
fromValue,
|
||||
fromRE
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fromType = rule.fromt;
|
||||
fromValue = rule.from;
|
||||
fromRE = rule.fromRE;
|
||||
}
|
||||
}
|
||||
return Promise.resolve({
|
||||
fromType,
|
||||
fromValue,
|
||||
fromRE
|
||||
});
|
||||
}
|
||||
function applyRule(msg,rule) {
|
||||
var property = rule.p;
|
||||
var current;
|
||||
var fromValue;
|
||||
var fromType;
|
||||
var fromRE;
|
||||
try {
|
||||
return getToValue(msg,rule).then(value => {
|
||||
return getFromValue(msg,rule).then(fromParts => {
|
||||
fromValue = fromParts.fromValue;
|
||||
fromType = fromParts.fromType;
|
||||
fromRE = fromParts.fromRE;
|
||||
if (rule.pt === 'msg') {
|
||||
try {
|
||||
if (rule.t === 'delete') {
|
||||
RED.util.setMessageProperty(msg,property,undefined);
|
||||
} else if (rule.t === 'set') {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
} else if (rule.t === 'change') {
|
||||
current = RED.util.getMessageProperty(msg,property);
|
||||
if (typeof current === 'string') {
|
||||
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
|
||||
// str representation of exact from number/boolean
|
||||
// only replace if they match exactly
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
} else {
|
||||
current = current.replace(fromRE,value);
|
||||
RED.util.setMessageProperty(msg,property,current);
|
||||
}
|
||||
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
|
||||
if (current == Number(fromValue)) {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
}
|
||||
} else if (typeof current === 'boolean' && fromType === 'bool') {
|
||||
if (current.toString() === fromValue) {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {}
|
||||
return msg;
|
||||
} else if (rule.pt === 'flow' || rule.pt === 'global') {
|
||||
var contextKey = RED.util.parseContextStore(property);
|
||||
return new Promise((resolve,reject) => {
|
||||
var target = node.context()[rule.pt];
|
||||
var callback = err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(msg);
|
||||
}
|
||||
}
|
||||
if (rule.t === 'delete') {
|
||||
target.set(contextKey.key,undefined,contextKey.store,callback);
|
||||
} else if (rule.t === 'set') {
|
||||
target.set(contextKey.key,value,contextKey.store,callback);
|
||||
} else if (rule.t === 'change') {
|
||||
target.get(contextKey.key,contextKey.store,(err,current) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
if (typeof current === 'string') {
|
||||
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
|
||||
// str representation of exact from number/boolean
|
||||
// only replace if they match exactly
|
||||
target.set(contextKey.key,value,contextKey.store,callback);
|
||||
} else {
|
||||
current = current.replace(fromRE,value);
|
||||
target.set(contextKey.key,current,contextKey.store,callback);
|
||||
}
|
||||
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
|
||||
if (current == Number(fromValue)) {
|
||||
target.set(contextKey.key,value,contextKey.store,callback);
|
||||
}
|
||||
} else if (typeof current === 'boolean' && fromType === 'bool') {
|
||||
if (current.toString() === fromValue) {
|
||||
target.set(contextKey.key,value,contextKey.store,callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}).catch(err => {
|
||||
node.error(err, msg);
|
||||
return null;
|
||||
});
|
||||
} catch(err) {
|
||||
return Promise.resolve(msg);
|
||||
}
|
||||
}
|
||||
function applyRules(msg, currentRule) {
|
||||
if (currentRule >= node.rules.length) {
|
||||
return Promise.resolve(msg);
|
||||
}
|
||||
var r = node.rules[currentRule];
|
||||
var rulePromise;
|
||||
if (r.t === "move") {
|
||||
if ((r.tot !== r.pt) || (r.p.indexOf(r.to) !== -1)) {
|
||||
rulePromise = applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:r.p, tot:r.pt}).then(
|
||||
msg => applyRule(msg,{t:"delete", p:r.p, pt:r.pt})
|
||||
);
|
||||
}
|
||||
else { // 2 step move if we are moving from a child
|
||||
rulePromise = applyRule(msg,{t:"set", p:"_temp_move", pt:r.tot, to:r.p, tot:r.pt}).then(
|
||||
msg => applyRule(msg,{t:"delete", p:r.p, pt:r.pt})
|
||||
).then(
|
||||
msg => applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:"_temp_move", tot:r.pt})
|
||||
).then(
|
||||
msg => applyRule(msg,{t:"delete", p:"_temp_move", pt:r.pt})
|
||||
)
|
||||
}
|
||||
} else {
|
||||
rulePromise = applyRule(msg,r);
|
||||
}
|
||||
return rulePromise.then(
|
||||
msg => {
|
||||
if (!msg) {
|
||||
return
|
||||
} else if (currentRule === node.rules.length - 1) {
|
||||
return msg;
|
||||
} else {
|
||||
return applyRules(msg, currentRule+1);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
if (valid) {
|
||||
this.on('input', function(msg) {
|
||||
applyRules(msg, 0)
|
||||
.then( msg => { if (msg) { node.send(msg) }} )
|
||||
.catch( err => node.error(err, msg))
|
||||
});
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("change", ChangeNode);
|
||||
};
|
@@ -1,61 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="tail">
|
||||
<div class="form-row">
|
||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="tail.label.filename"></span></label>
|
||||
<input id="node-input-filename" type="text">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-filetype"><i class="fa fa-file-text-o"></i> <span data-i18n="tail.label.type"></span></label>
|
||||
<select type="text" id="node-input-filetype">
|
||||
<option value="text" data-i18n="tail.action.text"></option>
|
||||
<option value="binary" data-i18n="tail.action.binary"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" id="node-tail-split">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-split" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-split" style="width: 70%;"><span data-i18n="tail.label.splitlines"></span></label>
|
||||
</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">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tail">
|
||||
<p>Tails (watches for things to be added) to the configured file. (Linux/Mac ONLY)</p>
|
||||
<p>This will not work on Windows filesystems, as it relies on the <b>tail -F</b> command.</p>
|
||||
<h3>Outputs</h3>
|
||||
<ul>
|
||||
<li>Text (UTF-8) files will be returned as strings.</li>
|
||||
<li>Binary files will be returned as Buffer objects.</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tail',{
|
||||
category: 'storage-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filetype: {value:"text"},
|
||||
split: {value:false},
|
||||
filename: {value:"",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "file.png",
|
||||
label: function() {
|
||||
return this.name||this.filename||this._("tail.tail");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-filetype").on("change",function() {
|
||||
if (this.value === "text") { $("#node-tail-split").show(); }
|
||||
else { $("#node-tail-split").hide(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var spawn = require('child_process').spawn;
|
||||
var plat = require('os').platform();
|
||||
|
||||
if (plat.match(/^win/)) {
|
||||
throw RED._("tail.errors.windowsnotsupport");
|
||||
}
|
||||
|
||||
function TailNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.filename = n.filename;
|
||||
this.filetype = n.filetype || "text";
|
||||
this.split = n.split || false;
|
||||
var node = this;
|
||||
|
||||
var err = "";
|
||||
// TODO: rewrite to use node-tail
|
||||
var tail = spawn("tail", ["-F", "-n", "0", this.filename]);
|
||||
tail.stdout.on("data", function (data) {
|
||||
var msg = { topic:node.filename };
|
||||
if (node.filetype === "text") {
|
||||
if (node.split) {
|
||||
// TODO: allow customisation of the line break - as we do elsewhere
|
||||
var strings = data.toString().split("\n");
|
||||
for (var s in strings) {
|
||||
//TODO: should we really filter blanks? Is that expected?
|
||||
if (strings[s] !== "") {
|
||||
node.send({
|
||||
topic: node.filename,
|
||||
payload: strings[s]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data.toString();
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data;
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
tail.stderr.on("data", function(data) {
|
||||
node.error(data.toString());
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
/* istanbul ignore else */
|
||||
if (tail) { tail.kill(); }
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tail",TailNode);
|
||||
}
|
233
package.json
@@ -1,120 +1,121 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.19.5",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"main": "red/red.js",
|
||||
"scripts": {
|
||||
"start": "node red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build"
|
||||
},
|
||||
"bin": {
|
||||
"node-red": "./red.js",
|
||||
"node-red-pi": "bin/node-red-pi"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-beta.3",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"start": "node packages/node_modules/node-red/red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build",
|
||||
"docs": "grunt docs"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.6.2",
|
||||
"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",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.6.0",
|
||||
"denque": "1.4.0",
|
||||
"express": "4.16.4",
|
||||
"express-session": "1.15.6",
|
||||
"fs-extra": "7.0.1",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"i18next": "13.1.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.6.3",
|
||||
"media-typer": "1.0.1",
|
||||
"memorystore": "1.6.0",
|
||||
"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-feedparser": "^0.1.14",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-sentiment": "^0.1.0",
|
||||
"node-red-node-tail": "^0.0.1",
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.3",
|
||||
"request": "2.88.0",
|
||||
"semver": "5.6.0",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.1.2",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chromedriver": "2.45.0",
|
||||
"grunt": "~1.0.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.3.2",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.4.0",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-jsdoc": "^2.2.1",
|
||||
"grunt-jsdoc-to-markdown": "^4.0.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mkdir": "~1.0.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-npm-command": "~0.1.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"http-proxy": "^1.16.2",
|
||||
"istanbul": "0.4.5",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "^5.2.0",
|
||||
"mosca": "^2.8.3",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "3.3.0",
|
||||
"wdio-chromedriver-service": "^0.1.5",
|
||||
"wdio-mocha-framework": "^0.6.4",
|
||||
"wdio-spec-reporter": "^0.1.5",
|
||||
"webdriverio": "^4.14.1",
|
||||
"node-red-node-test-helper": "node-red/node-red-node-test-helper",
|
||||
"jsdoc-nr-template": "node-red/jsdoc-nr-template"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"editor",
|
||||
"messaging",
|
||||
"iot",
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.5.4",
|
||||
"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",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.5.0",
|
||||
"denque": "1.3.0",
|
||||
"express": "4.16.4",
|
||||
"express-session": "1.15.6",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"i18next": "11.6.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.4",
|
||||
"media-typer": "0.3.0",
|
||||
"memorystore": "1.6.0",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.1",
|
||||
"mustache": "2.3.2",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "^0.1.12",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.3",
|
||||
"request": "2.88.0",
|
||||
"semver": "5.6.0",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8",
|
||||
"ws": "1.1.5",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chromedriver": "2.41.0",
|
||||
"grunt": "~1.0.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.3.1",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.4.0",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"http-proxy": "^1.16.2",
|
||||
"istanbul": "0.4.5",
|
||||
"mocha": "^5.2.0",
|
||||
"node-red-node-test-helper": "0.1.7",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.0.7",
|
||||
"supertest": "3.3.0",
|
||||
"wdio-chromedriver-service": "^0.1.3",
|
||||
"wdio-mocha-framework": "^0.6.2",
|
||||
"wdio-spec-reporter": "^0.1.5",
|
||||
"webdriverio": "^4.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
}
|
||||
|
2
packages/node_modules/@node-red/editor-api/.npmignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
src
|
||||
docs
|
178
packages/node_modules/@node-red/editor-api/LICENSE
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
12
packages/node_modules/@node-red/editor-api/README.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
@node-red/editor-api
|
||||
====================
|
||||
|
||||
Node-RED editor api module.
|
||||
|
||||
This provides an Express application that can be used to serve the Node-RED
|
||||
editor.
|
||||
|
||||
|
||||
### Source
|
||||
|
||||
The main Node-RED modules are maintained as a monorepo on [GitHub](https://github.com/node-red/node-red).
|
56
packages/node_modules/@node-red/editor-api/lib/admin/context.js
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
|
||||
get: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
scope: req.params.scope,
|
||||
id: req.params.id,
|
||||
key: req.params[0],
|
||||
store: req.query['store']
|
||||
}
|
||||
runtimeAPI.context.getValue(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
scope: req.params.scope,
|
||||
id: req.params.id,
|
||||
key: req.params[0],
|
||||
store: req.query['store']
|
||||
}
|
||||
runtimeAPI.context.delete(opts).then(function(result) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
69
packages/node_modules/@node-red/editor-api/lib/admin/flow.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.getFlow(opts).then(function(result) {
|
||||
return res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
post: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
flow: req.body
|
||||
}
|
||||
runtimeAPI.flows.addFlow(opts).then(function(id) {
|
||||
return res.json({id:id});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
put: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
flow: req.body
|
||||
}
|
||||
runtimeAPI.flows.updateFlow(opts).then(function(id) {
|
||||
return res.json({id:id});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.deleteFlow(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
70
packages/node_modules/@node-red/editor-api/lib/admin/flows.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var version = req.get("Node-RED-API-Version")||"v1";
|
||||
if (!/^v[12]$/.test(version)) {
|
||||
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
|
||||
}
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.flows.getFlows(opts).then(function(result) {
|
||||
if (version === "v1") {
|
||||
res.json(result.flows);
|
||||
} else if (version === "v2") {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
post: function(req,res) {
|
||||
var version = req.get("Node-RED-API-Version")||"v1";
|
||||
if (!/^v[12]$/.test(version)) {
|
||||
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
deploymentType: req.get("Node-RED-Deployment-Type")||"full"
|
||||
}
|
||||
|
||||
if (opts.deploymentType !== 'reload') {
|
||||
if (version === "v1") {
|
||||
opts.flows = {flows: req.body}
|
||||
} else {
|
||||
opts.flows = req.body;
|
||||
}
|
||||
}
|
||||
|
||||
runtimeAPI.flows.setFlows(opts).then(function(result) {
|
||||
if (version === "v1") {
|
||||
res.status(204).end();
|
||||
} else {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
@@ -25,11 +25,11 @@ var auth = require("../auth");
|
||||
var apiUtil = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
flows.init(runtime);
|
||||
flow.init(runtime);
|
||||
nodes.init(runtime);
|
||||
context.init(runtime);
|
||||
init: function(runtimeAPI) {
|
||||
flows.init(runtimeAPI);
|
||||
flow.init(runtimeAPI);
|
||||
nodes.init(runtimeAPI);
|
||||
context.init(runtimeAPI);
|
||||
|
||||
var needsPermission = auth.needsPermission;
|
||||
|
||||
@@ -48,6 +48,8 @@ module.exports = {
|
||||
// Nodes
|
||||
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler);
|
||||
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
|
||||
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler);
|
||||
adminApp.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler);
|
||||
@@ -60,6 +62,11 @@ module.exports = {
|
||||
adminApp.get("/context/:scope(node|flow)/:id",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(node|flow)/:id/*",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
|
||||
// adminApp.delete("/context/:scope(global)",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
adminApp.delete("/context/:scope(global)/*",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
// adminApp.delete("/context/:scope(node|flow)/:id",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
adminApp.delete("/context/:scope(node|flow)/:id/*",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
|
||||
|
||||
return adminApp;
|
||||
}
|
||||
}
|
173
packages/node_modules/@node-red/editor-api/lib/admin/nodes.js
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
getAll: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
if (req.get("accept") == "application/json") {
|
||||
runtimeAPI.nodes.getNodeList(opts).then(function(list) {
|
||||
res.json(list);
|
||||
})
|
||||
} else {
|
||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||
runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) {
|
||||
res.send(configs);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
post: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.body.module,
|
||||
version: req.body.version
|
||||
}
|
||||
runtimeAPI.nodes.addModule(opts).then(function(info) {
|
||||
res.json(info);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0]
|
||||
}
|
||||
runtimeAPI.nodes.removeModule(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getSet: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params[0] + "/" + req.params[2]
|
||||
}
|
||||
if (req.get("accept") === "application/json") {
|
||||
runtimeAPI.nodes.getNodeInfo(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else {
|
||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||
runtimeAPI.nodes.getNodeConfig(opts).then(function(result) {
|
||||
return res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getModule: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0]
|
||||
}
|
||||
runtimeAPI.nodes.getModuleInfo(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
putSet: function(req,res) {
|
||||
var body = req.body;
|
||||
if (!body.hasOwnProperty("enabled")) {
|
||||
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
|
||||
res.status(400).json({code:"invalid_request", message:"Invalid request"});
|
||||
return;
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params[0] + "/" + req.params[2],
|
||||
enabled: body.enabled
|
||||
}
|
||||
runtimeAPI.nodes.setNodeSetState(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
putModule: function(req,res) {
|
||||
var body = req.body;
|
||||
if (!body.hasOwnProperty("enabled")) {
|
||||
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
|
||||
res.status(400).json({code:"invalid_request", message:"Invalid request"});
|
||||
return;
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0],
|
||||
enabled: body.enabled
|
||||
}
|
||||
runtimeAPI.nodes.setModuleState(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
getModuleCatalog: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0],
|
||||
lang: req.query.lng
|
||||
}
|
||||
runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getModuleCatalogs: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
lang: req.query.lng
|
||||
}
|
||||
runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getIcons: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.nodes.getIconList(opts).then(function(list) {
|
||||
res.json(list);
|
||||
});
|
||||
}
|
||||
};
|
@@ -25,7 +25,7 @@ var permissions = require("./permissions");
|
||||
var theme = require("../editor/theme");
|
||||
|
||||
var settings = null;
|
||||
var log = null
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
|
||||
|
||||
passport.use(strategies.bearerStrategy.BearerStrategy);
|
||||
@@ -36,13 +36,12 @@ var server = oauth2orize.createServer();
|
||||
|
||||
server.exchange(oauth2orize.exchange.password(strategies.passwordTokenExchange));
|
||||
|
||||
function init(runtime) {
|
||||
settings = runtime.settings;
|
||||
log = runtime.log;
|
||||
function init(_settings,storage) {
|
||||
settings = _settings;
|
||||
if (settings.adminAuth) {
|
||||
Users.init(settings.adminAuth);
|
||||
Tokens.init(settings.adminAuth,runtime.storage);
|
||||
strategies.init(runtime);
|
||||
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
|
||||
Users.init(mergedAdminAuth);
|
||||
Tokens.init(mergedAdminAuth,storage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,23 +80,24 @@ function getToken(req,res,next) {
|
||||
function login(req,res) {
|
||||
var response = {};
|
||||
if (settings.adminAuth) {
|
||||
if (settings.adminAuth.type === "credentials") {
|
||||
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
|
||||
if (mergedAdminAuth.type === "credentials") {
|
||||
response = {
|
||||
"type":"credentials",
|
||||
"prompts":[{id:"username",type:"text",label:"user.username"},{id:"password",type:"password",label:"user.password"}]
|
||||
}
|
||||
} else if (settings.adminAuth.type === "strategy") {
|
||||
} else if (mergedAdminAuth.type === "strategy") {
|
||||
|
||||
var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot;
|
||||
response = {
|
||||
"type":"strategy",
|
||||
"prompts":[{type:"button",label:settings.adminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
|
||||
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
|
||||
}
|
||||
if (settings.adminAuth.strategy.icon) {
|
||||
response.prompts[0].icon = settings.adminAuth.strategy.icon;
|
||||
if (mergedAdminAuth.strategy.icon) {
|
||||
response.prompts[0].icon = mergedAdminAuth.strategy.icon;
|
||||
}
|
||||
if (settings.adminAuth.strategy.image) {
|
||||
response.prompts[0].image = theme.serveFile('/login/',settings.adminAuth.strategy.image);
|
||||
if (mergedAdminAuth.strategy.image) {
|
||||
response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image);
|
||||
}
|
||||
}
|
||||
if (theme.context().login && theme.context().login.image) {
|
||||
@@ -182,7 +182,12 @@ function genericStrategy(adminApp,strategy) {
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
||||
adminApp.get('/auth/strategy/callback',
|
||||
|
||||
var callbackMethodFunc = adminApp.get;
|
||||
if (/^post$/i.test(options.callbackMethod)) {
|
||||
callbackMethodFunc = adminApp.post;
|
||||
}
|
||||
callbackMethodFunc('/auth/strategy/callback',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
@@ -26,7 +26,7 @@ var Users = require("./users");
|
||||
var Clients = require("./clients");
|
||||
var permissions = require("./permissions");
|
||||
|
||||
var log;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
|
||||
var bearerStrategy = function (accessToken, done) {
|
||||
// is this a valid token?
|
||||
@@ -124,9 +124,6 @@ AnonymousStrategy.prototype.authenticate = function(req) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
log = runtime.log;
|
||||
},
|
||||
bearerStrategy: bearerStrategy,
|
||||
clientPasswordStrategy: clientPasswordStrategy,
|
||||
passwordTokenExchange: passwordTokenExchange,
|
@@ -25,25 +25,39 @@ function generateToken(length) {
|
||||
|
||||
|
||||
var storage;
|
||||
|
||||
var sessionExpiryTime
|
||||
|
||||
var sessions = {};
|
||||
|
||||
var loadedSessions = null;
|
||||
var apiAccessTokens;
|
||||
var sessionExpiryListeners = [];
|
||||
var expiryTimeout;
|
||||
|
||||
function expireSessions() {
|
||||
if (expiryTimeout) {
|
||||
clearTimeout(expiryTimeout);
|
||||
expiryTimeout = null;
|
||||
}
|
||||
var nextExpiry = Number.MAX_SAFE_INTEGER;
|
||||
var now = Date.now();
|
||||
var modified = false;
|
||||
for (var t in sessions) {
|
||||
if (sessions.hasOwnProperty(t)) {
|
||||
var session = sessions[t];
|
||||
if (!session.hasOwnProperty("expires") || session.expires < now) {
|
||||
sessionExpiryListeners.forEach(listener => { listener(session) })
|
||||
delete sessions[t];
|
||||
modified = true;
|
||||
} else {
|
||||
if (session.expires < nextExpiry) {
|
||||
nextExpiry = session.expires;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextExpiry < Number.MAX_SAFE_INTEGER) {
|
||||
// Allow 5 seconds grace
|
||||
expiryTimeout = setTimeout(expireSessions,(nextExpiry - Date.now()) + 5000)
|
||||
}
|
||||
if (modified) {
|
||||
return storage.saveSessions(sessions);
|
||||
} else {
|
||||
@@ -63,20 +77,40 @@ function loadSessions() {
|
||||
module.exports = {
|
||||
init: function(adminAuthSettings, _storage) {
|
||||
storage = _storage;
|
||||
|
||||
sessionExpiryListeners = [];
|
||||
|
||||
sessionExpiryTime = adminAuthSettings.sessionExpiryTime || 604800; // 1 week in seconds
|
||||
// At this point, storage will not have been initialised, so defer loading
|
||||
// the sessions until there's a request for them.
|
||||
loadedSessions = null;
|
||||
|
||||
apiAccessTokens = {};
|
||||
if ( Array.isArray(adminAuthSettings.tokens) ) {
|
||||
apiAccessTokens = adminAuthSettings.tokens.reduce(function(prev, current) {
|
||||
prev[current.token] = {
|
||||
user: current.user,
|
||||
scope: current.scope
|
||||
};
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
get: function(token) {
|
||||
return loadSessions().then(function() {
|
||||
if (sessions[token]) {
|
||||
if (sessions[token].expires < Date.now()) {
|
||||
return expireSessions().then(function() { return null });
|
||||
var info = apiAccessTokens[token] || null;
|
||||
|
||||
if (info) {
|
||||
return Promise.resolve(info);
|
||||
} else {
|
||||
if (sessions[token]) {
|
||||
if (sessions[token].expires < Date.now()) {
|
||||
return expireSessions().then(function() { return null });
|
||||
}
|
||||
}
|
||||
return Promise.resolve(sessions[token]);
|
||||
}
|
||||
return Promise.resolve(sessions[token]);
|
||||
});
|
||||
},
|
||||
create: function(user,client,scope) {
|
||||
@@ -93,6 +127,11 @@ module.exports = {
|
||||
expires: accessTokenExpiresAt
|
||||
};
|
||||
sessions[accessToken] = session;
|
||||
|
||||
if (!expiryTimeout) {
|
||||
expiryTimeout = setTimeout(expireSessions,(accessTokenExpiresAt - Date.now()) + 5000)
|
||||
}
|
||||
|
||||
return storage.saveSessions(sessions).then(function() {
|
||||
return {
|
||||
accessToken: accessToken,
|
||||
@@ -106,5 +145,8 @@ module.exports = {
|
||||
delete sessions[token];
|
||||
return storage.saveSessions(sessions);
|
||||
});
|
||||
},
|
||||
onSessionExpiry: function(callback) {
|
||||
sessionExpiryListeners.push(callback);
|
||||
}
|
||||
}
|
253
packages/node_modules/@node-red/editor-api/lib/editor/comms.js
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var ws = require("ws");
|
||||
var url = require("url");
|
||||
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var Tokens;
|
||||
var Users;
|
||||
var Permissions;
|
||||
|
||||
var server;
|
||||
var settings;
|
||||
var runtimeAPI;
|
||||
|
||||
var wsServer;
|
||||
var activeConnections = [];
|
||||
|
||||
var anonymousUser;
|
||||
|
||||
var retained = {};
|
||||
|
||||
var heartbeatTimer;
|
||||
var lastSentTime;
|
||||
|
||||
function init(_server,_settings,_runtimeAPI) {
|
||||
server = _server;
|
||||
settings = _settings;
|
||||
runtimeAPI = _runtimeAPI;
|
||||
Tokens = require("../auth/tokens");
|
||||
Tokens.onSessionExpiry(handleSessionExpiry);
|
||||
Users = require("../auth/users");
|
||||
Permissions = require("../auth/permissions");
|
||||
|
||||
}
|
||||
function handleSessionExpiry(session) {
|
||||
activeConnections.forEach(connection => {
|
||||
if (connection.token === session.accessToken) {
|
||||
connection.ws.send(JSON.stringify({auth:"fail"}));
|
||||
connection.ws.close();
|
||||
}
|
||||
})
|
||||
}
|
||||
function generateSession(length) {
|
||||
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
|
||||
var token = [];
|
||||
for (var i=0;i<length;i++) {
|
||||
token.push(c[Math.floor(Math.random()*c.length)]);
|
||||
}
|
||||
return token.join("");
|
||||
}
|
||||
|
||||
function CommsConnection(ws) {
|
||||
this.session = generateSession(32);
|
||||
this.ws = ws;
|
||||
this.stack = [];
|
||||
this.user = null;
|
||||
this.lastSentTime = 0;
|
||||
var self = this;
|
||||
|
||||
log.audit({event: "comms.open"});
|
||||
log.trace("comms.open "+self.session);
|
||||
var pendingAuth = (settings.adminAuth != null);
|
||||
|
||||
if (!pendingAuth) {
|
||||
addActiveConnection(self);
|
||||
}
|
||||
ws.on('close',function() {
|
||||
log.audit({event: "comms.close",user:self.user, session: self.session});
|
||||
log.trace("comms.close "+self.session);
|
||||
removeActiveConnection(self);
|
||||
});
|
||||
ws.on('message', function(data,flags) {
|
||||
var msg = null;
|
||||
try {
|
||||
msg = JSON.parse(data);
|
||||
} catch(err) {
|
||||
log.trace("comms received malformed message : "+err.toString());
|
||||
return;
|
||||
}
|
||||
if (!pendingAuth) {
|
||||
if (msg.subscribe) {
|
||||
self.subscribe(msg.subscribe);
|
||||
// handleRemoteSubscription(ws,msg.subscribe);
|
||||
}
|
||||
} else {
|
||||
var completeConnection = function(userScope,session,sendAck) {
|
||||
try {
|
||||
if (!userScope || !Permissions.hasPermission(userScope,"status.read")) {
|
||||
ws.send(JSON.stringify({auth:"fail"}));
|
||||
ws.close();
|
||||
} else {
|
||||
pendingAuth = false;
|
||||
addActiveConnection(self);
|
||||
self.token = msg.auth;
|
||||
if (sendAck) {
|
||||
ws.send(JSON.stringify({auth:"ok"}));
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err.stack);
|
||||
// Just in case the socket closes before we attempt
|
||||
// to send anything.
|
||||
}
|
||||
}
|
||||
if (msg.auth) {
|
||||
Tokens.get(msg.auth).then(function(client) {
|
||||
if (client) {
|
||||
Users.get(client.user).then(function(user) {
|
||||
if (user) {
|
||||
self.user = user;
|
||||
log.audit({event: "comms.auth",user:self.user});
|
||||
completeConnection(client.scope,msg.auth,true);
|
||||
} else {
|
||||
log.audit({event: "comms.auth.fail"});
|
||||
completeConnection(null,null,false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
log.audit({event: "comms.auth.fail"});
|
||||
completeConnection(null,null,false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (anonymousUser) {
|
||||
log.audit({event: "comms.auth",user:anonymousUser});
|
||||
self.user = anonymousUser;
|
||||
completeConnection(anonymousUser.permissions,null,false);
|
||||
//TODO: duplicated code - pull non-auth message handling out
|
||||
if (msg.subscribe) {
|
||||
self.subscribe(msg.subscribe);
|
||||
}
|
||||
} else {
|
||||
log.audit({event: "comms.auth.fail"});
|
||||
completeConnection(null,null,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ws.on('error', function(err) {
|
||||
log.warn(log._("comms.error",{message:err.toString()}));
|
||||
});
|
||||
}
|
||||
|
||||
CommsConnection.prototype.send = function(topic,data) {
|
||||
var self = this;
|
||||
if (topic && data) {
|
||||
this.stack.push({topic:topic,data:data});
|
||||
}
|
||||
if (!this._xmitTimer) {
|
||||
this._xmitTimer = setTimeout(function() {
|
||||
try {
|
||||
self.ws.send(JSON.stringify(self.stack));
|
||||
self.lastSentTime = Date.now();
|
||||
} catch(err) {
|
||||
removeActiveConnection(self);
|
||||
log.warn(log._("comms.error-send",{message:err.toString()}));
|
||||
}
|
||||
delete self._xmitTimer;
|
||||
self.stack = [];
|
||||
},50);
|
||||
}
|
||||
}
|
||||
|
||||
CommsConnection.prototype.subscribe = function(topic) {
|
||||
runtimeAPI.comms.subscribe({
|
||||
user: this.user,
|
||||
client: this,
|
||||
topic: topic
|
||||
})
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (!settings.disableEditor) {
|
||||
Users.default().then(function(_anonymousUser) {
|
||||
anonymousUser = _anonymousUser;
|
||||
var webSocketKeepAliveTime = settings.webSocketKeepAliveTime || 15000;
|
||||
var commsPath = settings.httpAdminRoot || "/";
|
||||
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
|
||||
wsServer = new ws.Server({ noServer: true });
|
||||
wsServer.on('connection',function(ws) {
|
||||
var commsConnection = new CommsConnection(ws);
|
||||
});
|
||||
wsServer.on('error', function(err) {
|
||||
log.warn(log._("comms.error-server",{message:err.toString()}));
|
||||
});
|
||||
|
||||
server.on('upgrade', function upgrade(request, socket, head) {
|
||||
const pathname = url.parse(request.url).pathname;
|
||||
if (pathname === commsPath) {
|
||||
wsServer.handleUpgrade(request, socket, head, function done(ws) {
|
||||
wsServer.emit('connection', ws, request);
|
||||
});
|
||||
}
|
||||
// Don't destroy the socket as other listeners may want to handle the
|
||||
// event.
|
||||
});
|
||||
|
||||
lastSentTime = Date.now();
|
||||
|
||||
heartbeatTimer = setInterval(function() {
|
||||
var now = Date.now();
|
||||
if (now-lastSentTime > webSocketKeepAliveTime) {
|
||||
activeConnections.forEach(connection => connection.send("hb",lastSentTime));
|
||||
}
|
||||
}, webSocketKeepAliveTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (heartbeatTimer) {
|
||||
clearInterval(heartbeatTimer);
|
||||
heartbeatTimer = null;
|
||||
}
|
||||
if (wsServer) {
|
||||
wsServer.close();
|
||||
wsServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function addActiveConnection(connection) {
|
||||
activeConnections.push(connection);
|
||||
runtimeAPI.comms.addConnection({client: connection});
|
||||
}
|
||||
function removeActiveConnection(connection) {
|
||||
for (var i=0;i<activeConnections.length;i++) {
|
||||
if (activeConnections[i] === connection) {
|
||||
activeConnections.splice(i,1);
|
||||
runtimeAPI.comms.removeConnection({client:connection})
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init:init,
|
||||
start:start,
|
||||
stop:stop
|
||||
}
|
36
packages/node_modules/@node-red/editor-api/lib/editor/credentials.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI
|
||||
},
|
||||
get: function (req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: req.params.type,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.getNodeCredentials(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
@@ -24,31 +24,35 @@ var info = require("./settings");
|
||||
var auth = require("../auth");
|
||||
var nodes = require("../admin/nodes"); // TODO: move /icons into here
|
||||
var needsPermission;
|
||||
var runtime;
|
||||
var log;
|
||||
var runtimeAPI;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
|
||||
var apiUtil = require("../util");
|
||||
|
||||
var ensureRuntimeStarted = function(req,res,next) {
|
||||
if (!runtime.isStarted()) {
|
||||
log.error("Node-RED runtime not started");
|
||||
res.status(503).send("Not started");
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
runtimeAPI.isStarted().then( started => {
|
||||
if (!started) {
|
||||
log.error("Node-RED runtime not started");
|
||||
res.status(503).send("Not started");
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(server, _runtime) {
|
||||
runtime = _runtime;
|
||||
log = runtime.log;
|
||||
init: function(server, settings, _runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
needsPermission = auth.needsPermission;
|
||||
var settings = runtime.settings;
|
||||
if (!settings.disableEditor) {
|
||||
info.init(runtime);
|
||||
comms.init(server,runtime);
|
||||
info.init(runtimeAPI);
|
||||
comms.init(server,settings,runtimeAPI);
|
||||
|
||||
var ui = require("./ui");
|
||||
ui.init(runtime);
|
||||
|
||||
ui.init(runtimeAPI);
|
||||
|
||||
var editorApp = express();
|
||||
if (settings.requireHttps === true) {
|
||||
editorApp.enable('trust proxy');
|
||||
@@ -60,6 +64,11 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settings.httpServerOptions) {
|
||||
for (var eOption in settings.httpServerOptions) {
|
||||
editorApp.set(eOption, settings.httpServerOptions[eOption]);
|
||||
}
|
||||
}
|
||||
editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor);
|
||||
|
||||
editorApp.get("/icons",needsPermission("nodes.read"),nodes.getIcons,apiUtil.errorHandler);
|
||||
@@ -67,31 +76,31 @@ module.exports = {
|
||||
editorApp.get("/icons/:scope/:module/:icon",ui.icon);
|
||||
|
||||
var theme = require("./theme");
|
||||
theme.init(runtime);
|
||||
theme.init(settings);
|
||||
editorApp.use("/theme",theme.app());
|
||||
editorApp.use("/",ui.editorResources);
|
||||
|
||||
//Projects
|
||||
var projects = require("./projects");
|
||||
projects.init(runtime);
|
||||
projects.init(runtimeAPI);
|
||||
editorApp.use("/projects",projects.app());
|
||||
|
||||
// Locales
|
||||
var locales = require("./locales");
|
||||
locales.init(runtime);
|
||||
editorApp.get('/locales/nodes',locales.getAllNodes,apiUtil.errorHandler);
|
||||
locales.init(runtimeAPI);
|
||||
editorApp.get(/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler);
|
||||
|
||||
// Library
|
||||
var library = require("./library");
|
||||
library.init(editorApp,runtime);
|
||||
editorApp.post(new RegExp("/library/flows\/(.*)"),needsPermission("library.write"),library.post,apiUtil.errorHandler);
|
||||
library.init(runtimeAPI);
|
||||
editorApp.get("/library/flows",needsPermission("library.read"),library.getAll,apiUtil.errorHandler);
|
||||
editorApp.get(new RegExp("/library/flows\/(.*)"),needsPermission("library.read"),library.get,apiUtil.errorHandler);
|
||||
editorApp.get(/library\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
|
||||
editorApp.post(/library\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);
|
||||
|
||||
|
||||
// Credentials
|
||||
var credentials = require("./credentials");
|
||||
credentials.init(runtime);
|
||||
credentials.init(runtimeAPI);
|
||||
editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler);
|
||||
|
||||
// Settings
|
||||
@@ -100,18 +109,15 @@ module.exports = {
|
||||
editorApp.get("/settings/user",needsPermission("settings.read"),info.userSettings,apiUtil.errorHandler);
|
||||
// User Settings
|
||||
editorApp.post("/settings/user",needsPermission("settings.write"),info.updateUserSettings,apiUtil.errorHandler);
|
||||
|
||||
// SSH keys
|
||||
var sshkeys = require("./sshkeys");
|
||||
sshkeys.init(runtime);
|
||||
editorApp.use("/settings/user/keys",sshkeys.app());
|
||||
editorApp.use("/settings/user/keys",needsPermission("settings.write"),info.sshkeys());
|
||||
|
||||
return editorApp;
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
var catalogPath = path.resolve(path.join(__dirname,"locales"));
|
||||
return runtime.i18n.registerMessageCatalogs([
|
||||
var catalogPath = path.resolve(path.join(path.dirname(require.resolve("@node-red/editor-client")),"locales"));
|
||||
return i18n.registerMessageCatalogs([
|
||||
{namespace: "editor", dir: catalogPath, file:"editor.json"},
|
||||
{namespace: "jsonata", dir: catalogPath, file:"jsonata.json"},
|
||||
{namespace: "infotips", dir: catalogPath, file:"infotips.json"}
|
||||
@@ -119,7 +125,5 @@ module.exports = {
|
||||
comms.start();
|
||||
});
|
||||
},
|
||||
stop: comms.stop,
|
||||
publish: comms.publish,
|
||||
registerLibrary: library.register
|
||||
stop: comms.stop
|
||||
}
|
83
packages/node_modules/@node-red/editor-api/lib/editor/library.js
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
var fs = require('fs');
|
||||
var fspath = require('path');
|
||||
var when = require('when');
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
|
||||
getAll: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: 'flows'
|
||||
}
|
||||
runtimeAPI.library.getEntries(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
},
|
||||
getEntry: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: req.params[0],
|
||||
path: req.params[1]||""
|
||||
}
|
||||
runtimeAPI.library.getEntry(opts).then(function(result) {
|
||||
if (typeof result === "string") {
|
||||
if (opts.type === 'flows') {
|
||||
res.writeHead(200, {'Content-Type': 'application/json'});
|
||||
} else {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
}
|
||||
res.write(result);
|
||||
res.end();
|
||||
} else {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
},
|
||||
saveEntry: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
type: req.params[0],
|
||||
path: req.params[1]||""
|
||||
}
|
||||
// TODO: horrible inconsistencies between flows and all other types
|
||||
if (opts.type === "flows") {
|
||||
opts.meta = {};
|
||||
opts.body = JSON.stringify(req.body);
|
||||
} else {
|
||||
opts.meta = req.body;
|
||||
opts.body = opts.meta.text;
|
||||
delete opts.meta.text;
|
||||
}
|
||||
runtimeAPI.library.saveEntry(opts).then(function(result) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
}
|
||||
}
|
@@ -16,13 +16,26 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
//var apiUtil = require('../util');
|
||||
var i18n;
|
||||
var redNodes;
|
||||
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
function loadResource(lang, namespace) {
|
||||
var catalog = i18n.i.getResourceBundle(lang, namespace);
|
||||
if (!catalog) {
|
||||
var parts = lang.split("-");
|
||||
if (parts.length == 2) {
|
||||
var new_lang = parts[0];
|
||||
return i18n.i.getResourceBundle(new_lang, namespace);
|
||||
}
|
||||
}
|
||||
return catalog;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
i18n = runtime.i18n;
|
||||
redNodes = runtime.nodes;
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var namespace = req.params[0];
|
||||
@@ -32,21 +45,9 @@ module.exports = {
|
||||
var prevLang = i18n.i.language;
|
||||
// Trigger a load from disk of the language if it is not the default
|
||||
i18n.i.changeLanguage(lang, function(){
|
||||
var catalog = i18n.i.getResourceBundle(lang, namespace);
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
});
|
||||
i18n.i.changeLanguage(prevLang);
|
||||
|
||||
},
|
||||
getAllNodes: function(req,res) {
|
||||
var lngs = req.query.lng;
|
||||
var nodeList = redNodes.getNodeList();
|
||||
var result = {};
|
||||
nodeList.forEach(function(n) {
|
||||
if (n.module !== "node-red") {
|
||||
result[n.id] = i18n.i.getResourceBundle(lngs, n.id)||{};
|
||||
}
|
||||
});
|
||||
res.json(result);
|
||||
}
|
||||
}
|
511
packages/node_modules/@node-red/editor-api/lib/editor/projects.js
vendored
Normal file
@@ -0,0 +1,511 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var express = require("express");
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
var needsPermission = require("../auth").needsPermission;
|
||||
|
||||
function listProjects(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.projects.listProjects(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
}
|
||||
function getProject(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.getProject(opts).then(function(data) {
|
||||
if (data) {
|
||||
res.json(data);
|
||||
} else {
|
||||
res.status(404).end();
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
function getProjectStatus(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.query.remote
|
||||
}
|
||||
runtimeAPI.projects.getStatus(opts).then(function(data){
|
||||
if (data) {
|
||||
res.json(data);
|
||||
} else {
|
||||
res.status(404).end();
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
function getProjectRemotes(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.getRemotes(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
app: function() {
|
||||
var app = express();
|
||||
|
||||
app.use(function(req,res,next) {
|
||||
runtimeAPI.projects.available().then(function(available) {
|
||||
if (!available) {
|
||||
res.status(404).end();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Projects
|
||||
|
||||
// List all projects
|
||||
app.get("/", needsPermission("projects.read"),listProjects);
|
||||
|
||||
// Create project
|
||||
app.post("/", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
project: req.body
|
||||
}
|
||||
runtimeAPI.projects.createProject(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Update a project
|
||||
app.put("/:id", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
project: req.body
|
||||
}
|
||||
|
||||
if (req.body.active) {
|
||||
runtimeAPI.projects.setActiveProject(opts).then(function() {
|
||||
listProjects(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else if (req.body.initialise) {
|
||||
runtimeAPI.projects.initialiseProject(opts).then(function() {
|
||||
getProject(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else if (req.body.hasOwnProperty('credentialSecret') ||
|
||||
req.body.hasOwnProperty('description') ||
|
||||
req.body.hasOwnProperty('dependencies')||
|
||||
req.body.hasOwnProperty('summary') ||
|
||||
req.body.hasOwnProperty('files') ||
|
||||
req.body.hasOwnProperty('git')) {
|
||||
runtimeAPI.projects.updateProject(opts).then(function() {
|
||||
getProject(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else {
|
||||
res.status(400).json({error:"unexpected_error", message:"invalid_request"});
|
||||
}
|
||||
});
|
||||
|
||||
// Get project metadata
|
||||
app.get("/:id", needsPermission("projects.read"), getProject);
|
||||
|
||||
// Delete project
|
||||
app.delete("/:id", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.deleteProject(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// Get project status - files, commit counts, branch info
|
||||
app.get("/:id/status", needsPermission("projects.read"), getProjectStatus);
|
||||
|
||||
|
||||
// Project file listing
|
||||
app.get("/:id/files", needsPermission("projects.read"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.getFiles(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Get file content in a given tree (index/stage)
|
||||
app.get("/:id/files/:treeish/*", needsPermission("projects.read"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0],
|
||||
tree: req.params.treeish
|
||||
}
|
||||
runtimeAPI.projects.getFile(opts).then(function(data) {
|
||||
res.json({content:data});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Revert a file
|
||||
app.delete("/:id/files/_/*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0]
|
||||
}
|
||||
|
||||
runtimeAPI.projects.revertFile(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Stage a file
|
||||
app.post("/:id/stage/*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0]
|
||||
}
|
||||
runtimeAPI.projects.stageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Stage multiple files
|
||||
app.post("/:id/stage", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.body.files
|
||||
}
|
||||
runtimeAPI.projects.stageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Commit changes
|
||||
app.post("/:id/commit", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
message: req.body.message
|
||||
}
|
||||
runtimeAPI.projects.commit(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Unstage a file
|
||||
app.delete("/:id/stage/*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0]
|
||||
}
|
||||
runtimeAPI.projects.unstageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Unstage multiple files
|
||||
app.delete("/:id/stage", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.unstageFile(opts).then(function() {
|
||||
getProjectStatus(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a file diff
|
||||
app.get("/:id/diff/:type/*", needsPermission("projects.read"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0],
|
||||
type: req.params.type
|
||||
}
|
||||
runtimeAPI.projects.getFileDiff(opts).then(function(data) {
|
||||
res.json({
|
||||
diff: data
|
||||
})
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of commits
|
||||
app.get("/:id/commits", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
limit: req.query.limit || 20,
|
||||
before: req.query.before
|
||||
}
|
||||
runtimeAPI.projects.getCommits(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get an individual commit details
|
||||
app.get("/:id/commits/:sha", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
sha: req.params.sha
|
||||
}
|
||||
runtimeAPI.projects.getCommit(opts).then(function(data) {
|
||||
res.json({commit:data});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Push local commits to remote
|
||||
app.post("/:id/push/?*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.params[0],
|
||||
track: req.query.u
|
||||
}
|
||||
runtimeAPI.projects.push(opts).then(function(data) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Pull remote commits
|
||||
app.post("/:id/pull/?*", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.params[0],
|
||||
track: req.query.setUpstream,
|
||||
allowUnrelatedHistories: req.query.allowUnrelatedHistories
|
||||
}
|
||||
runtimeAPI.projects.pull(opts).then(function(data) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Abort an ongoing merge
|
||||
app.delete("/:id/merge", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.projects.abortMerge(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Resolve a merge
|
||||
app.post("/:id/resolve/*", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
path: req.params[0],
|
||||
resolution: req.body.resolutions
|
||||
}
|
||||
runtimeAPI.projects.resolveMerge(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of local branches
|
||||
app.get("/:id/branches", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: false
|
||||
}
|
||||
runtimeAPI.projects.getBranches(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Delete a local branch - ?force=true
|
||||
app.delete("/:id/branches/:branchName", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
branch: req.params.branchName,
|
||||
force: !!req.query.force
|
||||
}
|
||||
runtimeAPI.projects.deleteBranch(opts).then(function(data) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of remote branches
|
||||
app.get("/:id/branches/remote", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: true
|
||||
}
|
||||
runtimeAPI.projects.getBranches(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get branch status - commit counts/ahead/behind
|
||||
app.get("/:id/branches/remote/*/status", needsPermission("projects.read"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
branch: req.params[0]
|
||||
}
|
||||
runtimeAPI.projects.getBranchStatus(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Set the active local branch
|
||||
app.post("/:id/branches", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
branch: req.body.name,
|
||||
create: req.body.create
|
||||
}
|
||||
runtimeAPI.projects.setBranch(opts).then(function(data) {
|
||||
res.json(data);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Get a list of remotes
|
||||
app.get("/:id/remotes", needsPermission("projects.read"), getProjectRemotes);
|
||||
|
||||
// Add a remote
|
||||
app.post("/:id/remotes", needsPermission("projects.write"), function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.body
|
||||
}
|
||||
if (/^https?:\/\/[^/]+@/i.test(req.body.url)) {
|
||||
res.status(400).json({error:"unexpected_error", message:"Git http url must not include username/password"});
|
||||
return;
|
||||
}
|
||||
runtimeAPI.projects.addRemote(opts).then(function(data) {
|
||||
getProjectRemotes(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Delete a remote
|
||||
app.delete("/:id/remotes/:remoteName", needsPermission("projects.write"), function(req, res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: req.params.remoteName
|
||||
}
|
||||
runtimeAPI.projects.removeRemote(opts).then(function(data) {
|
||||
getProjectRemotes(req,res);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
// Update a remote
|
||||
app.put("/:id/remotes/:remoteName", needsPermission("projects.write"), function(req,res) {
|
||||
var remote = req.body || {};
|
||||
remote.name = req.params.remoteName;
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
remote: remote
|
||||
}
|
||||
runtimeAPI.projects.updateRemote(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
87
packages/node_modules/@node-red/editor-api/lib/editor/settings.js
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var apiUtils = require("../util");
|
||||
var runtimeAPI;
|
||||
var sshkeys = require("./sshkeys");
|
||||
var theme = require("./theme");
|
||||
var clone = require("clone");
|
||||
|
||||
function extend(target, source) {
|
||||
var keys = Object.keys(source);
|
||||
var i = keys.length;
|
||||
while(i--) {
|
||||
var value = source[keys[i]]
|
||||
var type = typeof value;
|
||||
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
|
||||
target[keys[i]] = value;
|
||||
} else if (value === null) {
|
||||
if (target.hasOwnProperty(keys[i])) {
|
||||
delete target[keys[i]];
|
||||
}
|
||||
} else {
|
||||
// Object
|
||||
if (target.hasOwnProperty(keys[i])) {
|
||||
target[keys[i]] = extend(target[keys[i]],value);
|
||||
} else {
|
||||
target[keys[i]] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
sshkeys.init(runtimeAPI);
|
||||
},
|
||||
runtimeSettings: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
|
||||
var themeSettings = theme.settings();
|
||||
if (themeSettings) {
|
||||
// result.editorTheme may already exist with the palette
|
||||
// disabled. Need to merge that into the receive settings
|
||||
result.editorTheme = extend(clone(themeSettings),result.editorTheme||{});
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
},
|
||||
userSettings: function(req, res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.settings.getUserSettings(opts).then(function(result) {
|
||||
res.json(result);
|
||||
});
|
||||
},
|
||||
updateUserSettings: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
settings: req.body
|
||||
}
|
||||
runtimeAPI.settings.updateUserSettings(opts).then(function(result) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
},
|
||||
sshkeys: function() {
|
||||
return sshkeys.app()
|
||||
}
|
||||
}
|
101
packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
var express = require("express");
|
||||
var runtimeAPI;
|
||||
|
||||
function getUsername(userObj) {
|
||||
var username = '__default';
|
||||
if ( userObj && userObj.name ) {
|
||||
username = userObj.name;
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
app: function() {
|
||||
var app = express();
|
||||
|
||||
// List all SSH keys
|
||||
app.get("/", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.settings.getUserKeys(opts).then(function(list) {
|
||||
res.json({
|
||||
keys: list
|
||||
});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Get SSH key detail
|
||||
app.get("/:id", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.settings.getUserKey(opts).then(function(data) {
|
||||
res.json({
|
||||
publickey: data
|
||||
});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Generate a SSH key
|
||||
app.post("/", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
// TODO: validate params
|
||||
opts.name = req.body.name;
|
||||
opts.password = req.body.password;
|
||||
opts.comment = req.body.comment;
|
||||
opts.size = req.body.size;
|
||||
|
||||
runtimeAPI.settings.generateUserKey(opts).then(function(name) {
|
||||
res.json({
|
||||
name: name
|
||||
});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
// Delete a SSH key
|
||||
app.delete("/:id", function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.settings.removeUserKey(opts).then(function(name) {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
});
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
@@ -40,7 +40,6 @@ var defaultContext = {
|
||||
var theme = null;
|
||||
var themeContext = clone(defaultContext);
|
||||
var themeSettings = null;
|
||||
var runtime = null;
|
||||
|
||||
var themeApp;
|
||||
|
||||
@@ -78,12 +77,8 @@ function serveFilesFromTheme(themeValue, themeApp, directory) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
var settings = runtime.settings;
|
||||
init: function(settings) {
|
||||
themeContext = clone(defaultContext);
|
||||
if (runtime.version) {
|
||||
themeContext.version = runtime.version();
|
||||
}
|
||||
themeSettings = null;
|
||||
theme = settings.editorTheme || {};
|
||||
},
|
@@ -17,18 +17,22 @@ var express = require('express');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var Mustache = require("mustache");
|
||||
var mime = require("mime");
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var theme = require("./theme");
|
||||
|
||||
var redNodes;
|
||||
|
||||
var templateDir = path.resolve(__dirname+"/../../../editor/templates");
|
||||
var runtimeAPI;
|
||||
var editorClientDir = path.dirname(require.resolve("@node-red/editor-client"));
|
||||
var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.png");
|
||||
var editorTemplatePath = path.join(editorClientDir,"templates","index.mst");
|
||||
var editorTemplate;
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
redNodes = runtime.nodes;
|
||||
editorTemplate = fs.readFileSync(path.join(templateDir,"index.mst"),"utf8");
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
editorTemplate = fs.readFileSync(editorTemplatePath,"utf8");
|
||||
Mustache.parse(editorTemplate);
|
||||
},
|
||||
|
||||
@@ -46,11 +50,26 @@ module.exports = {
|
||||
var icon = req.params.icon;
|
||||
var scope = req.params.scope;
|
||||
var module = scope ? scope + '/' + req.params.module : req.params.module;
|
||||
var iconPath = redNodes.getNodeIconPath(module,icon);
|
||||
res.sendFile(iconPath);
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: module,
|
||||
icon: icon
|
||||
}
|
||||
runtimeAPI.nodes.getIcon(opts).then(function(data) {
|
||||
if (data) {
|
||||
var contentType = mime.getType(icon);
|
||||
res.set("Content-Type", contentType);
|
||||
res.send(data);
|
||||
} else {
|
||||
res.sendFile(defaultNodeIcon);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
editor: function(req,res) {
|
||||
res.send(Mustache.render(editorTemplate,theme.context()));
|
||||
},
|
||||
editorResources: express.static(__dirname + '/../../../public')
|
||||
editorResources: express.static(path.join(editorClientDir,'public'))
|
||||
};
|
@@ -26,17 +26,21 @@ var apiUtil = require("./util");
|
||||
|
||||
var adminApp;
|
||||
var server;
|
||||
var runtime;
|
||||
var editor;
|
||||
|
||||
function init(_server,_runtime) {
|
||||
function init(settings,_server,storage,runtimeAPI) {
|
||||
server = _server;
|
||||
runtime = _runtime;
|
||||
var settings = runtime.settings;
|
||||
if (settings.httpAdminRoot !== false) {
|
||||
apiUtil.init(runtime);
|
||||
adminApp = express();
|
||||
auth.init(runtime);
|
||||
|
||||
var cors = require('cors');
|
||||
var corsHandler = cors({
|
||||
origin: "*",
|
||||
methods: "GET,PUT,POST,DELETE"
|
||||
});
|
||||
adminApp.use(corsHandler);
|
||||
|
||||
auth.init(settings,storage);
|
||||
|
||||
var maxApiRequestSize = settings.apiMaxLength || '5mb';
|
||||
adminApp.use(bodyParser.json({limit:maxApiRequestSize}));
|
||||
@@ -61,7 +65,7 @@ function init(_server,_runtime) {
|
||||
// Editor
|
||||
if (!settings.disableEditor) {
|
||||
editor = require("./editor");
|
||||
var editorApp = editor.init(server, runtime);
|
||||
var editorApp = editor.init(server, settings, runtimeAPI);
|
||||
adminApp.use(editorApp);
|
||||
}
|
||||
|
||||
@@ -70,7 +74,7 @@ function init(_server,_runtime) {
|
||||
adminApp.use(corsHandler);
|
||||
}
|
||||
|
||||
var adminApiApp = require("./admin").init(runtime);
|
||||
var adminApiApp = require("./admin").init(runtimeAPI);
|
||||
adminApp.use(adminApiApp);
|
||||
} else {
|
||||
adminApp = null;
|
||||
@@ -93,23 +97,8 @@ module.exports = {
|
||||
init: init,
|
||||
start: start,
|
||||
stop: stop,
|
||||
library: {
|
||||
register: function(type) {
|
||||
if (editor) {
|
||||
editor.registerLibrary(type);
|
||||
}
|
||||
}
|
||||
},
|
||||
auth: {
|
||||
needsPermission: auth.needsPermission
|
||||
},
|
||||
comms: {
|
||||
publish: function(topic,data,retain) {
|
||||
if (editor) {
|
||||
editor.publish(topic,data,retain);
|
||||
}
|
||||
}
|
||||
},
|
||||
get adminApp() { return adminApp; },
|
||||
get server() { return server; }
|
||||
get httpAdmin() { return adminApp; }
|
||||
};
|
@@ -15,16 +15,14 @@
|
||||
**/
|
||||
|
||||
|
||||
var i18n;
|
||||
var log;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtime) {
|
||||
log = _runtime.log;
|
||||
i18n = _runtime.i18n;
|
||||
},
|
||||
errorHandler: function(err,req,res,next) {
|
||||
console.error(err.stack);
|
||||
//TODO: why this when rejectHandler also?!
|
||||
|
||||
if (err.message === "request entity too large") {
|
||||
log.error(err);
|
||||
} else {
|
||||
@@ -41,5 +39,13 @@ module.exports = {
|
||||
lang = acceptedLanguages[0];
|
||||
}
|
||||
return lang;
|
||||
},
|
||||
rejectHandler: function(req,res,err) {
|
||||
//TODO: why this when errorHandler also?!
|
||||
log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req);
|
||||
res.status(err.status||400).json({
|
||||
code: err.code||"unexpected_error",
|
||||
message: err.message||err.toString()
|
||||
});
|
||||
}
|
||||
}
|
37
packages/node_modules/@node-red/editor-api/package.json
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "0.20.0-beta.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "0.20.0-beta.3",
|
||||
"@node-red/editor-client": "0.20.0-beta.3",
|
||||
"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",
|
||||
"mime": "2.4.0",
|
||||
"mustache": "3.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.4.0",
|
||||
"when": "3.7.8",
|
||||
"ws": "6.1.2"
|
||||
}
|
||||
}
|
2
packages/node_modules/@node-red/editor-client/.npmignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
src
|
||||
docs
|
178
packages/node_modules/@node-red/editor-client/LICENSE
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
10
packages/node_modules/@node-red/editor-client/README.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
@node-red/editor-client
|
||||
====================
|
||||
|
||||
Node-RED editor resources module.
|
||||
|
||||
This provides all of the client-side resources of the Node-RED editor application.
|
||||
|
||||
### Source
|
||||
|
||||
The main Node-RED modules are maintained as a monorepo on [GitHub](https://github.com/node-red/node-red).
|
@@ -13,4 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var RED = {};
|
||||
|
||||
module.exports = false
|
105
red/api/editor/locales/en-US/editor.json → packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
vendored
Normal file → Executable file
@@ -23,11 +23,11 @@
|
||||
"confirmDelete": "Confirm delete",
|
||||
"delete": "Are you sure you want to delete '__label__'?",
|
||||
"dropFlowHere": "Drop the flow here",
|
||||
"addFlow": "Add Flow",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
"disabled":"Disabled",
|
||||
"info": "Description",
|
||||
"tip": "Description accepts Markdown and will appear in the Info tab."
|
||||
"info": "Description"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
@@ -46,6 +46,9 @@
|
||||
"sidebar": {
|
||||
"show": "Show sidebar"
|
||||
},
|
||||
"palette": {
|
||||
"show": "Show palette"
|
||||
},
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"nodes": "Nodes",
|
||||
@@ -75,9 +78,16 @@
|
||||
"projects": "Projects",
|
||||
"projects-new": "New",
|
||||
"projects-open": "Open",
|
||||
"projects-settings": "Project Settings"
|
||||
"projects-settings": "Project Settings",
|
||||
"showNodeLabelDefault": "Show label of newly added nodes"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "Toggle navigator",
|
||||
"zoom-out": "Zoom out",
|
||||
"zoom-reset": "Reset zoom",
|
||||
"zoom-in": "Zoom in"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "Logged in as __name__",
|
||||
"username": "Username",
|
||||
@@ -95,8 +105,10 @@
|
||||
"warning": "<strong>Warning</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "node has undeployed changes",
|
||||
"nodeActionDisabled": "node actions disabled within subflow",
|
||||
"nodeActionDisabled": "node actions disabled",
|
||||
"nodeActionDisabledSubflow": "node actions disabled within subflow",
|
||||
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
||||
"safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
||||
"credentials_load_failed_reset":"<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
||||
@@ -106,7 +118,6 @@
|
||||
"project_not_found": "<p>Project '__project__' not found.</p>",
|
||||
"git_merge_conflict": "<p>Automatic merging of changes failed.</p><p>Fix the unmerged conflicts then commit the results.</p>"
|
||||
},
|
||||
|
||||
"error": "<strong>Error</strong>: __message__",
|
||||
"errors": {
|
||||
"lostConnection": "Lost connection to server, reconnecting...",
|
||||
@@ -123,7 +134,7 @@
|
||||
"loaded": "Project '__project__' loaded",
|
||||
"updated": "Project '__project__' updated",
|
||||
"pull": "Project '__project__' reloaded",
|
||||
"revert": "Project '__project__' reloaded",
|
||||
"revert": "Project '__project__' reverted",
|
||||
"merge-complete": "Git merge completed"
|
||||
},
|
||||
"label": {
|
||||
@@ -138,13 +149,24 @@
|
||||
},
|
||||
"clipboard": {
|
||||
"nodes": "Nodes",
|
||||
"node": "__count__ node",
|
||||
"node_plural": "__count__ nodes",
|
||||
"configNode": "__count__ configuration node",
|
||||
"configNode_plural": "__count__ configuration nodes",
|
||||
"flow": "__count__ flow",
|
||||
"flow_plural": "__count__ flows",
|
||||
"subflow": "__count__ subflow",
|
||||
"subflow_plural": "__count__ subflows",
|
||||
"selectNodes": "Select the text above and copy to the clipboard.",
|
||||
"pasteNodes": "Paste nodes here",
|
||||
"pasteNodes": "Paste flow json or",
|
||||
"selectFile": "select a file to import",
|
||||
"importNodes": "Import nodes",
|
||||
"exportNodes": "Export nodes to clipboard",
|
||||
"exportNodes": "Export nodes",
|
||||
"download": "Download",
|
||||
"importUnrecognised": "Imported unrecognised type:",
|
||||
"importUnrecognised_plural": "Imported unrecognised types:",
|
||||
"nodesExported": "Nodes exported to clipboard",
|
||||
"nodesImported": "Imported:",
|
||||
"nodeCopied": "__count__ node copied",
|
||||
"nodeCopied_plural": "__count__ nodes copied",
|
||||
"invalidFlow": "Invalid flow: __message__",
|
||||
@@ -158,7 +180,13 @@
|
||||
},
|
||||
"import": {
|
||||
"import": "Import to",
|
||||
"newFlow": "new flow"
|
||||
"newFlow": "new flow",
|
||||
"errors": {
|
||||
"notArray": "Input not a JSON Array",
|
||||
"itemNotObject": "Input not a valid flow - item __index__ not a node object",
|
||||
"missingId": "Input not a valid flow - item __index__ missing 'id' property",
|
||||
"missingType": "Input not a valid flow - item __index__ missing 'type' property"
|
||||
}
|
||||
},
|
||||
"copyMessagePath": "Path copied",
|
||||
"copyMessageValue": "Value copied",
|
||||
@@ -172,7 +200,10 @@
|
||||
"modifiedFlowsDesc": "Only deploys flows that contain changed nodes",
|
||||
"modifiedNodes": "Modified Nodes",
|
||||
"modifiedNodesDesc": "Only deploys nodes that have changed",
|
||||
"restartFlows": "Restart Flows",
|
||||
"restartFlowsDesc": "Restarts the current deployed flows",
|
||||
"successfulDeploy": "Successfully deployed",
|
||||
"successfulRestart": "Successfully restarted flows",
|
||||
"deployFailed": "Deploy failed: __message__",
|
||||
"unusedConfigNodes":"You have some unused configuration nodes.",
|
||||
"unusedConfigNodesLink":"Click here to see them",
|
||||
@@ -201,6 +232,10 @@
|
||||
"plusNMore": "+ __count__ more"
|
||||
}
|
||||
},
|
||||
"eventLog": {
|
||||
"title": "Event log",
|
||||
"view": "View log"
|
||||
},
|
||||
"diff": {
|
||||
"unresolvedCount": "__count__ unresolved conflict",
|
||||
"unresolvedCount_plural": "__count__ unresolved conflicts",
|
||||
@@ -241,7 +276,6 @@
|
||||
"deleteSubflow": "delete subflow",
|
||||
"info": "Description",
|
||||
"category": "Category",
|
||||
"format":"markdown format",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
|
||||
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
|
||||
@@ -259,7 +293,8 @@
|
||||
"editConfig": "Edit __type__ config node",
|
||||
"addNewType": "Add new __type__...",
|
||||
"nodeProperties": "node properties",
|
||||
"portLabels": "node settings",
|
||||
"label": "Label",
|
||||
"portLabels": "Port labels",
|
||||
"labelInputs": "Inputs",
|
||||
"labelOutputs": "Outputs",
|
||||
"settingIcon": "Icon",
|
||||
@@ -267,6 +302,9 @@
|
||||
"defaultLabel": "use default label",
|
||||
"searchIcons": "Search icons",
|
||||
"useDefault": "use default",
|
||||
"description": "Description",
|
||||
"show": "Show",
|
||||
"hide": "Hide",
|
||||
"errors": {
|
||||
"scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it"
|
||||
}
|
||||
@@ -290,6 +328,7 @@
|
||||
"nudgeNode": "Move selected nodes (1px)",
|
||||
"moveNode": "Move selected nodes (20px)",
|
||||
"toggleSidebar": "Toggle sidebar",
|
||||
"togglePalette": "Toggle palette",
|
||||
"copyNode": "Copy selected nodes",
|
||||
"cutNode": "Cut selected nodes",
|
||||
"pasteNode": "Paste nodes",
|
||||
@@ -330,6 +369,10 @@
|
||||
"analysis": "analysis",
|
||||
"advanced": "advanced"
|
||||
},
|
||||
"actions": {
|
||||
"collapse-all": "Collapse all categories",
|
||||
"expand-all": "Expand all categories"
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "Node added to palette:",
|
||||
"nodeAdded_plural": "Nodes added to palette",
|
||||
@@ -377,6 +420,8 @@
|
||||
"updated": "updated",
|
||||
"install": "install",
|
||||
"installed": "installed",
|
||||
"conflict": "conflict",
|
||||
"conflictTip": "<p>This module cannot be installed as it includes a<br/>node type that has already been installed</p><p>Conflicts with <code>__module__</code></p>",
|
||||
"loading": "Loading catalogues...",
|
||||
"tab-nodes": "Nodes",
|
||||
"tab-install": "Install",
|
||||
@@ -415,7 +460,6 @@
|
||||
"update": "Update"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
@@ -425,6 +469,7 @@
|
||||
"label": "info",
|
||||
"node": "Node",
|
||||
"type": "Type",
|
||||
"module": "Module",
|
||||
"id": "ID",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
@@ -433,6 +478,7 @@
|
||||
"instances": "Instances",
|
||||
"properties": "Properties",
|
||||
"info": "Information",
|
||||
"desc": "Description",
|
||||
"blank": "blank",
|
||||
"null": "null",
|
||||
"showMore": "show more",
|
||||
@@ -466,7 +512,8 @@
|
||||
"empty": "empty",
|
||||
"node": "Node",
|
||||
"flow": "Flow",
|
||||
"global": "Global"
|
||||
"global": "Global",
|
||||
"deleteConfirm": "Are you sure you want to delete this item?"
|
||||
},
|
||||
"palette": {
|
||||
"name": "Palette management",
|
||||
@@ -482,7 +529,9 @@
|
||||
"editDescription": "Edit project description",
|
||||
"editDependencies": "Edit project dependencies",
|
||||
"editReadme": "Edit README.md",
|
||||
"showProjectSettings": "Show project settings",
|
||||
"projectSettings": {
|
||||
"title": "Project Settings",
|
||||
"edit": "edit",
|
||||
"none": "None",
|
||||
"install": "install",
|
||||
@@ -544,6 +593,11 @@
|
||||
"versionControl": {
|
||||
"unstagedChanges": "Unstaged changes",
|
||||
"stagedChanges": "Staged changes",
|
||||
"unstageChange": "Unstage change",
|
||||
"stageChange": "Stage change",
|
||||
"unstageAllChange": "Unstage all changes",
|
||||
"stageAllChange": "Stage all changes",
|
||||
"commitChanges": "Commit changes",
|
||||
"resolveConflicts": "Resolve conflicts",
|
||||
"head": "HEAD",
|
||||
"staged": "Staged",
|
||||
@@ -587,6 +641,7 @@
|
||||
"pullUnrelatedHistory": "<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",
|
||||
"pullChanges": "Pull changes",
|
||||
"history": "history",
|
||||
"projectHistory": "Project History",
|
||||
"daysAgo": "__count__ day ago",
|
||||
"daysAgo_plural": "__count__ days ago",
|
||||
"hoursAgo": "__count__ hour ago",
|
||||
@@ -606,7 +661,9 @@
|
||||
"commitsAheadAndBehind2": "__count__ commit ahead of the remote. ",
|
||||
"commitsAheadAndBehind2_plural": "__count__ commits ahead of the remote. ",
|
||||
"commitsAheadAndBehind3": "You must pull the remote commit down before pushing.",
|
||||
"commitsAheadAndBehind3_plural": "You must pull the remote commits down before pushing."
|
||||
"commitsAheadAndBehind3_plural": "You must pull the remote commits down before pushing.",
|
||||
"refreshCommitHistory": "Refresh commit history",
|
||||
"refreshChanges": "Refresh changes"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -657,7 +714,20 @@
|
||||
"format": "format JSON"
|
||||
},
|
||||
"markdownEditor": {
|
||||
"title": "Markdown editor"
|
||||
"title": "Markdown editor",
|
||||
"format": "Formatted with markdown",
|
||||
"heading1": "Heading 1",
|
||||
"heading2": "Heading 2",
|
||||
"heading3": "Heading 3",
|
||||
"bold": "Bold",
|
||||
"italic": "Italic",
|
||||
"code": "Code",
|
||||
"ordered-list": "Ordered list",
|
||||
"unordered-list": "Unordered list",
|
||||
"quote": "Quote",
|
||||
"link": "Link",
|
||||
"horizontal-rule": "Horizontal rule",
|
||||
"toggle-preview": "Toggle preview"
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "Buffer editor",
|
||||
@@ -827,5 +897,10 @@
|
||||
"unexpected": "An unexpected error occurred",
|
||||
"code": "code"
|
||||
}
|
||||
},
|
||||
"editor-tab": {
|
||||
"properties": "Properties",
|
||||
"description": "Description",
|
||||
"appearance": "Appearance"
|
||||
}
|
||||
}
|
14
red/api/editor/locales/en-US/jsonata.json → packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json
vendored
Normal file → Executable file
@@ -115,7 +115,6 @@
|
||||
"args": "array",
|
||||
"desc": "Returns the mean value of an `array` of numbers. It is an error if the input `array` contains an item which isn't a number."
|
||||
},
|
||||
|
||||
"$boolean": {
|
||||
"args": "arg",
|
||||
"desc": "Casts the argument to a Boolean using the following rules:\n\n - `Boolean` : unchanged\n - `string`: empty : `false`\n - `string`: non-empty : `true`\n - `number`: `0` : `false`\n - `number`: non-zero : `true`\n - `null` : `false`\n - `array`: empty : `false`\n - `array`: contains a member that casts to `true` : `true`\n - `array`: all members cast to `false` : `false`\n - `object`: empty : `false`\n - `object`: non-empty : `true`\n - `function` : `false`"
|
||||
@@ -219,5 +218,18 @@
|
||||
"$env": {
|
||||
"args": "arg",
|
||||
"desc": "Returns the value of an environment variable.\n\nThis is a Node-RED defined function."
|
||||
},
|
||||
"$eval": {
|
||||
"args": "expr [, context]",
|
||||
"desc": "Parses and evaluates the string `expr` which contains literal JSON or a JSONata expression using the current context as the context for evaluation."
|
||||
},
|
||||
"$formatInteger": {
|
||||
"args": "number, picture",
|
||||
"desc": "Casts the `number` to a string and formats it to an integer representation as specified by the `picture` string. The picture string parameter defines how the number is formatted and has the same syntax as `fn:format-integer` from the XPath F&O 3.1 specification."
|
||||
},
|
||||
"$parseInteger": {
|
||||
"args": "string, picture",
|
||||
"desc": "Parses the contents of the `string` parameter to an integer (as a JSON number) using the format specified by the `picture` string. The `picture` string parameter has the same format as `$formatInteger`."
|
||||
|
||||
}
|
||||
}
|
133
red/api/editor/locales/ja/editor.json → packages/node_modules/@node-red/editor-client/locales/ja/editor.json
vendored
Normal file → Executable file
@@ -23,11 +23,11 @@
|
||||
"confirmDelete": "削除の確認",
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
"info": "詳細",
|
||||
"tip": "マークダウン形式で記述した「詳細」は「情報タブ」に表示されます。"
|
||||
"info": "詳細"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
@@ -46,6 +46,9 @@
|
||||
"sidebar": {
|
||||
"show": "サイドバーを表示"
|
||||
},
|
||||
"palette": {
|
||||
"show": "パレットを表示"
|
||||
},
|
||||
"settings": "設定",
|
||||
"userSettings": "ユーザ設定",
|
||||
"nodes": "ノード",
|
||||
@@ -75,9 +78,16 @@
|
||||
"projects": "プロジェクト",
|
||||
"projects-new": "新規",
|
||||
"projects-open": "開く",
|
||||
"projects-settings": "設定"
|
||||
"projects-settings": "設定",
|
||||
"showNodeLabelDefault": "追加したノードのラベルを表示する"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "ナビゲータの表示/非表示を切替",
|
||||
"zoom-out": "縮小",
|
||||
"zoom-reset": "拡大/縮小を初期化",
|
||||
"zoom-in": "拡大"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "__name__ としてログインしました",
|
||||
"username": "ユーザ名",
|
||||
@@ -95,8 +105,10 @@
|
||||
"warning": "<strong>警告</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "ノードの変更をデプロイしていません",
|
||||
"nodeActionDisabled": "ノードのアクションは、サブフロー内で無効になっています",
|
||||
"nodeActionDisabled": "ノードのアクションは無効になっています",
|
||||
"nodeActionDisabledSubflow": "ノードのアクションは、サブフロー内で無効になっています",
|
||||
"missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください。",
|
||||
"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>",
|
||||
@@ -113,7 +125,7 @@
|
||||
"lostConnectionTry": "すぐに接続",
|
||||
"cannotAddSubflowToItself": "サブフロー自身を追加できません",
|
||||
"cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません",
|
||||
"unsupportedVersion": "サポートされていないバージョンのNode.jsを使用しています。<br/>最新のNode.js LTSに更新してください。",
|
||||
"unsupportedVersion": "<p>サポートされていないバージョンのNode.jsを使用しています。</p><p><br/>最新のNode.js LTSに更新してください。</p>",
|
||||
"failedToAppendNode": "<p>'__module__'がロードできませんでした。</p><p>__error__</p>"
|
||||
},
|
||||
"project": {
|
||||
@@ -122,7 +134,7 @@
|
||||
"loaded": "プロジェクト'__project__'をロードしました",
|
||||
"updated": "プロジェクト'__project__'を更新しました",
|
||||
"pull": "プロジェクト'__project__'を再ロードしました",
|
||||
"revert": "プロジェクト'__project__'を再ロードしました",
|
||||
"revert": "プロジェクト'__project__'を取り消しました",
|
||||
"merge-complete": "Gitマージが完了しました"
|
||||
},
|
||||
"label": {
|
||||
@@ -137,13 +149,24 @@
|
||||
},
|
||||
"clipboard": {
|
||||
"nodes": "ノード",
|
||||
"node": "__count__ 個のノード",
|
||||
"node_plural": "__count__ 個のノード",
|
||||
"configNode": "__count__ 個の設定ノード",
|
||||
"configNode_plural": "__count__ 個の設定ノード",
|
||||
"flow": "__count__ 個のフロー",
|
||||
"flow_plural": "__count__ 個のフロー",
|
||||
"subflow": "__count__ 個のサブフロー",
|
||||
"subflow_plural": "__count__ 個のサブフロー",
|
||||
"selectNodes": "上のテキストを選択し、クリップボードへコピーしてください",
|
||||
"pasteNodes": "JSON形式のフローデータを貼り付けてください",
|
||||
"selectFile": "読み込むファイルを選択してください",
|
||||
"importNodes": "フローをクリップボートから読み込み",
|
||||
"exportNodes": "フローをクリップボードへ書き出し",
|
||||
"download": "ダウンロード",
|
||||
"importUnrecognised": "認識できない型が読み込まれました:",
|
||||
"importUnrecognised_plural": "認識できない型が読み込まれました:",
|
||||
"nodesExported": "クリップボードへフローを書き出しました",
|
||||
"nodesImported": "読み込みました:",
|
||||
"nodeCopied": "__count__ 個のノードをコピーしました",
|
||||
"nodeCopied_plural": "__count__ 個のノードをコピーしました",
|
||||
"invalidFlow": "不正なフロー: __message__",
|
||||
@@ -157,7 +180,13 @@
|
||||
},
|
||||
"import": {
|
||||
"import": "読み込み先",
|
||||
"newFlow": "新規のタブ"
|
||||
"newFlow": "新規のタブ",
|
||||
"errors": {
|
||||
"notArray": "JSON形式の配列ではありません",
|
||||
"itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません",
|
||||
"missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません",
|
||||
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
|
||||
}
|
||||
},
|
||||
"copyMessagePath": "パスをコピーしました",
|
||||
"copyMessageValue": "値をコピーしました",
|
||||
@@ -171,7 +200,10 @@
|
||||
"modifiedFlowsDesc": "変更したノードを含むフローのみデプロイ",
|
||||
"modifiedNodes": "変更したノード",
|
||||
"modifiedNodesDesc": "変更したノードのみデプロイ",
|
||||
"restartFlows": "フローを再起動",
|
||||
"restartFlowsDesc": "デプロイされた現在のフローを再起動",
|
||||
"successfulDeploy": "デプロイが成功しました",
|
||||
"successfulRestart": "フローの再起動が成功しました",
|
||||
"deployFailed": "デプロイが失敗しました: __message__",
|
||||
"unusedConfigNodes": "使われていない「ノードの設定」があります。",
|
||||
"unusedConfigNodesLink": "設定を参照する",
|
||||
@@ -192,7 +224,7 @@
|
||||
"unknown": "ワークスペースに未知の型のノードがあります。",
|
||||
"confirm": "このままデプロイしても良いですか?",
|
||||
"doNotWarn": "この警告を再度表示しない",
|
||||
"conflict": "フローを編集している間に、他のブラウザがフローをデプロイしました。デプロイを継続すると、他のブラウザがデプロイしたフローが削除されます。",
|
||||
"conflict": "フローを編集している間に、他のブラウザがフローをデプロイしました。",
|
||||
"backgroundUpdate": "サーバ上のフローが更新されました",
|
||||
"conflictChecking": "変更を自動的にマージしてよいか確認してください。",
|
||||
"conflictAutoMerge": "変更の衝突がないため、自動的にマージできます。",
|
||||
@@ -200,6 +232,10 @@
|
||||
"plusNMore": "さらに __count__ 個"
|
||||
}
|
||||
},
|
||||
"eventLog": {
|
||||
"title": "イベントログ",
|
||||
"view": "ログを確認"
|
||||
},
|
||||
"diff": {
|
||||
"unresolvedCount": "未解決の衝突 __count__",
|
||||
"unresolvedCount_plural": "未解決の衝突 __count__",
|
||||
@@ -240,7 +276,6 @@
|
||||
"deleteSubflow": "サブフローを削除",
|
||||
"info": "詳細",
|
||||
"category": "カテゴリ",
|
||||
"format": "マークダウン形式",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません",
|
||||
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
|
||||
@@ -258,14 +293,18 @@
|
||||
"editConfig": "__type__ ノードの設定を編集",
|
||||
"addNewType": "新規に __type__ を追加...",
|
||||
"nodeProperties": "プロパティ",
|
||||
"portLabels": "設定",
|
||||
"label": "ラベル",
|
||||
"portLabels": "ポートラベル",
|
||||
"labelInputs": "入力",
|
||||
"labelOutputs": "出力",
|
||||
"settingIcon": "アイコン",
|
||||
"noDefaultLabel": "なし",
|
||||
"defaultLabel": "既定の名前を使用",
|
||||
"defaultLabel": "既定のラベルを使用",
|
||||
"searchIcons": "アイコンを検索",
|
||||
"useDefault": "デフォルトを使用",
|
||||
"useDefault": "デフォルトを使用",
|
||||
"description": "詳細",
|
||||
"show": "表示",
|
||||
"hide": "非表示",
|
||||
"errors": {
|
||||
"scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします"
|
||||
}
|
||||
@@ -288,7 +327,8 @@
|
||||
"exportNode": "フローの書き出し",
|
||||
"nudgeNode": "選択したノードを移動(移動量小)",
|
||||
"moveNode": "選択したノードを移動(移動量大)",
|
||||
"toggleSidebar": "サイドバーの表示非表示",
|
||||
"toggleSidebar": "サイドバーの表示/非表示",
|
||||
"togglePalette": "パレットの表示/非表示",
|
||||
"copyNode": "選択したノードをコピー",
|
||||
"cutNode": "選択したノードを切り取り",
|
||||
"pasteNode": "ノードを貼り付け",
|
||||
@@ -329,6 +369,10 @@
|
||||
"analysis": "分析",
|
||||
"advanced": "その他"
|
||||
},
|
||||
"actions": {
|
||||
"collapse-all": "全カテゴリを折畳む",
|
||||
"expand-all": "全カテゴリを展開"
|
||||
},
|
||||
"event": {
|
||||
"nodeAdded": "ノードをパレットへ追加しました:",
|
||||
"nodeAdded_plural": "ノードをパレットへ追加しました",
|
||||
@@ -376,6 +420,8 @@
|
||||
"updated": "更新済",
|
||||
"install": "ノードを追加",
|
||||
"installed": "追加しました",
|
||||
"conflict": "競合",
|
||||
"conflictTip": "<p>インストール済みのノードの種別と競合しているため<br/>ノードをインストールできません</p><p>競合: <code>__module__</code></p>",
|
||||
"loading": "カタログを読み込み中",
|
||||
"tab-nodes": "現在のノード",
|
||||
"tab-install": "ノードを追加",
|
||||
@@ -384,28 +430,28 @@
|
||||
"sortRecent": "日付順",
|
||||
"more": "+ さらに __count__ 個",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "ノードのカタログの読み込みに失敗しました。<br>詳細はブラウザのコンソールを確認してください。",
|
||||
"installFailed": "追加処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください。",
|
||||
"removeFailed": "削除処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください。",
|
||||
"updateFailed": "更新処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください。",
|
||||
"enableFailed": "有効化処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください。",
|
||||
"disableFailed": "無効化処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください。"
|
||||
"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": "ノードを追加する前に、ドキュメントを確認してください。ノードによっては、モジュールの依存関係を自動的に解決できない場合や、Node-REDの再起動が必要となる場合があります。",
|
||||
"body": "<p>__module__ をインストールします。</p><p>ノードを追加する前に、ドキュメントを確認してください。ノードによっては、モジュールの依存関係を自動的に解決できない場合や、Node-REDの再起動が必要となる場合があります。</p>",
|
||||
"title": "ノードを追加"
|
||||
},
|
||||
"remove": {
|
||||
"body": "Node-REDからノードを削除します。ノードはNode-REDが再起動されるまで、リソースを使い続けます。",
|
||||
"body": "<p>__module__ を削除します。</p><p>Node-REDからノードを削除します。ノードはNode-REDが再起動されるまで、リソースを使い続ける可能性があります。</p>",
|
||||
"title": "ノードを削除"
|
||||
},
|
||||
"update": {
|
||||
"body": "更新を完了するには手動でNode-REDを再起動する必要があります。",
|
||||
"body": "<p>__module__ を更新します。</p><p>更新を完了するには手動でNode-REDを再起動する必要があります。</p>",
|
||||
"title": "ノードの更新"
|
||||
},
|
||||
"cannotUpdate": {
|
||||
"body": "ノードの更新があります。「パレットの管理」の画面では更新されません。ドキュメントを参照し、ノードの更新手順を確認してください。"
|
||||
"body": "ノードの更新があります。「パレットの管理」の画面では更新されません。<br/><br/>ドキュメントを参照し、ノードの更新手順を確認してください。"
|
||||
},
|
||||
"button": {
|
||||
"review": "ノードの情報を参照",
|
||||
@@ -423,6 +469,7 @@
|
||||
"label": "情報",
|
||||
"node": "ノード",
|
||||
"type": "型",
|
||||
"module": "モジュール",
|
||||
"id": "ID",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
@@ -431,6 +478,7 @@
|
||||
"instances": "インスタンス",
|
||||
"properties": "プロパティ",
|
||||
"info": "情報",
|
||||
"desc": "詳細",
|
||||
"blank": "ブランク",
|
||||
"null": "ヌル",
|
||||
"showMore": "さらに表示",
|
||||
@@ -464,7 +512,8 @@
|
||||
"empty": "データが存在しません",
|
||||
"node": "Node",
|
||||
"flow": "Flow",
|
||||
"global": "Global"
|
||||
"global": "Global",
|
||||
"deleteConfirm": "データを削除しても良いですか?"
|
||||
},
|
||||
"palette": {
|
||||
"name": "パレットの管理",
|
||||
@@ -480,7 +529,9 @@
|
||||
"editDescription": "プロジェクトの詳細を編集",
|
||||
"editDependencies": "プロジェクトの依存関係を編集",
|
||||
"editReadme": "README.mdを編集",
|
||||
"showProjectSettings": "プロジェクト設定を表示",
|
||||
"projectSettings": {
|
||||
"title": "プロジェクト設定",
|
||||
"edit": "編集",
|
||||
"none": "なし",
|
||||
"install": "インストール",
|
||||
@@ -542,6 +593,11 @@
|
||||
"versionControl": {
|
||||
"unstagedChanges": "ステージングされていない変更",
|
||||
"stagedChanges": "ステージングされた変更",
|
||||
"unstageChange": "ステージングした変更の取り消し",
|
||||
"stageChange": "変更をステージング",
|
||||
"unstageAllChange": "ステージングした全ての変更の取り消し",
|
||||
"stageAllChange": "全ての変更をステージング",
|
||||
"commitChanges": "変更をコミット",
|
||||
"resolveConflicts": "コンフリクトの解決",
|
||||
"head": "最新",
|
||||
"staged": "ステージング",
|
||||
@@ -585,6 +641,7 @@
|
||||
"pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>",
|
||||
"pullChanges": "プル変更",
|
||||
"history": "履歴",
|
||||
"projectHistory": "プロジェクト履歴",
|
||||
"daysAgo": "__count__ 日前",
|
||||
"daysAgo_plural": "__count__ 日前",
|
||||
"hoursAgo": "__count__ 時間前",
|
||||
@@ -604,7 +661,9 @@
|
||||
"commitsAheadAndBehind2": "__count__コミット進んでいます。 ",
|
||||
"commitsAheadAndBehind2_plural": "__count__コミット進んでいます。 ",
|
||||
"commitsAheadAndBehind3": "プッシュする前にリモートのコミットをプルしてください。",
|
||||
"commitsAheadAndBehind3_plural": "プッシュする前にリモートのコミットをプルしてください。"
|
||||
"commitsAheadAndBehind3_plural": "プッシュする前にリモートのコミットをプルしてください。",
|
||||
"refreshCommitHistory": "コミット履歴を更新",
|
||||
"refreshChanges": "変更を更新"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -655,7 +714,20 @@
|
||||
"format": "JSONフォーマット"
|
||||
},
|
||||
"markdownEditor": {
|
||||
"title": "マークダウンエディタ"
|
||||
"title": "マークダウンエディタ",
|
||||
"format": "マークダウン形式で記述",
|
||||
"heading1": "見出しレベル1",
|
||||
"heading2": "見出しレベル2",
|
||||
"heading3": "見出しレベル3",
|
||||
"bold": "太字",
|
||||
"italic": "斜体",
|
||||
"code": "コード",
|
||||
"ordered-list": "箇条書き(番号付き)",
|
||||
"unordered-list": "箇条書き",
|
||||
"quote": "引用",
|
||||
"link": "リンク",
|
||||
"horizontal-rule": "区切り線",
|
||||
"toggle-preview": "プレビュー表示切替え"
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "バッファエディタ",
|
||||
@@ -719,7 +791,7 @@
|
||||
"repo-not-found": "リポジトリが見つかりません"
|
||||
},
|
||||
"default-files": {
|
||||
"create": "プロジェクト関連ファアイルの作成",
|
||||
"create": "プロジェクト関連ファイルの作成",
|
||||
"desc0": "プロジェクトはフローファイル、README、package.jsonを含みます。",
|
||||
"desc1": "その他、Gitリポジトリで管理したいファイルを含めても構いません。",
|
||||
"desc2": "既存のフローと認証情報ファイルをプロジェクトにコピーします。",
|
||||
@@ -735,7 +807,7 @@
|
||||
"desc4": "認証情報を公開Gitリポジトリに保存する際には、秘密キーフレーズによって暗号化します。",
|
||||
"desc5": "フロー認証情報ファイルはsettingsファイルのcredentialSecretプロパティで暗号化されています。",
|
||||
"desc6": "フロー認証情報ファイルはシステムが生成したキーによって暗号化されています。このプロジェクト用に新しい秘密キーを指定してください。",
|
||||
"desc7": "キーはプロジェクトファイルとば別に保存されます。他のNode-REDでこのプロジェクトを利用するには、このプロジェクトのキーが必要です。",
|
||||
"desc7": "キーはプロジェクトファイルとは別に保存されます。他のNode-REDでこのプロジェクトを利用するには、このプロジェクトのキーが必要です。",
|
||||
"credentials": "認証情報",
|
||||
"enable": "暗号化を有効にする",
|
||||
"disable": "暗号化を無効にする",
|
||||
@@ -825,5 +897,10 @@
|
||||
"unexpected": "予期しないエラーが発生しました",
|
||||
"code": "コード"
|
||||
}
|
||||
},
|
||||
"editor-tab": {
|
||||
"properties": "プロパティ",
|
||||
"description": "説明",
|
||||
"appearance": "外観"
|
||||
}
|
||||
}
|
@@ -22,8 +22,7 @@
|
||||
"status": "状态",
|
||||
"enabled": "有效",
|
||||
"disabled": "无效",
|
||||
"info": "详细描述",
|
||||
"tip": "详细描述支持Markdown轻量级标记语言,并将出现在信息标签中。"
|
||||
"info": "详细描述"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
@@ -86,7 +85,7 @@
|
||||
"warning": "<strong>警告</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "节点中存在未部署的更改",
|
||||
"nodeActionDisabled": "节点动作在子流程中被禁用",
|
||||
"nodeActionDisabledSubflow": "节点动作在子流程中被禁用",
|
||||
"missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息",
|
||||
"restartRequired": "Node-RED必须重新启动,以启用升级的模块"
|
||||
},
|
||||
@@ -191,7 +190,6 @@
|
||||
"output": "输出:",
|
||||
"deleteSubflow": "删除子流程",
|
||||
"info": "详细描述",
|
||||
"format": "标记格式",
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点",
|
||||
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"
|
18
packages/node_modules/@node-red/editor-client/package.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "0.20.0-beta.3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"main": "./lib/index.js"
|
||||
}
|
50
packages/node_modules/@node-red/editor-client/src/ace/README.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
How to build the custom ACE modes for Node-RED
|
||||
----------------------------------------------
|
||||
|
||||
Node-RED includes custom JSONata and JavaScript modes.
|
||||
|
||||
|
||||
## JSONata
|
||||
|
||||
The `ace/mode/jsonata` mode is maintained under `editor-client/src/vendor/jsonata`.
|
||||
Those files are edited in place and copied into the build by Grunt.
|
||||
|
||||
## JavaScript
|
||||
|
||||
The `ace/mode/nrjavascript` mode is used exclusively by the Function node. It
|
||||
inherits almost entirely from the normal JavaScript mode. The one key difference
|
||||
is that it wraps the code with a Function before parsing. This is required to
|
||||
avoid some false-flagged errors.
|
||||
|
||||
The source of the mode is under `editor-client/src/ace/mode`. If those files are
|
||||
modified in anyway, they *must* be manually built to generate the files under
|
||||
`editor-client/src/ace/bin` and checked in. Those files are the ones the Grunt
|
||||
built copies out in the Node-RED build.
|
||||
|
||||
### Building the mode files
|
||||
|
||||
|
||||
#### Setup build environment
|
||||
|
||||
cd /tmp/
|
||||
git clone https://github.com/ajaxorg/ace.git
|
||||
cd ace
|
||||
npm install
|
||||
|
||||
#### Copy mode src files into build environment
|
||||
|
||||
cd <node-red-source-directory
|
||||
cp packages/node_modules/@node-red/editor-client/src/ace/mode/* \
|
||||
/tmp/ace/lib/ace/mode/
|
||||
|
||||
#### Run the build
|
||||
|
||||
cd /tmp/ace
|
||||
node ./Makefile.dryice.js -m -nc
|
||||
|
||||
#### Copy the built versions back
|
||||
|
||||
cp build/src-min-noconflict/*-nrjavascript.js \
|
||||
<node-red-source-directory>/packages/node_modules/@node-red/editor-client/src/ace/bin/
|
||||
cp build/src-min-noconflict/snippets/nrjavascript.js \
|
||||
<node-red-source-directory>/packages/node_modules/@node-red/editor-client/src/ace/bin/snippets/
|
9
packages/node_modules/@node-red/editor-client/src/ace/bin/mode-nrjavascript.js
vendored
Normal file
9
packages/node_modules/@node-red/editor-client/src/ace/bin/snippets/nrjavascript.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="nrjavascript"});
|
||||
(function() {
|
||||
ace.require(["ace/snippets/nrjavascript"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
1
packages/node_modules/@node-red/editor-client/src/ace/bin/worker-nrjavascript.js
vendored
Normal file
49
packages/node_modules/@node-red/editor-client/src/ace/mode/nrjavascript.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var JavaScriptMode = require("./javascript").Mode;
|
||||
var WorkerClient = require("../worker/worker_client").WorkerClient;
|
||||
|
||||
var Mode = function() {
|
||||
// Inherit everything from the standard JavaScript mode
|
||||
JavaScriptMode.call(this);
|
||||
};
|
||||
oop.inherits(Mode, JavaScriptMode);
|
||||
|
||||
(function() {
|
||||
// Insert our custom worker
|
||||
this.createWorker = function(session) {
|
||||
var worker = new WorkerClient(["ace"], "ace/mode/nrjavascript_worker", "NRJavaScriptWorker");
|
||||
worker.attachToDocument(session.getDocument());
|
||||
|
||||
worker.on("annotate", function(results) {
|
||||
session.setAnnotations(results.data);
|
||||
});
|
||||
|
||||
worker.on("terminate", function() {
|
||||
session.clearAnnotations();
|
||||
});
|
||||
|
||||
return worker;
|
||||
};
|
||||
|
||||
this.$id = "ace/mode/nrjavascript";
|
||||
}).call(Mode.prototype);
|
||||
exports.Mode = Mode;
|
||||
});
|
189
packages/node_modules/@node-red/editor-client/src/ace/mode/nrjavascript_worker.js
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var Mirror = require("../worker/mirror").Mirror;
|
||||
var lint = require("./javascript/jshint").JSHINT;
|
||||
|
||||
function startRegex(arr) {
|
||||
return RegExp("^(" + arr.join("|") + ")");
|
||||
}
|
||||
|
||||
var disabledWarningsRe = startRegex([
|
||||
"Bad for in variable '(.+)'.",
|
||||
'Missing "use strict"'
|
||||
]);
|
||||
var errorsRe = startRegex([
|
||||
"Unexpected",
|
||||
"Expected ",
|
||||
"Confusing (plus|minus)",
|
||||
"\\{a\\} unterminated regular expression",
|
||||
"Unclosed ",
|
||||
"Unmatched ",
|
||||
"Unbegun comment",
|
||||
"Bad invocation",
|
||||
"Missing space after",
|
||||
"Missing operator at"
|
||||
]);
|
||||
var infoRe = startRegex([
|
||||
"Expected an assignment",
|
||||
"Bad escapement of EOL",
|
||||
"Unexpected comma",
|
||||
"Unexpected space",
|
||||
"Missing radix parameter.",
|
||||
"A leading decimal point can",
|
||||
"\\['{a}'\\] is better written in dot notation.",
|
||||
"'{a}' used out of scope"
|
||||
]);
|
||||
|
||||
var NRJavaScriptWorker = exports.NRJavaScriptWorker = function(sender) {
|
||||
Mirror.call(this, sender);
|
||||
this.setTimeout(500);
|
||||
this.setOptions();
|
||||
};
|
||||
|
||||
oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
|
||||
(function() {
|
||||
this.setOptions = function(options) {
|
||||
this.options = options || {
|
||||
// undef: true,
|
||||
// unused: true,
|
||||
esnext: true,
|
||||
moz: true,
|
||||
devel: true,
|
||||
browser: true,
|
||||
node: true,
|
||||
laxcomma: true,
|
||||
laxbreak: true,
|
||||
lastsemic: true,
|
||||
onevar: false,
|
||||
passfail: false,
|
||||
maxerr: 100,
|
||||
expr: true,
|
||||
multistr: true,
|
||||
globalstrict: true
|
||||
};
|
||||
this.doc.getValue() && this.deferredUpdate.schedule(100);
|
||||
};
|
||||
|
||||
this.changeOptions = function(newOptions) {
|
||||
oop.mixin(this.options, newOptions);
|
||||
this.doc.getValue() && this.deferredUpdate.schedule(100);
|
||||
};
|
||||
|
||||
this.isValidJS = function(str) {
|
||||
try {
|
||||
// evaluated code can only create variables in this function
|
||||
eval("throw 0;" + str);
|
||||
} catch(e) {
|
||||
if (e === 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.onUpdate = function() {
|
||||
var value = this.doc.getValue();
|
||||
value = value.replace(/^#!.*\n/, "\n");
|
||||
if (!value)
|
||||
return this.sender.emit("annotate", []);
|
||||
|
||||
// [Node-RED] wrap the code in a function
|
||||
value = "async function __nodered__(msg) {\n"+value+"\n}";
|
||||
|
||||
var errors = [];
|
||||
// jshint reports many false errors
|
||||
// report them as error only if code is actually invalid
|
||||
var maxErrorLevel = this.isValidJS(value) ? "warning" : "error";
|
||||
|
||||
// var start = new Date();
|
||||
lint(value, this.options, this.options.globals);
|
||||
var results = lint.errors;
|
||||
|
||||
var errorAdded = false;
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var error = results[i];
|
||||
if (!error)
|
||||
continue;
|
||||
var raw = error.raw;
|
||||
var type = "warning";
|
||||
|
||||
if (raw == "Missing semicolon.") {
|
||||
var str = error.evidence.substr(error.character);
|
||||
str = str.charAt(str.search(/\S/));
|
||||
if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
|
||||
error.reason = 'Missing ";" before statement';
|
||||
type = "error";
|
||||
} else {
|
||||
type = "info";
|
||||
}
|
||||
}
|
||||
else if (disabledWarningsRe.test(raw)) {
|
||||
continue;
|
||||
}
|
||||
else if (infoRe.test(raw)) {
|
||||
type = "info";
|
||||
}
|
||||
else if (errorsRe.test(raw)) {
|
||||
errorAdded = true;
|
||||
type = maxErrorLevel;
|
||||
}
|
||||
else if (raw == "'{a}' is not defined.") {
|
||||
type = "warning";
|
||||
}
|
||||
else if (raw == "'{a}' is defined but never used.") {
|
||||
type = "info";
|
||||
}
|
||||
|
||||
errors.push({
|
||||
// [Node-RED] offset the row for the added line
|
||||
row: error.line-2,
|
||||
column: error.character-1,
|
||||
text: error.reason,
|
||||
type: type,
|
||||
raw: raw
|
||||
});
|
||||
|
||||
if (errorAdded) {
|
||||
// break;
|
||||
}
|
||||
}
|
||||
// console.log("lint time: " + (new Date() - start));
|
||||
|
||||
this.sender.emit("annotate", errors);
|
||||
};
|
||||
|
||||
}).call(NRJavaScriptWorker.prototype);
|
||||
|
||||
});
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 291 B After Width: | Height: | Size: 291 B |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
BIN
packages/node_modules/@node-red/editor-client/src/images/deploy-reload.png
vendored
Normal file
After Width: | Height: | Size: 1015 B |
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B |