Compare commits

..

105 Commits

Author SHA1 Message Date
Dave Conway-Jones
e86f6a841a fix numeric status not displaying by ensuring it's a string 2021-02-05 11:36:26 +00:00
Nick O'Leary
23f0cd3a26 Bump for 1.2.8 2021-02-02 13:11:33 +00:00
Nick O'Leary
74db3e17d0 Restrict project file access to inside the project directory 2021-02-01 13:39:39 +00:00
Matthias Radde
7bde7f0cfd fixing minor typo in node's documentation (#2848) 2021-01-30 18:30:29 +00:00
Nick O'Leary
7068c175f2 Ensure subflow help is picked up for palette tooltip
Fixes #2834
2021-01-27 22:53:06 +00:00
Nick O'Leary
9b5ed8407f Broaden lang verification to include * 2021-01-27 22:06:12 +00:00
Nick O'Leary
37935bf388 Merge pull request #2748 from neuroforgede/master
make split node work with out of order messages
2021-01-27 20:35:32 +00:00
Alex Kaul
70554e24b1 Improve Ru locale (#2826)
* Update Russian Locale

* Upd ru translation for "timestamp"

* Improve node help texts for ru locale

* Improve editor texts for ru locale
2021-01-25 17:25:06 +00:00
Nick O'Leary
a0f736bb88 Validate user-provided language parameter before passing to i18n 2021-01-25 17:06:27 +00:00
Alex Kaul
79473c243d Fix grunt release mkdir issue on Node.js 14 (#2827)
* Update Russian Locale

* Upd grunt-mkdir
2021-01-25 11:03:51 +00:00
Alex Kaul
441eb3bb29 Fix scrollbars (#2825)
* Update Russian Locale

* Fix scrollbars
2021-01-25 11:02:43 +00:00
Ben Hardill
ca44af0625 Prevent crash when coreNodesDir is empty (#2831)
* Fix for HTTP-Request not sending body for GET

Background in SO question:
https://stackoverflow.com/q/60356824/504554

* Prevent crash when coreNodesDir points to empty dir

This should prevent a crash when you point to an empty core nodes
directory.

* Matching upstream master
2021-01-25 10:56:23 +00:00
martinb
b0acb58442 Merge tag '1.2.7' into release/1.2.7 2021-01-14 15:46:22 +01:00
Nick O'Leary
06ceb056f3 Update build.yml 2021-01-07 10:09:49 +00:00
Nick O'Leary
abe77ab96f Bump for 1.2.7 2021-01-06 11:49:31 +00:00
Nick O'Leary
ea720bb4a5 Bump dependencies 2021-01-06 11:41:17 +00:00
Nick O'Leary
6ee2e2b570 Merge pull request #2777 from aaronmyatt/improve-test-coverage-in-editor-api-index
Improve editor api index test coverage
2021-01-06 11:39:30 +00:00
Nick O'Leary
3885107e6e Merge pull request #2805 from kelvininc/user_menu_theme_improvement
Allow to explicit use userMenu in the theme configuration
2021-01-06 11:37:22 +00:00
Nick O'Leary
30a68fefec Ensure subflow-scoped config nodes do not get moved on import
Fixes #2789
2021-01-06 11:22:52 +00:00
Tiago Ferreira
fa84c4e461 Allow to explicit use userMenu in the theme configuration
Unit test to ensure that   works after the theme is initialize

Allow to explicti use userMenu in the theme configuration
2020-12-29 22:06:02 +00:00
David Mödinger
c433f736a5 Improvements to DE translation (#2192)
* Gitter->Raster inconsistency

* Set to -> Festlegen bei // Setzen als
2020-12-17 08:25:35 +00:00
aaronmyatt
55e6c6e01a adds tests for editor-api.start() 2020-12-16 21:53:52 +08:00
Nick O'Leary
496b5a092f Ensure subflow credential objects exist
Fixes #2783
2020-12-15 17:20:22 +00:00
Nick O'Leary
02510efda1 Merge pull request #2781 from johnwang71/flow-undefined-474
Fix bug: Crash & quit while handling exception with undefine msg.error
2020-12-15 13:37:07 +00:00
johnwang71
be828af3e2 Fix bug: Crash & quit while handling exception with undefine msg.error. i.e. flow with 3 nodes, http-in, delay 5-10s, http-out; client with 3s timeout request the flow; TypeError: Cannot read property 'hasOwnProperty' of undefined\r at Flow.handleError (/usr/src/node-red/node_modules/@node-red/runtime/lib/flows/Flow.js:474:27) 2020-12-14 18:18:50 +08:00
Nick O'Leary
df1eb631e1 Merge pull request #2752 from bartbutenaers/readonly-typedinput
Allow TypedInput to be disabled
2020-12-07 12:21:53 +00:00
Nick O'Leary
9f3e9786a8 Disable nyc coverage reporting on older node versions 2020-12-07 11:46:14 +00:00
aaronmyatt
c9bc530df0 tests custom cors settings 2020-12-06 15:29:54 +08:00
aaronmyatt
0b569a4120 exercise admin auth pathways 2020-12-05 23:06:18 +08:00
aaronmyatt
950fd7d2cf removes unused dependencies 2020-12-05 15:15:36 +08:00
aaronmyatt
50dd0354d1 adds admin middleware tests 2020-12-04 23:10:28 +08:00
Dave Conway-Jones
78f1cb8a66 ensure trigger timestamp option sends .now()
To close #2771
2020-12-01 23:05:22 +00:00
Nick O'Leary
4bfe9a9ae9 Bump for 1.2.6 2020-11-25 21:09:45 +00:00
Nathanaël Lécaudé
c5d38d8962 Library: properly handle symlinked folders 2020-11-25 21:08:43 +00:00
Nick O'Leary
2f86bb1ca5 Update MQTT to latest to fix Node 8 URL breakage 2020-11-25 21:05:31 +00:00
Nick O'Leary
3999690062 Support Windows paths when installing tarball by path name
Fixes #2769
2020-11-25 21:04:24 +00:00
Kazuhito Yokoi
d57edaa4c1 Update Japanese translations for 1.2.5 (#2764) 2020-11-19 15:09:30 +00:00
Nick O'Leary
088419b38e Fix unsecure command usage in GH Action 2020-11-18 11:02:09 +00:00
Nick O'Leary
8ebcee32c2 Bump for 1.2.5 2020-11-17 23:09:07 +00:00
Nick O'Leary
2b801a756a Fix import of config nodes with unknown z property 2020-11-17 23:07:43 +00:00
Nick O'Leary
98b639540b Set ACTIONS_ALLOW_UNSECURE_COMMANDS in GH Action 2020-11-17 22:09:17 +00:00
Nick O'Leary
e0b797fc7e Update changelog 2020-11-17 21:06:21 +00:00
Nick O'Leary
795416a84d Bump for 1.2.4 2020-11-17 21:03:24 +00:00
Nick O'Leary
545dda166f Support bigint types in Debug sidebar 2020-11-17 20:50:29 +00:00
Nick O'Leary
f19ec5d9b6 Clear retained status of deleted nodes 2020-11-17 13:29:13 +00:00
Nick O'Leary
6ea978d83d Prevent needless retention of node status messages 2020-11-16 21:05:13 +00:00
Alex Kaul
42f3b70a22 Update Russian Locale (#2761) 2020-11-16 18:44:18 +00:00
Nick O'Leary
1cd10f074b Update projects dialogs to use TypedInput-cred input 2020-11-16 11:37:32 +00:00
Nick O'Leary
bed1d31bc8 Restore cursor position in TypedInput cred-mode 2020-11-16 11:37:04 +00:00
Nick O'Leary
99478897c5 Ensure config nodes with invalid z are imported somewhere 2020-11-14 14:10:32 +00:00
Nick O'Leary
d79cd463a0 Disable projects when flowFile passed into grunt dev
Useful for quickly testing a standalone flow file
2020-11-14 14:09:24 +00:00
martinb
ccf4e73701 cleanup test case for support of out of order messages 2020-11-12 18:56:43 +01:00
martinb
01b67c692b add test case for support of out of order messages support in auto mode of join node if exactly one message has count set 2020-11-12 18:51:14 +01:00
Alex Kaul
4023ab3f28 Add Russian Locale (#2531) 2020-11-12 17:01:44 +00:00
Kazuhito Yokoi
70f3b7450f Add Japanese translation for http-in node (#2758) 2020-11-12 10:21:45 +00:00
Dave Conway-Jones
ca4960e097 Fix CSV node repeating array output
and add tests to cover it
2020-11-10 14:43:59 +00:00
Nick O'Leary
ebe604e1af Ensure user keyboard shortcuts override defaults
Fixes #2753
2020-11-09 21:13:20 +00:00
bartbutenaers
32b04cd32f Disable TypedInput 2020-11-06 08:48:14 +01:00
bartbutenaers
e149174696 Disable TypedInput 2020-11-06 08:45:50 +01:00
Nick O'Leary
f878ffc01b Update changelog 2020-11-05 13:53:22 +00:00
Nick O'Leary
15b49f4db8 Disable 'use strict' checking in Function node
Fixes #2743
2020-11-05 13:48:55 +00:00
Dave Conway-Jones
b1cc7b3296 de-duplicate colour keys 2020-11-05 09:38:34 +00:00
Dave Conway-Jones
65d90a6dff Add gray/grey alternate options for status 2020-11-05 09:20:47 +00:00
Dave Conway-Jones
a58f4c2ec2 remove " from npm install prefix option
to fix npm 7
2020-11-05 09:19:47 +00:00
Nick O'Leary
75d7ac2d8a Merge pull request #2747 from node-red-hitachi/update-message-jp
update Japanese message catalogue for 1.2.3 release
2020-11-03 10:42:45 +00:00
martinb
468cfeffb6 make split node work with out of order messages as long as one of the messages has msg.parts.count set to the proper value 2020-11-03 09:35:21 +01:00
Hiroyasu Nishiyama
6720c1aa46 update Japanese message catalogue for 1.2.3 release 2020-11-03 09:16:13 +09:00
Nick O'Leary
280203e64e Move mosca to ui-test-dependencies list 2020-11-02 21:32:20 +00:00
Nick O'Leary
281d8b7cec Bump for 1.2.3 2020-11-02 21:31:27 +00:00
Nick O'Leary
2c6cda1f27 Handle import errors on initial load and report to user 2020-11-02 21:14:24 +00:00
Nick O'Leary
fa532da8c7 Merge pull request #2739 from node-red/settings-file
Modify default settings comment
2020-10-29 15:42:00 +00:00
Nick O'Leary
cbf84647de Modify default settings comment 2020-10-29 11:51:30 +00:00
Nick O'Leary
c38a490a6f Merge pull request #2737 from node-red/fix-async-settings
Add mutex lock to saveSettings storage call
2020-10-28 22:14:25 +00:00
Nick O'Leary
9d7a450821 Add mutex lock to saveSettings storage call
Fixes #2736
2020-10-28 21:59:22 +00:00
Nick O'Leary
0ecd9673b8 Only apply recovery tab on initial load
Fixes #2731
2020-10-21 10:36:47 +01:00
Nick O'Leary
97aa1230ef Reinstate coveralls reporting to travis build 2020-10-19 21:22:15 +01:00
Nick O'Leary
ff0be73b1f Migrate to nyc instead of istanbul for code coverage 2020-10-19 21:10:34 +01:00
Nick O'Leary
8049e44dec Update CHANGELOG for 1.2.2 2020-10-19 13:25:38 +01:00
Nick O'Leary
dc26022fb4 Prevent node z property getting set to 0 or "" 2020-10-19 13:24:04 +01:00
Nick O'Leary
e8e44f9a32 Only apply z-recovery logic to flow nodes 2020-10-19 13:23:43 +01:00
Nick O'Leary
12d56b8b03 Fix api call to reload flows
Fixes #2726
2020-10-19 12:56:40 +01:00
Nick O'Leary
e62fd7ed15 Remove bad z property from import config nodes 2020-10-19 12:53:03 +01:00
Nick O'Leary
978eb95acd Bump for 1.2.1 2020-10-15 16:22:37 +01:00
Nick O'Leary
e34f4acb22 Fix race condition in .config file migration
Fixes #2724
2020-10-15 16:21:28 +01:00
Nick O'Leary
15a600c763 Fix tab selection after sidebar tab reorder 2020-10-14 22:10:03 +01:00
Nick O'Leary
82ad5839fa Update changelog and bump dependencies 2020-10-13 21:49:11 +01:00
Nick O'Leary
9af883231d Merge pull request #2722 from node-red-hitachi/fix-link-selection
fix selection of link node not existing within active workspace
2020-10-13 13:56:53 +01:00
Hiroyasu Nishiyama
9bfe8ac007 fix selection of link node not existing within active workspace 2020-10-12 20:16:21 +09:00
Nick O'Leary
f46367d77b Fix import of merged flow 2020-10-12 11:20:44 +01:00
Nick O'Leary
eb2e1c0c45 Merge pull request #2718 from node-red-hitachi/fix-upload-button-width-on-safari
Fix upload button width on Safari
2020-10-09 17:12:35 +01:00
Jiye Yu
baffc2d6ca update Chinese translation for NodeRed v1.2 (#2719) 2020-10-08 13:17:04 +01:00
Hiroyasu Nishiyama
96ab508c91 move width specification of upload button to scss 2020-10-08 09:07:11 +09:00
Nick O'Leary
57e42659e3 Merge pull request #2716 from node-red-hitachi/fix-sidebar-tab-popup
Fix unexpected line break of sidebar tab name popover
2020-10-07 12:33:02 +01:00
Nick O'Leary
f059e97697 Merge pull request #2717 from node-red-hitachi/i18n-module-list-refresh-tooltip
i18n module refresh tooltip
2020-10-07 11:37:01 +01:00
Hiroyasu Nishiyama
516e6430eb fix upload button width on safari 2020-10-07 13:42:43 +09:00
Hiroyasu Nishiyama
f194a8ecf4 i18n module refresh tooltip 2020-10-07 11:08:23 +09:00
Hiroyasu Nishiyama
13f046f310 fix unexpected line break of sidebar tab name popover 2020-10-07 09:57:34 +09:00
Nick O'Leary
1edf5acb87 Merge pull request #2714 from node-red-hitachi/update-function-node-help-text
Update info text of Function node
2020-10-06 17:46:11 +01:00
Nick O'Leary
af636870d4 Add better error message if context file gets corrupted 2020-10-06 15:42:52 +01:00
Hiroyasu Nishiyama
379b8ada61 update info text of function node 2020-10-06 13:45:00 +09:00
Nick O'Leary
5e63471983 Use markdown editor if editText called with md mode 2020-10-05 20:38:05 +01:00
Nick O'Leary
086f0f8450 Prevent group actions when in non-default mouse mode 2020-10-02 16:07:22 +01:00
Nick O'Leary
97a4b3dc2a Merge branch 'pr_2709' into dev 2020-10-02 11:14:16 +01:00
Kazuhito Yokoi
4eb8d681c1 Update Japanese translations needed for 1.2 (#2710) 2020-10-02 11:07:01 +01:00
Hiroyasu Nishiyama
2066584164 fix to make Japanese import dialogue message single line 2020-10-01 19:25:21 +09:00
125 changed files with 5720 additions and 289 deletions

View File

@@ -1,5 +1,6 @@
name: PublishDockerImage
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
on:
release:
types: [published]

3
.gitignore vendored
View File

@@ -22,4 +22,5 @@ packages/node_modules/@node-red/editor-client/public
!test/**/node_modules
docs
!packages/node_modules/**/docs
.vscode
.vscode
.nyc_output

View File

@@ -5,11 +5,17 @@ language: node_js
matrix:
include:
- node_js: "14"
script:
- ./node_modules/.bin/grunt && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
# - scripts/install-ui-test-dependencies.sh && grunt test-ui
before_script:
- npm install -g coveralls
- node_js: "12"
script:
- ./node_modules/.bin/grunt no-coverage
- node_js: "10"
# script:
# - ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
# - scripts/install-ui-test-dependencies.sh && grunt test-ui
# before_script:
# - npm install -g istanbul coveralls
script:
- ./node_modules/.bin/grunt no-coverage
- node_js: "8"
script:
- ./node_modules/.bin/grunt no-coverage

View File

@@ -1,3 +1,148 @@
### 1.2.8: Maintenance Release
Editor
- Ensure subflow help is picked up for palette tooltip Fixes #2834
- Improve Ru locale (#2826) @alexk111
- Fix scrollbars (#2825) @alexk111
Runtime
- Restrict project file access to inside the project directory
- Validate user-provided language parameter before passing to i18n
- Fix grunt release mkdir issue on Node.js 14 (#2827) @alexk111
- Prevent crash when coreNodesDir is empty (#2831) @hardillb
Nodes
- Batch node: Fixing minor typo in node's documentation (#2848) @matthiasradde
- Split node: Handle out of order messages as long as one of the messages has msg.parts.count set to the proper value (#2748) @s4ke
### 1.2.7: Maintenance Release
Editor
- Ensure subflow-scoped config nodes do not get moved on import Fixes #2789
- Allow TypedInput to be disabled (#2752) @bartbutenaers
- Allow userMenu to be explicitly enabled (#2805) @tfmf
- Improvements to DE translation (#2192) @ketzu
Runtime
- Handle `undefined` error passed to node.error (#2781) @johnwang71
- Disable nyc coverage reporting on older node versions
- Improve Editor API unit test coverage (#2777) @aaronmyatt
Nodes
- Trigger: ensure timestamp option sends .now() at point of sending
### 1.2.6: Maintenance Release
Editor
- Update Japanese translations for 1.2.5 (#2764) @kazuhitoyokoi
- Library: properly handle symlinked folders (#2768) @natcl
Runtime
- Support Windows paths when installing tarball by path name Fixes #2769
- Fix unsecure command usage in GH Action
Nodes
- Update MQTT to latest to fix Node 8 URL breakage
### 1.2.5: Maintenance Release
Editor
- Fix import of config nodes with unknown z property
Runtime
- Set ACTIONS_ALLOW_UNSECURE_COMMANDS in GH Action
### 1.2.4: Maintenance Release
Editor
- Support bigint types in Debug sidebar
- Clear retained status of deleted nodes
- Prevent needless retention of node status messages
- Update projects dialogs to use TypedInput-cred input
- Restore cursor position in TypedInput cred-mode
- Ensure config nodes with invalid z are imported somewhere
- Ensure user keyboard shortcuts override defaults Fixes #2753
Runtime
- Disable projects when flowFile passed into grunt dev
- Add Russian Locale (#2761) (#2531) (@alexk111)
- Add Japanese translation for http-in node (#2758) (@kazuhitoyokoi)
Nodes
- CSV: Fix CSV node repeating array output
### 1.2.3: Maintenance Release
Editor
- Disable 'use strict' checking in Function node Fixes #2743
- Add gray/grey alternate options for status
- Handle import errors on initial load and report to user
- Only apply recovery tab on initial load Fixes #2731
- Reinstate coveralls reporting to travis build
- Update Japanese message catalogue for 1.2.3 release #2747 (@HiroyasuNishiyama)
Runtime
- Modify default settings comment (#2739)
- Add mutex lock to saveSettings storage call Fixes #2736 (#2737)
- Migrate to nyc instead of istanbul for code coverage
- Move mosca to ui-test-dependencies
- Remove " from npm install prefix option
### 1.2.2: Maintenance Release
Editor
- Prevent node z property getting set to 0 or ""
- Only apply z-recovery logic to flow nodes
- Fix api call to reload flows Fixes #2726
- Remove bad z property from import config nodes
### 1.2.1: Maintenance Release
Runtime
- Fix race condition in .config file migration Fixes #2724
### 1.2.0: Milestone Release
Editor
- Fix selection of link node not existing within active workspace #2722 (@HiroyasuNishiyama)
- Fix import of merged flow
- Fix width of upload button in Safari #2718 (@HiroyasuNishiyama)
- Update Chinese translations #2719 (@JiyeYu)
- Update Japanese translations needed for 1.2 #2710 (@kazuhitoyokoi)
- Fix unexpected line break of sidebar tab name popover #2716 (@HiroyasuNishiyama)
- i18n module refresh tooltip #2717 (@HiroyasuNishiyama)
- Add better error message if context file gets corrupted
- Update info text of function node #2714 (@HiroyasuNishiyama)
- Use markdown editor if editText called with md mode
- Prevent group actions when in non-default mouse mode
### 1.2.0-beta.1: Beta Release
Editor

View File

@@ -24,6 +24,7 @@ module.exports = function(grunt) {
var flowFile = grunt.option('flowFile');
if (flowFile) {
nodemonArgs.push(flowFile);
process.env.NODE_RED_ENABLE_PROJECTS=false;
}
var userDir = grunt.option('userDir');
if (userDir) {
@@ -52,8 +53,8 @@ module.exports = function(grunt) {
ui: 'bdd',
reporter: 'spec'
},
all: { src: ['test/**/*_spec.js'] },
core: { src: ["test/_spec.js","test/unit/**/*_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"]}
},
webdriver: {
@@ -61,19 +62,19 @@ module.exports = function(grunt) {
configFile: 'test/editor/wdio.conf.js'
}
},
mocha_istanbul: {
nyc: {
options: {
globals: ['expect'],
timeout: 3000,
ignoreLeaks: false,
ui: 'bdd',
reportFormats: ['lcov','html'],
print: 'both',
istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
cwd: '.',
include: ['packages/node_modules/**'],
excludeNodeModules: false,
exclude: ['packages/node_modules/@node-red/editor-client/**'],
reporter: ['lcov', 'html','text-summary'],
reportDir: 'coverage',
all: true
},
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"]}
all: { cmd: false, args: ['grunt', 'simplemocha:all'] },
core: { options: { exclude:['packages/node_modules/@node-red/editor-client/**', 'packages/node_modules/@node-red/nodes/**']},cmd: false, args: ['grunt', 'simplemocha:core'] },
nodes: { cmd: false, args: ['grunt', 'simplemocha:nodes'] }
},
jshint: {
options: {
@@ -512,7 +513,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-chmod');
grunt.loadNpmTasks('grunt-jsonlint');
grunt.loadNpmTasks('grunt-mocha-istanbul');
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.loadNpmTasks('grunt-webdriver');
}
@@ -520,6 +520,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
grunt.loadNpmTasks('grunt-npm-command');
grunt.loadNpmTasks('grunt-mkdir');
grunt.loadNpmTasks('grunt-simple-nyc');
grunt.registerMultiTask('nodemon', 'Runs a nodemon monitor of your node.js server.', function () {
const nodemon = require('nodemon');
@@ -620,11 +621,16 @@ module.exports = function(grunt) {
grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components',
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
['build','verifyPackageDependencies','jshint:editor','nyc:all']);
grunt.registerTask('no-coverage',
'Builds editor content then runs code style checks and unit tests on all components without code coverage',
['build','verifyPackageDependencies','jshint:editor','simplemocha:all']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',
['build','mocha_istanbul:core']);
['build','nyc:core']);
grunt.registerTask('test-editor',
'Runs code style check on editor code',
@@ -642,7 +648,7 @@ module.exports = function(grunt) {
grunt.registerTask('test-nodes',
'Runs unit tests on core nodes',
['build','mocha_istanbul:nodes']);
['build','nyc:nodes']);
grunt.registerTask('build',
'Builds editor content',
@@ -667,7 +673,7 @@ module.exports = function(grunt) {
grunt.registerTask('coverage',
'Run Istanbul code test coverage task',
['build','mocha_istanbul:all']);
['build','nyc:all']);
grunt.registerTask('docs',
'Generates API documentation',

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "1.2.0-beta.1",
"version": "1.2.8",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -26,8 +26,8 @@
}
],
"dependencies": {
"ajv": "6.12.5",
"async-mutex": "0.2.4",
"ajv": "6.12.6",
"async-mutex": "0.2.6",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
@@ -38,7 +38,7 @@
"cookie-parser": "1.4.5",
"cors": "2.8.5",
"cron": "1.7.2",
"denque": "1.4.1",
"denque": "1.5.0",
"express": "4.17.1",
"express-session": "1.17.1",
"fs-extra": "8.1.0",
@@ -50,15 +50,15 @@
"is-utf8": "0.2.1",
"js-yaml": "3.14.0",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.3",
"jsonata": "1.8.4",
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0",
"memorystore": "1.6.2",
"mime": "2.4.6",
"moment-timezone": "^0.5.31",
"mqtt": "4.2.1",
"memorystore": "1.6.4",
"mime": "2.4.7",
"moment-timezone": "0.5.32",
"mqtt": "4.2.6",
"multer": "1.4.2",
"mustache": "4.0.1",
"mustache": "4.1.0",
"node-red-admin": "^0.2.6",
"node-red-node-rbe": "^0.2.9",
"node-red-node-sentiment": "^0.1.6",
@@ -73,7 +73,7 @@
"request": "2.88.0",
"semver": "6.3.0",
"tar": "6.0.5",
"uglify-js": "3.11.0",
"uglify-js": "3.12.4",
"when": "3.7.8",
"ws": "6.2.1",
"xml2js": "0.4.23"
@@ -82,7 +82,7 @@
"bcrypt": "3.0.8"
},
"devDependencies": {
"dompurify": "2.1.1",
"dompurify": "2.2.6",
"grunt": "1.3.0",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.3.2",
@@ -97,21 +97,19 @@
"grunt-jsdoc": "2.4.1",
"grunt-jsdoc-to-markdown": "5.0.0",
"grunt-jsonlint": "2.1.3",
"grunt-mkdir": "~1.0.0",
"grunt-mocha-istanbul": "5.0.2",
"grunt-mkdir": "~1.1.0",
"grunt-npm-command": "~0.1.2",
"grunt-sass": "~3.1.0",
"grunt-simple-mocha": "~0.4.1",
"grunt-simple-nyc": "^3.0.1",
"http-proxy": "1.18.1",
"istanbul": "0.4.5",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "1.2.0",
"marked": "1.2.7",
"minami": "1.2.3",
"mocha": "^5.2.0",
"mosca": "^2.8.3",
"node-red-node-test-helper": "^0.2.5",
"node-red-node-test-helper": "^0.2.6",
"node-sass": "^4.14.1",
"nodemon": "2.0.4",
"nodemon": "2.0.6",
"should": "13.2.3",
"sinon": "1.17.7",
"stoppable": "^1.1.0",

View File

@@ -33,8 +33,6 @@ var activeConnections = [];
var anonymousUser;
var retained = {};
var heartbeatTimer;
var lastSentTime;

View File

@@ -39,9 +39,12 @@ module.exports = {
},
get: function(req,res) {
var namespace = req.params[0];
var lngs = req.query.lng;
namespace = namespace.replace(/\.json$/,"");
var lang = req.query.lng || i18n.defaultLang; //apiUtil.determineLangFromHeaders(req.acceptsLanguages() || []);
if (/[^a-z\-\*]/i.test(lang)) {
res.json({});
return;
}
var prevLang = i18n.i.language;
// Trigger a load from disk of the language if it is not the default
i18n.i.changeLanguage(lang, function(){

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "1.2.0-beta.1",
"version": "1.2.8",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,18 +16,18 @@
}
],
"dependencies": {
"@node-red/util": "1.2.0-beta.1",
"@node-red/editor-client": "1.2.0-beta.1",
"@node-red/util": "1.2.8",
"@node-red/editor-client": "1.2.8",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.1",
"express": "4.17.1",
"memorystore": "1.6.2",
"mime": "2.4.6",
"memorystore": "1.6.4",
"mime": "2.4.7",
"multer": "1.4.2",
"mustache": "4.0.1",
"mustache": "4.1.0",
"oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",

View File

@@ -32,7 +32,7 @@
"label" : {
"view" : {
"view" : "Ansicht",
"grid" : "Gitter",
"grid" : "Raster",
"showGrid" : "Raster anzeigen",
"snapGrid" : "Am Raster ausrichten",
"gridSize" : "Rastergröße",

View File

@@ -42,7 +42,8 @@
"loadNodeCatalogs": "Loading Node catalogs",
"loadNodes": "Loading Nodes __count__",
"loadFlows": "Loading Flows",
"importFlows": "Adding Flows to workspace"
"importFlows": "Adding Flows to workspace",
"importError": "<p>Error adding flows</p><p>__message__</p>"
},
"workspace": {
"defaultName": "Flow __number__",
@@ -207,6 +208,8 @@
"download": "Download",
"importUnrecognised": "Imported unrecognised type:",
"importUnrecognised_plural": "Imported unrecognised types:",
"importDuplicate": "Imported duplicate node:",
"importDuplicate_plural": "Imported duplicate nodes:",
"nodesExported": "Nodes exported to clipboard",
"nodesImported": "Imported:",
"nodeCopied": "__count__ node copied",
@@ -545,6 +548,7 @@
"sortRecent": "recent",
"more": "+ __count__ more",
"upload": "Upload module tgz file",
"refresh": "Refresh module list",
"errors": {
"catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
"installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
@@ -1085,6 +1089,7 @@
"en-US": "English",
"ja": "Japanese",
"ko": "Korean",
"ru": "Russian",
"zh-CN": "Chinese(Simplified)",
"zh-TW": "Chinese(Traditional)"
}

View File

@@ -22,7 +22,8 @@
"color": "色",
"position": "配置",
"enable": "有効",
"disable": "無効"
"disable": "無効",
"upload": "アップロード"
},
"type": {
"string": "文字列",
@@ -41,7 +42,8 @@
"loadNodeCatalogs": "ノードカタログを読み込み中",
"loadNodes": "ノードを読み込み中 __count__",
"loadFlows": "フローを読み込み中",
"importFlows": "ワークスペースにフローを追加中"
"importFlows": "ワークスペースにフローを追加中",
"importError": "<p>フロー追加エラー</p><p>__message__</p>"
},
"workspace": {
"defaultName": "フロー __number__",
@@ -197,13 +199,17 @@
"flow_plural": "__count__ 個のフロー",
"subflow": "__count__ 個のサブフロー",
"subflow_plural": "__count__ 個のサブフロー",
"pasteNodes": "JSON形式のフローデータを貼り付けてください",
"selectFile": "読み込むファイルを選択してください",
"importNodes": "フローをクリップボートから読み込み",
"replacedNodes": "置換された __count__ 個のノード",
"replacedNodes_plural": "置換された __count__ 個のノード",
"pasteNodes": "JSON形式のフローデータを貼り付け",
"selectFile": "読み込むファイルを選択",
"importNodes": "フローをクリップボードから読み込み",
"exportNodes": "フローをクリップボードへ書き出し",
"download": "ダウンロード",
"importUnrecognised": "認識できない型が読み込まれました:",
"importUnrecognised_plural": "認識できない型が読み込まれました:",
"importDuplicate": "重複したノードを読み込みました:",
"importDuplicate_plural": "重複したノードを読み込みました:",
"nodesExported": "クリップボードへフローを書き出しました",
"nodesImported": "読み込みました:",
"nodeCopied": "__count__ 個のノードをコピーしました",
@@ -212,6 +218,9 @@
"groupCopied_plural": "__count__ 個のグループをコピーしました",
"groupStyleCopied": "グループの形式をコピーしました",
"invalidFlow": "不正なフロー: __message__",
"recoveredNodes": "復旧したノード",
"recoveredNodesInfo": "このフロー内のードは読み込み時に、有効なフローIDがありませんでした。これらフローIDは、フローに追加されているため、復元または削除できます。",
"recoveredNodesNotification": "<p>有効なフローIDを持たないードが読み込まれました</p><p>これらノードは '__flowName__' という新しいフローへ追加されました。</p>",
"export": {
"selected": "選択したフロー",
"current": "現在のタブ",
@@ -226,13 +235,19 @@
},
"import": {
"import": "読み込み先",
"importSelected": "選択したノードを読み込み",
"importCopy": "コピーを読み込み",
"viewNodes": "ノードを参照...",
"newFlow": "新規のタブ",
"replace": "置換",
"errors": {
"notArray": "JSON形式の配列ではありません",
"itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません",
"missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません",
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
}
},
"conflictNotification1": "読み込もうとしているノードのいくつかは、既にワークスペース内に存在しています。",
"conflictNotification2": "読み込むノードを選択し、また既存のノードを置き換えるか、もしくはそれらのコピーを読み込むかも選択してください。"
},
"copyMessagePath": "パスをコピーしました",
"copyMessageValue": "値をコピーしました",
@@ -532,6 +547,8 @@
"sortAZ": "辞書順",
"sortRecent": "日付順",
"more": "+ さらに __count__ 個",
"upload": "モジュールのtgzファイルをアップロード",
"refresh": "モジュールリスト更新",
"errors": {
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
@@ -708,6 +725,12 @@
"committerTip": "システムのデフォルトを使用する場合、空白のままにしてください",
"userName": "ユーザ名",
"email": "メールアドレス",
"workflow": "ワークフロー",
"workfowTip": "望ましいgitワークフローを選択してください",
"workflowManual": "手動",
"workflowManualTip": "全ての変更は「履歴」サイドバー内で手動でコミットする必要があります",
"workflowAuto": "自動",
"workflowAutoTip": "変更はデプロイの度に自動的にコミットされます",
"sshKeys": "SSH キー",
"sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。",
"add": "キーを追加",
@@ -1066,6 +1089,7 @@
"en-US": "英語",
"ja": "日本語",
"ko": "韓国語",
"ru": "ロシア語",
"zh-CN": "中国語(簡体)",
"zh-TW": "中国語(繁体)"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
{
"info": {
"tip0" : "Вы можете удалить выбранные узлы или провода с {{core:delete-selection}}",
"tip1" : "Ищите узлы с {{core:search}}",
"tip2" : "{{core:toggle-sidebar}} показывает/скрывает эту боковою панель",
"tip3" : "Вы можете управлять палитрой узлов с помощью {{core:manage-palette}}",
"tip4" : "Узлы конфигурации потока перечисляются на боковой панели. Доступ к списку можно получить из меню или с помощью {{core:show-config-tab}}",
"tip5" : "Эти советы можно включить/выключить через настройки",
"tip6" : "Перемещайте выбранные узлы клавишами [влево] [вверх] [вниз] и [вправо]. Удерживайте [Shift], чтобы увеличить шаг",
"tip7" : "Перетаскивание узла на провод соединит его с обеих сторон",
"tip8" : "Экспортируйте выбранные узлы или текущую вкладку с {{core:show-export-dialog}}",
"tip9" : "Импортируйте поток, перетаскивая его JSON в редактор или с помощью {{core:show-import-dialog}}",
"tip10" : "Нажмите [Shift], [кликните] по порту узла и перетаскивайте подключенные провода на другой узел",
"tip11" : "Открывайте вкладку Информация с {{core:show-info-tab}} или вкладку Отладка с {{core:show-debug-tab}}",
"tip12" : "Нажмите [ctrl] и [кликните] в рабочей области, чтобы открыть диалог быстрого добавления",
"tip13" : "Нажмите [ctrl] и [кликните] по порту узла, чтобы начать быстрое подключение",
"tip14" : "Нажмите [Shift] и [кликните] по узлу, чтобы выбрать все соединенные узлы",
"tip15" : "Нажмите [ctrl] и [кликните] по узлу, чтобы добавить или убрать его из текущего выбора",
"tip16" : "Переключайте вкладки потока с помощью {{core:show-previous-tab}} и {{core:show-next-tab}}",
"tip17" : "Вы можете подтвердить изменения в редакторе узла с {{core:confirm-edit-tray}} или отменить их с {{core:cancel-edit-tray}}",
"tip18" : "Нажатие {{core:edit-selected-node}} откроет редактор первого узла в текущем выборе"
}
}

View File

@@ -0,0 +1,274 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Преобразует параметр `arg` в строку, используя следующие правила приведения:\n\n - Строки возвращаются как есть\n - Функции преобразуются в пустую строку\n - Числовая бесконечность и NaN выдают ошибку, поскольку они не могут быть представлены числом в JSON\n - Все остальные значения преобразуются в строку JSON с помощью функции `JSON.stringify`. Если значение `prettify` равно true, тогда будет сгенерирован \"отформатированный\" JSON. То есть каждое поле будет в отдельной строке, а строки будут иметь отступ в зависимости от глубины поля."
},
"$length": {
"args": "str",
"desc": "Возвращает количество символов в строке `str`. Выдается ошибка, если `str` не является строкой."
},
"$substring": {
"args": "str, start[, length]",
"desc": "Возвращает строку, содержащую символы из первого параметра `str`, начиная с позиции `start` (отсчет с нуля). Если указан `length`, то подстрока будет содержать максимум `length` символов. Если `start` отрицателен, то это означает количество символов с конца `str`."
},
"$substringBefore": {
"args": "str, chars",
"desc": "Возвращает подстроку перед первым вхождением последовательности символов `chars` в строке `str`. Если `str` не содержит `chars`, то он возвращает `str`."
},
"$substringAfter": {
"args": "str, chars",
"desc": "Возвращает подстроку после первого вхождения последовательности символов `chars` в строке `str`. Если `str` не содержит `chars`, то он возвращает `str`."
},
"$uppercase": {
"args": "str",
"desc": "Возвращает строку со всеми символами `str`, преобразованными в верхний регистр."
},
"$lowercase": {
"args": "str",
"desc": "Возвращает строку со всеми символами `str`, преобразованными в нижний регистр."
},
"$trim": {
"args": "str",
"desc": "Нормализует и обрезает все пробельные символы в строке `str`, выполняя следующие шаги:\n\n - Все символы табуляции, возврата каретки и перевода строки заменяются пробелами.\n- Последовательности пробелов сокращаются до одного пробела.\n- Пробелы в начале и конце `str` удаляются.\n\n Если `str` не указан (то есть эта функция вызывается без аргументов), тогда значение контекста используется в качестве значения `str`. Выдается ошибка, если `str` не является строкой."
},
"$contains": {
"args": "str, pattern",
"desc": "Возвращает `true`, если строка `str` соответствует шаблону `pattern`, в противном случае возвращает `false`. Если `str` не указан (то есть эта функция вызывается с одним аргументом), то значение контекста используется как значение `str`. Параметр `pattern` может быть либо строкой, либо регулярным выражением."
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "Разбивает строку `str` на массив подстрок. Выдает ошибку, если `str` не является строкой. Необязательный параметр `separator` (строка или регулярное выражение) указывает символы внутри строки `str`, относительно которых она должна быть разделена. Если `separator` не указан, то предполагается пустая строка, и `str` будет разбит на массив из отдельных символов. Выдает ошибку, если `separator` не является строкой. Необязательный параметр `limit` - это число, указывающее максимальное количество подстрок для включения в результирующий массив. Любые дополнительные подстроки отбрасываются. Если `limit` не указан, то весь `str` разделяется без ограничения размера результирующего массива. Выдает ошибку, если `limit` не является положительным числом."
},
"$join": {
"args": "array[, separator]",
"desc": "Объединяет массив подстрок в одну объединенную строку, в которой каждая подстрока отделена необязательным параметром `separator`. Выдает ошибку, если входной массив содержит элемент, который не является строкой. Если `separator` не указан, то предполагается, что это пустая строка, то есть нет `separator` между подстроками. Выдает ошибку, если `separator` не является строкой."
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "Применяет строку `str` к регулярному выражению `pattern` и возвращает массив объектов, каждый из которых содержит информацию о каждом совпадении внутри `str`."
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "Находит вхождения шаблона `pattern` в строке `str` и заменяет их на строку `replacement`.\n\nНеобязательный параметр `limit` - это максимальное количество замен."
},
"$now": {
"args":"",
"desc":"Создает отметку времени в формате, совместимом с ISO 8601, и возвращает ее как строку."
},
"$base64encode": {
"args":"string",
"desc":"Преобразует ASCII-строку в base-64 кодировку. Каждый символ в строке обрабатывается как байт двоичных данных. Для этого необходимо, чтобы все символы в строке находились в диапазоне от 0x00 до 0xFF, который включает все символы строк в URI-кодировке. Символы Юникода за пределами этого диапазона не поддерживаются."
},
"$base64decode": {
"args":"string",
"desc":"Преобразует байты в кодировке base-64 в строку, используя кодовую страницу Юникод UTF-8."
},
"$number": {
"args": "arg",
"desc": "Преобразует параметр `arg` в число с использованием следующих правил приведения:\n\n - Числа возвращаются как есть\n - Строки, которые содержат последовательность символов, представляющих допустимое в JSON число, преобразуются в это число\n - Все остальные значения вызывают ошибку."
},
"$abs": {
"args":"number",
"desc":"Возвращает абсолютное значение числа `number`."
},
"$floor": {
"args":"number",
"desc":"Возвращает значение числа `number`, округленное до ближайшего целого числа, которое меньше или равно `number`."
},
"$ceil": {
"args":"number",
"desc":"Возвращает значение числа `number`, округленное до ближайшего целого числа, которое больше или равно `number`."
},
"$round": {
"args":"number [, precision]",
"desc":"Возвращает значение числа `number`, округленное до количества десятичных знаков, указанных необязательным параметром `precision`."
},
"$power": {
"args":"base, exponent",
"desc":"Возвращает значение числа `base`, возведенное в степень `exponent`."
},
"$sqrt": {
"args":"number",
"desc":"Возвращает квадратный корень из значения числа `number`."
},
"$random": {
"args":"",
"desc":"Возвращает псевдослучайное число, которе больше или равно нулю и меньше единицы."
},
"$millis": {
"args":"",
"desc":"Возвращает число миллисекунд с начала Unix-эпохи (1 января 1970 года по Гринвичу) в виде числа. Все вызовы `$millis()` в пределах выполнения выражения будут возвращать одно и то же значение."
},
"$sum": {
"args": "array",
"desc": "Возвращает арифметическую сумму массива чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$max": {
"args": "array",
"desc": "Возвращает максимальное число в массиве чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$min": {
"args": "array",
"desc": "Возвращает минимальное число в массиве чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$average": {
"args": "array",
"desc": "Возвращает среднее значение массива чисел `array`. Вызывает ошибку, если входной массив `array` содержит элемент, который не является числом."
},
"$boolean": {
"args": "arg",
"desc": "Приводит аргумент к логическому значению, используя следующие правила: \n\n - Логические значения возвращаются как есть\n - пустая строка: `false`\n - непустая строка: `true`\n - число равное `0`: `false`\n - ненулевое число: `true`\n - `null` : `false`\n - пустой массив: `false`\n - массив, который содержит хотя бы один элемент, приводимый к `true`: `true`\n - массив, все элементы которого приводятся к `false`: `false`\n - пустой объект: `false`\n - непустой объект: `true`\n - функция: `false`"
},
"$not": {
"args": "arg",
"desc": "Возвращает логическое НЕ для аргумента. `arg` сначала приводится к логическому значению"
},
"$exists": {
"args": "arg",
"desc": "Возвращает логическое `true`, если выполнение выражения `arg` возвращает значение, или `false`, если выражение ничему не соответствует (например, путь к несуществующему полю)."
},
"$count": {
"args": "array",
"desc": "Возвращает количество элементов в массиве"
},
"$append": {
"args": "array, array",
"desc": "Присоединяет один массив к другому"
},
"$sort": {
"args":"array [, function]",
"desc":"Возвращает массив, содержащий все значения параметра `array`, но отсортированные по порядку.\n\nЕсли указан компаратор `function`, то это должна быть функция, которая принимает два параметра:\n\n`function(val1, val2)`\n\nЭту функцию вызывает алгоритм сортировки для сравнения двух значений: val1 и val2. Если значение val1 следует поместить после значения val2 в желаемом порядке сортировки, то функция должна возвращать логическое значение `true`, чтобы обозначить замену. В противном случае она должна вернуть `false`."
},
"$reverse": {
"args":"array",
"desc":"Возвращает массив, содержащий все значения из параметра `array`, но в обратном порядке."
},
"$shuffle": {
"args":"array",
"desc":"Возвращает массив, содержащий все значения из параметра `array`, но перемешанный в случайном порядке."
},
"$zip": {
"args":"array, ...",
"desc":"Возвращает свернутый (сжатый) массив, содержащий сгруппированные массивы значений из аргументов `array1` … `arrayN` по индексам 0, 1, 2...."
},
"$keys": {
"args": "object",
"desc": "Возвращает массив, содержащий ключи объекта. Если аргумент является массивом объектов, то возвращаемый массив содержит недублированный список всех ключей из всех объектов."
},
"$lookup": {
"args": "object, key",
"desc": "Возвращает значение, связанное с ключом в объекте. Если первый аргумент является массивом объектов, то просходит поиск по всем объектам в массиве, и возвращаются значения, связанные со всеми вхождениями ключа."
},
"$spread": {
"args": "object",
"desc": "Разбивает объект, содержащий пары ключ / значение, на массив объектов, каждый из которых имеет одну пару ключ / значение из входного объекта. Если параметр является массивом объектов, то результирующий массив содержит объект для каждой пары ключ / значение из каждого объекта предоставленного массива."
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "Объединяет массив объектов в один объект, содержащий все пары ключ / значение каждого из объектов входного массива. Если какой-либо из входных объектов содержит один и тот же ключ, возвращаемый объект будет содержать значение последнего в массиве. Вызывает ошибку, если входной массив содержит элемент, который не является объектом."
},
"$sift": {
"args":"object, function",
"desc":"Возвращает объект, который содержит только пары ключ / значение из параметра `object`, которые удовлетворяют предикату `function`, переданному в качестве второго параметра.\n\n`function`, которая передается в качестве второго параметра, должна иметь следующую сигнатуру:\n\n`function(value [, key [, object]])`"
},
"$each": {
"args":"object, function",
"desc":"Возвращает массив, который содержит значения, возвращаемые функцией `function` при применении к каждой паре ключ/значение из объекта `object`."
},
"$map": {
"args":"array, function",
"desc":"Возвращает массив, содержащий результаты применения функции `function` к каждому значению массива `array`.\n\nФункция `function`, указанная в качестве второго параметра, должна иметь следующую сигнатуру:\n\n`function(value [, index [, array]])`"
},
"$filter": {
"args":"array, function",
"desc":"Возвращает массив, содержащий только те значения из массива `array`, которые удовлетворяют предикату `function`.\n\nФункция `function`, указанная в качестве второго параметра, должна иметь следующую сигнатуру:\n\n`function(value [, index [, array]])`"
},
"$reduce": {
"args":"array, function [, init]",
"desc":"Возвращает агрегированное значение, полученное в результате последовательного применения функции `function` к каждому значению в массиве в сочетании с результатом от предыдущего применения функции.\n\nФункция должна принимать два аргумента и вести себя как инфиксный оператор между каждым значением в массиве `array`. Сигнатура `function` должна иметь форму: `myfunc($accumulator, $value[, $index[, $array]])`\n\nНеобязательный параметр `init` используется в качестве начального значения в агрегации."
},
"$flowContext": {
"args": "string[, string]",
"desc": "Извлекает свойство контекста потока.\n\nЭто функция от Node-RED."
},
"$globalContext": {
"args": "string[, string]",
"desc": "Извлекает свойство глобального контекста.\n\nЭто функция от Node-RED."
},
"$pad": {
"args": "string, width [, char]",
"desc": "Возвращает копию строки `string` с дополнительным заполнением, если необходимо, чтобы общее количество символов как минимум соответствовало абсолютному значению параметра `width`.\n\nЕсли `width` является положительным числом, то строка дополняется справа; если отрицательным, то дополняется слева.\n\nНеобязательный аргумент `char` указывает символ(ы) для заполнения. Если не указано, по умолчанию используется пробел."
},
"$fromMillis": {
"args": "number",
"desc": "Преобразует число, представляющее миллисекунды с начала Unix-эпохи (1 января 1970 года по Гринвичу), в строку отметки времени в формате ISO 8601."
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "Преобразует число `number` в строку и форматирует ее в десятичное представление, как указано в строке `picture`.\n\nПоведение этой функции соответствует XPath/XQuery-функции fn:format-number, как определено в спецификация XPath F&O 3.1. Строка `picture` определяет, как форматируется число и имеет тот же синтаксис, что и fn:format-number.\n\nНеобязательный третий аргумент `options` используется для переопределения символов форматирования, специфичных для локали по умолчанию, таких как десятичный разделитель. Если аргумент указан, то это должен быть объект, содержащий пары имя/значение, указанные в разделе десятичного формата спецификации XPath F&O 3.1."
},
"$formatBase": {
"args": "number [, radix]",
"desc": "Преобразует число `number` в строку и форматирует ее в целое число, представленное в системе счисления, указанной аргументом `radix`. Если `radix` не указан, то по умолчанию используется десятичная. Значение 'radix` может быть от 2 до 36, в противном случае выдается ошибка."
},
"$toMillis": {
"args": "timestamp",
"desc": "Преобразует строку `timestamp` в формате ISO 8601 в число миллисекунд с начала Unix-эпохи (1 января 1970 года по Гринвичу). Вызывает ошибку, если строка в неправильном формате."
},
"$env": {
"args": "arg",
"desc": "Возвращает значение переменной среды.\n\nЭто функция от Node-RED."
},
"$eval": {
"args": "expr [, context]",
"desc": "Анализирует и исполняет строку `expr`, которая содержит JSON или выражение JSONata, используя текущий контекст в качестве контекста для исполнения."
},
"$formatInteger": {
"args": "number, picture",
"desc": "Преобразует число `number` в строку и форматирует ее в целочисленное представление, как указано в строке `picture`. Строка `picture` определяет, как форматируется число и имеет тот же синтаксис, что и `fn:format-integer` из спецификации XPath F&O 3.1."
},
"$parseInteger": {
"args": "string, picture",
"desc": "Разбирает содержимое строки `string` в целое число (как число JSON), используя формат, указанный в строке `picture`. Строковый параметр `picture` имеет тот же формат, что и `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Вызывает ошибку с сообщением. Необязательная строка `str` заменяет сообщение по умолчанию $error() function evaluated`"
},
"$assert": {
"args": "arg, str",
"desc": "Если значение `arg` равно true, функция возвращает значение undefined. Если значение `arg` равно false, генерируется исключение с `str` в качестве сообщения об исключении."
},
"$single": {
"args": "array, function",
"desc": "Возвращает одно-единственное значение из массива `array`, которое удовлетворяет предикату `function` (то есть когда `function` возвращает логическое `true` при передаче значения). Выдает исключение, если число подходящих значений не одно.\n\nФункция должна соответствовать следующей сигнатуре: `function(value [, index [, array]])` где value - элемент массива, index - позиция этого значения, а весь массив передается в качестве третьего аргумента"
},
"$encodeUrl": {
"args": "str",
"desc": "Кодирует компонент Uniform Resource Locator (URL), заменяя каждый экземпляр определенных символов одной, двумя, тремя или четырьмя escape-последовательностями, представляющими кодировку UTF-8 символа.\n\nПример: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Кодирует Uniform Resource Locator (URL), заменяя каждый экземпляр определенных символов одной, двумя, тремя или четырьмя escape-последовательностями, представляющими кодировку UTF-8 символа.\n\nПример: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Декодирует компонент Uniform Resource Locator (URL), ранее созданный с помощью encodeUrlComponent.\n\nПример: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Декодирует компонент Uniform Resource Locator (URL), ранее созданный с помощью encodeUrl. \n\nПример: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Возвращает массив содержащий все элементы из массива `array`, с удаленными дупликатами"
},
"$type": {
"args": "value",
"desc": "Возвращает тип значения `value` в виде строки. Если `value` не определено, то будет возвращено `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Получает date объект, используя библиотеку Moment."
}
}

View File

@@ -22,7 +22,8 @@
"color": "颜色",
"position": "位置",
"enable": "启用",
"disable": "禁用"
"disable": "禁用",
"upload": "上传"
},
"type": {
"string": "字符串",
@@ -197,6 +198,8 @@
"flow_plural": "__count__ 个流程",
"subflow": "__count__ 个子流程",
"subflow_plural": "__count__ 子流程",
"replacedNodes": "__count__ 个节点被置换",
"replacedNodes_plural": "__count__ 个节点被置换",
"pasteNodes": "在这里粘贴节点",
"selectFile": "选择要导入的文件",
"importNodes": "导入节点",
@@ -212,6 +215,9 @@
"groupCopied_plural": "已复制 __count__ 个groups",
"groupStyleCopied": "已复制组风格",
"invalidFlow": "无效的流程: __message__",
"recoveredNodes": "复原的节点",
"recoveredNodesInfo": "导入节点时此流上的节点缺少有效的流ID。 它们已被添加到此流中,您可以复原或删除它们。",
"recoveredNodesNotification": "<p>导入的节点缺少有效的流ID</p><p>已将它们添加到名为 '__flowName__'的新流中。</p>",
"export": {
"selected": "已选择的节点",
"current": "现在的节点",
@@ -226,13 +232,19 @@
},
"import": {
"import": "导入到",
"importSelected": "导入所选项",
"importCopy": "导入副本",
"viewNodes": "查看节点",
"newFlow": "新流程",
"replace": "置换",
"errors": {
"notArray": "输入的不是JSON数组",
"itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象",
"missingId": "输入的流无效-项 __index__ 缺少'id'属性",
"missingType": "输入的流程无效-项 __index__ 缺少'类型'属性"
}
},
"conflictNotification1": "您要导入的某些节点已经存在于工作空间中。",
"conflictNotification2": "选择要导入的节点,并确认要替换现有的节点还是导入它们的副本"
},
"copyMessagePath": "已复制路径",
"copyMessageValue": "已复制数值",
@@ -533,6 +545,7 @@
"sortAZ": "a-z顺序",
"sortRecent": "日期顺序",
"more": "增加 __count__ 个",
"upload": "上传模块tgz文件",
"errors": {
"catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息",
"installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息",
@@ -709,6 +722,12 @@
"committerTip": "保留空白以使用系统默认值",
"userName": "用户名",
"email": "电子邮件",
"workflow": "工作流",
"workfowTip": "选择您偏好的工作流",
"workflowManual": "手动",
"workflowManualTip": "所有更改都必须在“历史记录”侧边栏中手动提交",
"workflowAuto": "自动",
"workflowAutoTip": "每次部署后都会自动提交更改",
"sshKeys": "SSH密钥",
"sshKeysTip": "允许您创建到远程git存储库的安全连接。",
"add": "添加密钥",

View File

@@ -22,7 +22,8 @@
"color": "顏色",
"position": "位置",
"enable": "啟用",
"disable": "禁用"
"disable": "禁用",
"upload": "上傳"
},
"type": {
"string": "字符串",
@@ -197,6 +198,8 @@
"flow_plural": "__count__ 多流程",
"subflow": "__count__ 子流程",
"subflow_plural": "__count__ 多子流程",
"replacedNodes": "__count__ 個節點被置換",
"replacedNodes_plural": "__count__ 個節點被置換",
"pasteNodes": "在這裡粘貼節點",
"selectFile": "匯入所選檔案",
"importNodes": "匯入節點",
@@ -212,6 +215,9 @@
"groupCopied_plural": "已複製 __count__ 個groups",
"groupStyleCopied": "已複製組風格",
"invalidFlow": "無效的流程: __message__",
"recoveredNodes": "復原的節點",
"recoveredNodesInfo": "導入節點時此流上的節點缺少有效的流ID。它們已被添加到此流中您可以復原或刪除它們。",
"recoveredNodesNotification": "<p>導入的節點缺少有效的流ID</p><p>已將它們添加到名為 '__flowName__'的新流中。</p>",
"export": {
"selected": "已選擇的節點",
"current": "現在的節點",
@@ -226,13 +232,19 @@
},
"import": {
"import": "匯入到",
"importSelected": "導入所選項",
"importCopy": "導入副本",
"viewNodes": "查看節點",
"newFlow": "新流程",
"replace": "置換",
"errors": {
"notArray": "輸入的不是JSON數組",
"itemNotObject": "輸入的流程無效-項目 __index__ 不是節點對象",
"missingId": "輸入的流程無效-項 __index__ 缺少“ id”屬性",
"missingType": "輸入的流程無效-項 __index__ 缺少“類型”屬性"
}
},
"conflictNotification1": "您要導入的某些節點已經存在於工作空間中。",
"conflictNotification2": "選擇要導入的節點,並確認要替換現有的節點還是導入它們的副本"
},
"copyMessagePath": "已複製路徑",
"copyMessageValue": "已複製數值",
@@ -533,6 +545,7 @@
"sortAZ": "a-z順序",
"sortRecent": "日期順序",
"more": "增加 __count__ 個",
"upload": "上傳模塊tgz文件",
"errors": {
"catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊",
"installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊",
@@ -709,6 +722,12 @@
"committerTip": "保留空白以使用系統默認值",
"userName": "用戶名",
"email": "電子郵件",
"workflow": "工作流",
"workfowTip": "選擇您偏好的工作流",
"workflowManual": "手動",
"workflowManualTip": "所有更改都必須在“歷史記錄”側邊欄中手動提交",
"workflowAuto": "自動",
"workflowAutoTip": "每次部署後都會自動提交更改",
"sshKeys": "SSH密鑰",
"sshKeysTip": "允許您創建到遠程git存儲庫的安全連接。",
"add": "添加密鑰",

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -80,9 +80,8 @@ oop.inherits(NRJavaScriptWorker, Mirror);
// undef: true,
// unused: true,
esversion: 9,
moz: true,
devel: true,
browser: true,
browser: false,
node: true,
laxcomma: true,
laxbreak: true,
@@ -92,7 +91,7 @@ oop.inherits(NRJavaScriptWorker, Mirror);
maxerr: 100,
expr: true,
multistr: true,
globalstrict: true,
strict: false,
sub: true,
asi: true
};

View File

@@ -553,6 +553,9 @@ RED.nodes = (function() {
node.id = n.id;
node.type = n.type;
node.z = n.z;
if (node.z === 0 || node.z === "") {
delete node.z;
}
if (n.d === true) {
node.d = true;
}
@@ -1047,6 +1050,7 @@ RED.nodes = (function() {
* Options:
* - generateIds - whether to replace all node ids
* - addFlow - whether to import nodes to a new tab
* - importToCurrent
* - importMap - how to resolve any conflicts.
* - id:import - import as-is
* - id:copy - import with new id
@@ -1103,8 +1107,9 @@ RED.nodes = (function() {
if (!options.generateIds) {
if (!options.importMap[id]) {
// No conflict resolution for this node
if (nodes[id] || configNodes[id] || workspaces[id] || subflows[id] || groups[id]) {
existingNodes.push(id);
var existing = nodes[id] || configNodes[id] || workspaces[id] || subflows[id] || groups[id];
if (existing) {
existingNodes.push({existing:existing, imported:n});
}
} else if (options.importMap[id] === "replace") {
nodesToReplace.push(n);
@@ -1116,7 +1121,21 @@ RED.nodes = (function() {
})
if (existingNodes.length > 0) {
var existingNodesError = new Error();
var errorMessage = RED._("clipboard.importDuplicate",{count:existingNodes.length});
var nodeList = $("<ul>");
var existingNodesCount = Math.min(5,existingNodes.length);
for (var i=0;i<existingNodesCount;i++) {
var conflict = existingNodes[i];
$("<li>").text(
conflict.existing.id+
" [ "+conflict.existing.type+ ((conflict.imported.type !== conflict.existing.type)?" | "+conflict.imported.type:"")+" ]").appendTo(nodeList)
}
if (existingNodesCount !== existingNodes.length) {
$("<li>").text(RED._("deploy.confirm.plusNMore",{count:existingNodes.length-existingNodesCount})).appendTo(nodeList)
}
var wrapper = $("<p>").append(nodeList);
var existingNodesError = new Error(errorMessage+wrapper.html());
existingNodesError.code = "import_conflict";
existingNodesError.importConfig = identifyImportConflicts(newNodes);
throw existingNodesError;
@@ -1150,7 +1169,7 @@ RED.nodes = (function() {
if (n.z) {
nodeZmap[n.z] = nodeZmap[n.z] || [];
nodeZmap[n.z].push(n);
} else if (n.z === 0) {
} else if (isInitialLoad && n.hasOwnProperty('x') && n.hasOwnProperty('y') && !n.z) {
// Hit the rare issue where node z values get set to 0.
// Repair the flow - but we really need to track that down.
if (!recoveryWorkspace) {
@@ -1235,6 +1254,9 @@ RED.nodes = (function() {
if (defaultWorkspace == null) {
defaultWorkspace = n;
}
if (activeWorkspace === 0) {
activeWorkspace = n.id;
}
if (createNewIds || options.importMap[n.id] === "copy") {
nid = getID();
workspace_map[n.id] = nid;
@@ -1337,6 +1359,10 @@ RED.nodes = (function() {
}
}
}
} else {
if (n.z && !workspaces[n.z] && !subflow_map[n.z]) {
n.z = activeWorkspace;
}
}
if (!existingConfigNode || existingConfigNode._def.exclusive) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode.z !== n.z) {
@@ -1348,6 +1374,9 @@ RED.nodes = (function() {
users:[],
_config:{}
};
if (!n.z) {
delete configNode.z;
}
if (n.hasOwnProperty('d')) {
configNode.d = n.d;
}
@@ -1490,6 +1519,9 @@ RED.nodes = (function() {
delete node.wires;
delete node.inputLabels;
delete node.outputLabels;
if (!n.z) {
delete node.z;
}
}
var orig = {};
for (var p in n) {
@@ -1842,6 +1874,8 @@ RED.nodes = (function() {
});
defaultWorkspace = null;
initialLoad = null;
workspaces = {};
RED.nodes.dirty(false);
RED.view.redraw(true, true);
RED.palette.refresh();

View File

@@ -178,11 +178,21 @@ var RED = (function() {
var currentHash = window.location.hash;
RED.nodes.version(nodes.rev);
loader.reportProgress(RED._("event.importFlows"),90 )
RED.nodes.import(nodes.flows);
RED.nodes.dirty(false);
RED.view.redraw(true);
if (/^#flow\/.+$/.test(currentHash)) {
RED.workspaces.show(currentHash.substring(6));
try {
RED.nodes.import(nodes.flows);
RED.nodes.dirty(false);
RED.view.redraw(true);
if (/^#flow\/.+$/.test(currentHash)) {
RED.workspaces.show(currentHash.substring(6));
}
} catch(err) {
RED.notify(
RED._("event.importError", {message: err.message}),
{
fixed: true,
type: 'error'
}
);
}
}
done();

View File

@@ -21,7 +21,18 @@ RED.actions = (function() {
var result = [];
Object.keys(actions).forEach(function(action) {
var shortcut = RED.keyboard.getShortcut(action);
result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined,user:shortcut?shortcut.user:undefined})
var isUser = false;
if (shortcut) {
isUser = shortcut.user;
} else {
isUser = !!RED.keyboard.getUserShortcut(action);
}
result.push({
id:action,
scope:shortcut?shortcut.scope:undefined,
key:shortcut?shortcut.key:undefined,
user:isUser
})
})
return result;
}

View File

@@ -773,6 +773,9 @@ RED.clipboard = (function() {
// representation or null
return null;
}
if (value.type === 'bigint') {
return value.data.toString();
}
if (value.type === 'undefined') {
return undefined;
}

View File

@@ -84,6 +84,7 @@ RED.popover = (function() {
var targetHeight = target.outerHeight();
var divHeight = div.height();
var divWidth = div.width();
var paddingRight = 10;
var viewportTop = $(window).scrollTop();
var viewportLeft = $(window).scrollLeft();
@@ -105,7 +106,7 @@ RED.popover = (function() {
d = "right";
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
left = targetPos.left+targetWidth+deltaSizes[size].leftRight;
} else if (left+divWidth > viewportRight) {
} else if (left+divWidth+paddingRight > viewportRight) {
d = "left";
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
left = targetPos.left-deltaSizes[size].leftLeft-divWidth;

View File

@@ -617,6 +617,7 @@ RED.tabs = (function() {
}
},
stop: function(event,ui) {
dragActive = false;
collapsedButtonsRow.children().css({position:"relative",left:"",transition:""});
$(".red-ui-tab-link-buttons").width('auto');
pinnedLink.css({zIndex:""});

View File

@@ -173,6 +173,7 @@
valueLabel: function(container,value) {
var that = this;
container.css("pointer-events","none");
container.css("flex-grow",0);
this.elementDiv.hide();
var buttons = $('<div>').css({
position: "absolute",
@@ -184,22 +185,25 @@
width:"20px"
}).appendTo(buttons).on("click", function(evt) {
evt.preventDefault();
var cursorPosition = that.input[0].selectionStart;
var currentType = that.input.attr("type");
if (currentType === "text") {
that.input.attr("type","password");
eyeCon.removeClass("fa-eye-slash").addClass("fa-eye");
setTimeout(function() {
that.input.focus();
that.input[0].setSelectionRange(cursorPosition, cursorPosition);
},50);
} else {
that.input.attr("type","text");
eyeCon.removeClass("fa-eye").addClass("fa-eye-slash");
setTimeout(function() {
that.input.focus();
that.input[0].setSelectionRange(cursorPosition, cursorPosition);
},50);
}
}).hide();
var eyeCon = $('<i class="fa fa-eye"></i>').css("margin-left","-1px").appendTo(eyeButton);
var eyeCon = $('<i class="fa fa-eye"></i>').css("margin-left","-2px").appendTo(eyeButton);
if (value === "__PWRD__") {
var innerContainer = $('<div><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i><i class="fa fa-asterisk"></i></div>').css({
@@ -284,7 +288,7 @@
this.input.css('width','100%');
this.uiSelect.width(m[1]);
this.uiWidth = null;
} else {
} else if (this.uiWidth !== 0){
this.uiSelect.width(this.uiWidth);
}
["Right","Left"].forEach(function(d) {
@@ -304,7 +308,11 @@
this.element.attr('type','hidden');
this.options.types = this.options.types||Object.keys(allOptions);
if (!this.options.types && this.options.type) {
this.options.types = [this.options.type]
} else {
this.options.types = this.options.types||Object.keys(allOptions);
}
this.selectTrigger = $('<button class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
$('<i class="red-ui-typedInput-icon fa fa-caret-down"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
@@ -872,6 +880,9 @@
this.elementDiv.hide();
this.valueLabelContainer.hide();
} else if (opt.valueLabel) {
// Reset any CSS the custom label may have set
this.valueLabelContainer.css("pointer-events","");
this.valueLabelContainer.css("flex-grow",1);
this.valueLabelContainer.show();
this.valueLabelContainer.empty();
this.elementDiv.hide();
@@ -954,6 +965,18 @@
},
hide: function() {
this.uiSelect.hide();
},
disable: function(val) {
if(val === true) {
this.uiSelect.attr("disabled", "disabled");
} else if (val === false) {
this.uiSelect.attr("disabled", null); //remove attr
} else {
this.uiSelect.attr("disabled", val); //user value
}
},
disabled: function() {
return this.uiSelect.attr("disabled");
}
});
})(jQuery);

View File

@@ -1411,7 +1411,7 @@ RED.diff = (function() {
// Restore the original flow so subsequent merge resolutions can properly
// identify new-vs-old
RED.nodes.originalFlow(originalFlow);
imported[0].forEach(function(n) {
imported.nodes.forEach(function(n) {
if (nodeChangedStates[n.id] || localChangedStates[n.id]) {
n.changed = true;
}

View File

@@ -2788,7 +2788,13 @@ RED.editor = (function() {
editExpression: function(options) { showTypeEditor("_expression", options) },
editJSON: function(options) { showTypeEditor("_json", options) },
editMarkdown: function(options) { showTypeEditor("_markdown", options) },
editText: function(options) { showTypeEditor("_text", options) },
editText: function(options) {
if (options.mode == "markdown") {
showTypeEditor("_markdown", options)
} else {
showTypeEditor("_text", options)
}
},
editBuffer: function(options) { showTypeEditor("_buffer", options) },
buildEditForm: buildEditForm,
validateNode: validateNode,

View File

@@ -247,6 +247,7 @@ RED.group = (function() {
var groupStyleClipboard;
function copyGroupStyle() {
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
@@ -254,6 +255,7 @@ RED.group = (function() {
}
}
function pasteGroupStyle() {
if (RED.view.state() !== RED.state.DEFAULT) { return }
if (groupStyleClipboard) {
var selection = RED.view.selection();
if (selection.nodes) {
@@ -287,6 +289,7 @@ RED.group = (function() {
}
function groupSelection() {
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
var group = createGroup(selection.nodes);
@@ -303,6 +306,7 @@ RED.group = (function() {
}
}
function ungroupSelection() {
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
var newSelection = [];
@@ -351,8 +355,7 @@ RED.group = (function() {
}
function mergeSelection() {
// TODO: this currently creates an entirely new group. Need to merge properties
// of any existing group
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
var nodes = [];
@@ -420,6 +423,7 @@ RED.group = (function() {
}
function removeSelection() {
if (RED.view.state() !== RED.state.DEFAULT) { return }
var selection = RED.view.selection();
if (selection.nodes) {
var nodes = [];

View File

@@ -70,6 +70,11 @@ RED.keyboard = (function() {
}
}
}
function getUserKey(action) {
var currentEditorSettings = RED.settings.get('editor') || {};
var userKeymap = currentEditorSettings.keymap || {};
return userKeymap[action];
}
function init() {
// Migrate from pre-0.18
migrateOldKeymap();
@@ -255,6 +260,19 @@ RED.keyboard = (function() {
var i=0;
if (typeof key === 'string') {
if (typeof cbdown === 'string') {
if (!ondown && !defaultKeyMap.hasOwnProperty(cbdown)) {
defaultKeyMap[cbdown] = {
scope:scope,
key:key,
user:false
}
}
if (!ondown) {
var userAction = getUserKey(cbdown);
if (userAction) {
return;
}
}
actionToKeyMap[cbdown] = {scope:scope,key:key};
if (typeof ondown === 'boolean') {
actionToKeyMap[cbdown].user = ondown;
@@ -417,11 +435,9 @@ RED.keyboard = (function() {
});
revertButton.on("click", function(e) {
e.stopPropagation();
RED.keyboard.revertToDefault(object.id);
container.empty();
container.removeClass('keyboard-shortcut-entry-expanded');
var shortcut = RED.keyboard.getShortcut(object.id);
var userKeymap = RED.settings.get('keymap') || {};
// var userKeymap = RED.settings.get('keymap') || {};
var currentEditorSettings = RED.settings.get('editor') || {};
var userKeymap = currentEditorSettings.keymap || {};
@@ -429,6 +445,9 @@ RED.keyboard = (function() {
currentEditorSettings.keymap = userKeymap;
RED.settings.set('editor',currentEditorSettings);
RED.keyboard.revertToDefault(object.id);
var shortcut = RED.keyboard.getShortcut(object.id);
var obj = {
id:object.id,
scope:shortcut?shortcut.scope:undefined,
@@ -589,6 +608,7 @@ RED.keyboard = (function() {
getShortcut: function(actionName) {
return actionToKeyMap[actionName];
},
getUserShortcut: getUserKey,
revertToDefault: revertToDefault,
formatKey: formatKey,
validateKey: validateKey,

View File

@@ -796,7 +796,7 @@ RED.palette.editor = (function() {
loadedIndex = {};
initInstallTab();
})
RED.popover.tooltip(refreshButton,"NLS-TODO: Refresh module list");
RED.popover.tooltip(refreshButton,RED._("palette.editor.refresh"));
packageList = $('<ol>',{style:"position: absolute;top: 79px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
addButton: false,

View File

@@ -417,7 +417,8 @@ RED.palette = (function() {
RED.workspaces.show(nt.substring(8));
e.preventDefault();
});
nodeInfo = RED.utils.renderMarkdown(def.info||"");
var subflow = RED.nodes.subflow(nt.substring(8));
nodeInfo = RED.utils.renderMarkdown(subflow.info||"");
}
setLabel(nt,d,label,nodeInfo);

View File

@@ -1033,7 +1033,7 @@ RED.projects.settings = (function() {
var credentialSecretExistingRow = $('<div class="red-ui-settings-row red-ui-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.currentKey")).appendTo(credentialSecretExistingRow);
var credentialSecretExistingInput = $('<input type="password">').appendTo(credentialSecretExistingRow)
var credentialSecretExistingInput = $('<input type="text">').appendTo(credentialSecretExistingRow).typedInput({type:"cred"})
.on("change keyup paste",function() {
if (popover) {
popover.close();
@@ -1046,7 +1046,7 @@ RED.projects.settings = (function() {
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.newKey")).appendTo(credentialSecretNewRow);
var credentialSecretNewInput = $('<input type="password">').appendTo(credentialSecretNewRow).on("change keyup paste",checkFiles);
var credentialSecretNewInput = $('<input type="text">').appendTo(credentialSecretNewRow).typedInput({type:"cred"}).on("change keyup paste",checkFiles);
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i>' + RED._("sidebar.project.projectSettings.credentialsAlert") + '</div>').hide().appendTo(credentialFormRows);

View File

@@ -81,8 +81,8 @@ RED.projects = (function() {
$('<p>').text(RED._("projects.welcome.desc2")).appendTo(body);
var row = $('<div style="text-align: center"></div>').appendTo(body);
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.welcome.create")+'</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.welcome.clone")+'</button>').appendTo(row);
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.welcome.create")+'</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.welcome.clone")+'</button>').appendTo(row);
createAsEmpty.on("click", function(e) {
e.preventDefault();
@@ -511,7 +511,8 @@ RED.projects = (function() {
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="red-ui-projects-dialog-screen-create-project-repo-pass">'+RED._("projects.clone-project.passwd")+'</label>').appendTo(subrow);
projectRepoPasswordInput = $('<input id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
projectRepoPasswordInput = $('<input style="width:100%" id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
projectRepoPasswordInput.typedInput({type:"cred"});
// -----------------------------------------------------
// Repo credentials - key/passphrase -------------------
@@ -539,12 +540,12 @@ RED.projects = (function() {
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="red-ui-projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.clone-project.passphrase")+'</label>').appendTo(subrow);
projectRepoPassphrase = $('<input id="red-ui-projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
projectRepoPassphrase.typedInput({type:"cred"});
subrow = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.clone-project.ssh-key-desc")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="red-ui-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
e.preventDefault();
dialog.dialog( "close" );
RED.userSettings.show('gitconfig');
@@ -558,8 +559,8 @@ RED.projects = (function() {
// Secret - clone
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label>'+RED._("projects.clone-project.credential-key")+'</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row);
projectSecretInput = $('<input style="width: 100%" type="password"></input>').appendTo(row);
projectSecretInput.typedInput({type:"cred"});
return container;
@@ -894,6 +895,7 @@ RED.projects = (function() {
$('<label class="red-ui-projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="custom" name="projects-encryption-key"> <span style="vertical-align: middle;">'+RED._("projects.encryption-config.use-custom")+'</span></label>').appendTo(row);
row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
emptyProjectCredentialInput = $('<input disabled type="password" style="margin-left: 25px; width: calc(100% - 30px);"></input>').appendTo(row);
emptyProjectCredentialInput.typedInput({type:"cred"});
emptyProjectCredentialInput.on("change keyup paste", validateForm);
row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox);
@@ -1169,11 +1171,11 @@ RED.projects = (function() {
row = $('<div class="form-row button-group"></div>').appendTo(container);
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
row.find(".red-ui-projects-dialog-screen-create-type").on("click", function(evt) {
evt.preventDefault();
container.find(".red-ui-projects-dialog-screen-create-type").removeClass('selected');
@@ -1298,6 +1300,7 @@ RED.projects = (function() {
$('<label class="red-ui-projects-edit-form-inline-label">'+RED._("projects.create.encryption-key")+'</label>').appendTo(row);
// row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
emptyProjectCredentialInput = $('<input type="password"></input>').appendTo(row);
emptyProjectCredentialInput.typedInput({type:"cred"});
emptyProjectCredentialInput.on("change keyup paste", validateForm);
$('<label class="red-ui-projects-edit-form-sublabel"><small>'+RED._("projects.create.desc0")+'</small></label>').appendTo(row);
@@ -1356,7 +1359,8 @@ RED.projects = (function() {
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="red-ui-projects-dialog-screen-create-project-repo-pass">'+RED._("projects.create.password")+'</label>').appendTo(subrow);
projectRepoPasswordInput = $('<input id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
projectRepoPasswordInput = $('<input style="width:100%" id="red-ui-projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
projectRepoPasswordInput.typedInput({type:"cred"});
// -----------------------------------------------------
// Repo credentials - key/passphrase -------------------
@@ -1384,12 +1388,13 @@ RED.projects = (function() {
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="red-ui-projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.create.passphrase")+'</label>').appendTo(subrow);
projectRepoPassphrase = $('<input id="red-ui-projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
projectRepoPassphrase.typedInput({type:"cred"});
subrow = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.create.desc2")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="red-ui-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
e.preventDefault();
$('#red-ui-projects-dialog-cancel').trigger("click");
RED.userSettings.show('gitconfig');
@@ -1403,8 +1408,8 @@ RED.projects = (function() {
// Secret - clone
row = $('<div class="hide form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label>'+RED._("projects.create.credentials-encryption-key")+'</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row);
projectSecretInput = $('<input style="width:100%" type="password"></input>').appendTo(row);
projectSecretInput.typedInput({type:"cred"});
switch(options.screen||"empty") {
case "empty": createAsEmpty.trigger("click"); break;
@@ -1617,14 +1622,14 @@ RED.projects = (function() {
function deleteProject(row,name,done) {
var cover = $('<div class="red-ui-projects-dialog-project-list-entry-delete-confirm"></div>').on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button class="red-ui-button">'+RED._("common.label.cancel")+'</button>')
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
cover.remove();
done(true);
});
$('<button class="red-ui-button primary">'+RED._("common.label.delete")+'</button>')
$('<button class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
@@ -1808,7 +1813,7 @@ RED.projects = (function() {
header.addClass("selectable");
var tools = $('<div class="red-ui-projects-dialog-project-list-entry-tools"></div>').appendTo(header);
$('<button class="red-ui-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
$('<button class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
.appendTo(tools)
.on("click", function(e) {
e.stopPropagation();
@@ -1962,7 +1967,8 @@ RED.projects = (function() {
var isSSH = false;
if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
'<div class="form-row"><label for="projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
message.find("#projects-user-auth-password").typedInput({type:"cred"})
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
isSSH = true;
var row = $('<div class="form-row"></div>').appendTo(message);
@@ -1980,7 +1986,7 @@ RED.projects = (function() {
});
row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row).typedInput({type:"cred"});
}
var notification = RED.notify(message,{

View File

@@ -60,7 +60,7 @@ RED.utils = (function() {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('array['+value.length+']');
} else if (value.hasOwnProperty('type') && value.type === 'function') {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function');
} else if (value.hasOwnProperty('type') && value.type === 'number') {
} else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
} else {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
@@ -352,7 +352,7 @@ RED.utils = (function() {
$('<span class="red-ui-debug-msg-type-null">'+obj+'</span>').appendTo(entryObj);
} else if (obj.__enc__ && obj.type === 'undefined') {
$('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj);
} else if (obj.__enc__ && obj.type === 'number') {
} else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) {
e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj);
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj);

View File

@@ -98,7 +98,8 @@ RED.view = (function() {
"green": "#5a8",
"yellow": "#F9DF31",
"blue": "#53A3F3",
"grey": "#d3d3d3"
"grey": "#d3d3d3",
"gray": "#d3d3d3"
}
var PORT_TYPE_INPUT = 1;
@@ -1892,7 +1893,8 @@ RED.view = (function() {
activeLinkNodes = {};
for (var i=0;i<movingSet.length();i++) {
var msn = movingSet.get(i);
if (msn.n.type === "link out" || msn.n.type === "link in") {
if ((msn.n.type === "link out" || msn.n.type === "link in") &&
(msn.n.z === activeWorkspace)) {
var linkNode = msn.n;
activeLinkNodes[linkNode.id] = linkNode;
var offFlowLinks = {};

View File

@@ -219,7 +219,7 @@ RED.user = (function() {
function init() {
if (RED.settings.user) {
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) {
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu") || RED.settings.editorTheme.userMenu) {
var userMenu = $('<li><a id="red-ui-header-button-user" class="button hide" href="#"></a></li>')
.prependTo(".red-ui-header-toolbar");

View File

@@ -15,6 +15,9 @@
**/
body {
overflow: hidden;
}
.red-ui-editor {
font-size: $primary-font-size;

View File

@@ -251,7 +251,7 @@ g.red-ui-flow-node-selected {
stroke-dasharray: none;
}
}
@each $current-color in red green yellow blue grey {
@each $current-color in red green yellow blue grey gray {
.red-ui-flow-node-status-dot-#{$current-color} {
fill: map-get($node-status-colors,$current-color);
stroke: map-get($node-status-colors,$current-color);

View File

@@ -253,6 +253,9 @@ button.red-ui-palette-editor-upload-button {
min-width: 0;
padding: 2px 8px;
}
form {
width: 0;
}
}
.red-ui-palette-editor-upload {
display: none;
@@ -275,4 +278,4 @@ button.red-ui-palette-editor-upload-button {
button {
margin-left: 10px;
}
}
}

View File

@@ -90,7 +90,7 @@
font-size: 1.2em;
}
}
button.red-ui-button {
button.red-ui-button.red-ui-projects-dialog-button {
width: calc(50% - 80px);
margin: 20px;
height: auto;

View File

@@ -18,6 +18,7 @@
border: 1px solid $form-input-border-color;
border-radius: 4px;
height: 34px;
line-height: 14px;
display: inline-flex;
padding: 0;
margin: 0;
@@ -25,6 +26,14 @@
box-sizing: border-box;
overflow:visible;
position: relative;
&[disabled] {
input, button {
background: $secondary-background-inactive;
pointer-events: none;
cursor: not-allowed;
}
}
.red-ui-typedInput-input-wrap {
flex-grow: 1;
}

View File

@@ -21,8 +21,11 @@ module.exports = function(RED) {
this.tosidebar = n.tosidebar;
if (this.tosidebar === undefined) { this.tosidebar = true; }
this.active = (n.active === null || typeof n.active === "undefined") || n.active;
if (this.tostatus) { this.status({fill:"grey", shape:"ring"}); }
else { this.status({}); }
if (this.tostatus) {
this.status({fill:"grey", shape:"ring"});
this.oldState = "{}";
}
var hasStatExpression = (n.statusType === "jsonata");
var statExpression = hasStatExpression ? n.statusVal : null;
@@ -97,7 +100,11 @@ module.exports = function(RED) {
}
}
}
this.on("close", function() {
if (this.oldState) {
this.status({});
}
})
this.on("input", function(msg, send, done) {
if (msg.hasOwnProperty("status") && msg.status.hasOwnProperty("source") && msg.status.source.hasOwnProperty("id") && (msg.status.source.id === node.id)) {
done();
@@ -202,13 +209,8 @@ module.exports = function(RED) {
function setNodeState(node,state) {
if (state) {
node.active = true;
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
} else {
node.active = false;
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "dot";
node.status(node.oldStatus);
}
}
}

View File

@@ -127,6 +127,8 @@ module.exports = function(RED) {
node.topic = n.topic;
node.outstandingTimers = [];
node.outstandingIntervals = [];
node.clearStatus = false;
var sandbox = {
console:console,
util:util,
@@ -163,6 +165,7 @@ module.exports = function(RED) {
node.on.apply(node, arguments);
},
status: function() {
node.clearStatus = true;
node.status.apply(node, arguments);
}
},
@@ -389,7 +392,9 @@ module.exports = function(RED) {
while (node.outstandingIntervals.length > 0) {
clearInterval(node.outstandingIntervals.pop());
}
node.status({});
if (node.clearStatus) {
node.status({});
}
});
promise.then(function (v) {

View File

@@ -179,7 +179,10 @@ module.exports = function(RED) {
/* istanbul ignore else */
if (node.op1type !== "nul") {
var msg2 = RED.util.cloneMessage(msg);
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, delayDuration);
node.topics[topic].tout = setInterval(function() {
if (node.op1type === "date") { msg2.payload = Date.now(); }
node.send(RED.util.cloneMessage(msg2));
}, delayDuration);
}
}
else {
@@ -209,6 +212,7 @@ module.exports = function(RED) {
}
else {
msg2.payload = node.topics[topic].m2;
if (node.op2type === "date") { msg2.payload = Date.now(); }
if (node.second === true) { node.send([null,msg2]); }
else { node.send(msg2); }
}

View File

@@ -63,14 +63,19 @@ module.exports = function(RED) {
if (typeof msg.payload == "object") { // convert object to CSV string
try {
var ou = "";
if (!Array.isArray(msg.payload)) { msg.payload = [ msg.payload ]; }
if (node.hdrout !== "none" && node.hdrSent === false) {
if ((node.template.length === 1) && (node.template[0] === '') && (msg.hasOwnProperty("columns"))) {
node.template = clean((msg.columns || "").split(","));
if ((node.template.length === 1) && (node.template[0] === '')) {
if (msg.hasOwnProperty("columns")) {
node.template = clean((msg.columns || "").split(","));
}
else {
node.template = Object.keys(msg.payload[0]);
}
}
ou += node.template.join(node.sep) + node.ret;
if (node.hdrout === "once") { node.hdrSent = true; }
}
if (!Array.isArray(msg.payload)) { msg.payload = [ msg.payload ]; }
for (var s = 0; s < msg.payload.length; s++) {
if ((Array.isArray(msg.payload[s])) || (typeof msg.payload[s] !== "object")) {
if (typeof msg.payload[s] !== "object") { msg.payload = [ msg.payload ]; }
@@ -98,10 +103,10 @@ module.exports = function(RED) {
}
for (var p in msg.payload[0]) {
/* istanbul ignore else */
if (msg.payload[0].hasOwnProperty(p)) {
if (msg.payload[s].hasOwnProperty(p)) {
/* istanbul ignore else */
if (typeof msg.payload[0][p] !== "object") {
var q = "" + msg.payload[0][p];
if (typeof msg.payload[s][p] !== "object") {
var q = "" + msg.payload[s][p];
if (q.indexOf(node.quo) !== -1) { // add double quotes if any quotes
q = q.replace(/"/g, '""');
ou += node.quo + q + node.quo + node.sep;
@@ -228,7 +233,7 @@ module.exports = function(RED) {
// Finished so finalize and send anything left
if (f === false) { node.warn(RED._("csv.errors.bad_csv")); }
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
if ( node.template[j] && (node.template[j] !== "") ) {
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
else { if (k[j] !== null) k[j].replace(/\r$/,''); }

View File

@@ -677,7 +677,10 @@ module.exports = function(RED) {
}
group.msg = Object.assign(group.msg, msg);
var tcnt = group.targetCount;
if (msg.hasOwnProperty("parts")) { tcnt = group.targetCount || msg.parts.count; }
if (msg.hasOwnProperty("parts")) {
tcnt = group.targetCount || msg.parts.count;
group.targetCount = tcnt;
}
if ((tcnt > 0 && group.currentCount >= tcnt) || msg.hasOwnProperty('complete')) {
completeSend(partId);
}
@@ -697,3 +700,4 @@ module.exports = function(RED) {
}
RED.nodes.registerType("join",JoinNode);
}

View File

@@ -583,11 +583,11 @@
"regex" : "Reguläre Ausdrücke verwenden"
},
"action" : {
"set" : "Festlegen",
"set" : "Setze",
"change" : "Ändern",
"delete" : "Löschen",
"move" : "Bewegen",
"to" : "bis",
"to" : "auf",
"search" : "Suchen nach",
"replace" : "Ersetzen durch"
},

View File

@@ -20,19 +20,18 @@
<p>Es gibt drei Modi für die Erstellung von Nachrichtensequenzen:</p>
<dl>
<dt>Anzahl der Nachrichten</dt>
<dd>Die Nachrichten werden zu Sequenzen einer bestimmten Länge gruppiert. Die Option <b>Überlappung</b>>
<dd>Die Nachrichten werden zu Sequenzen einer bestimmten Länge gruppiert. Die Option <b>Überlappung</b>
gibt an, wie viele Nachrichten vom Ende einer Sequenz am Anfang der nächsten Sequenz wiederholt werden sollen.</dd>
<dt>Zeitintervall</dt>
<dd>Gruppiert Nachrichten, die innerhalb des angegebenen Intervalls eingehen. Wenn keine Nachrichten
innerhalb des Intervalls ankommen, kann der Node optional eine leere Nachricht senden.</dd>
<dt>Sequenzesn verketten/dt>
<dt>Sequenzen verketten/dt>
<dd>Erzeugt eine Nachrichtensequenz durch die Verkettung eingehender Sequenzen. Jede Nachricht muss eine <code>msg.topic</code>
und eine <code>msg.parts</code> Eigenschaft haben, um die Sequenz identifizieren zu können.
Der Node ist mit einer Liste von <code>topic</code> konfiguriert,
mit der die Reihnmefolge der Verkettung der Sequenzen definiert wird.
</dd>
mit der die Reihenfolge der Verkettung der Sequenzen definiert wird.</dd>
</dl>
<h4>Speichern der Nachrichten</h4>

View File

@@ -23,6 +23,7 @@
to return nothing in order to halt a flow.</p>
<p>The <b>Setup</b> tab contains code that will be run whenever the node is started.
The <b>Close</b> tab contains code that will be run when the node is stopped.</p>
<p>If an promise object is returned from the setup code, input message processing starts after its completion.</p>
<h3>Details</h3>
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
for more information on writing functions.</p>
@@ -34,6 +35,7 @@
<li>a single message object - passed to nodes connected to the first output</li>
<li>an array of message objects - passed to nodes connected to the corresponding outputs</li>
</ul>
<p>Note: The setup code is executed during the initialization of nodes. Therefore, if <code>node.send</code> is called in the setup tab, subsequent nodes may not be able to receive the message.</p>
<p>If any element of the array is itself an array of messages, multiple
messages are sent to the corresponding output.</p>
<p>If null is returned, either by itself or as an element of the array, no

View File

@@ -39,7 +39,7 @@
will be used as the property names. Alternatively, the column names can be taken from the first row of the CSV.</p>
<p>When converting to CSV, the column template is used to identify which properties to extract from the object and in what order.</p>
<p>If the template is blank then the node can use a simple comma separated list of properties supplied in <code>msg.columns</code> to
determine what to extract. If that is not present then all the object properties are ouput in the order in which they are found.</p>
determine what to extract. If that is not present then all the object properties are output in the order in which the properties are found in the first row.</p>
<p>If the input is an array then the columns template is only used to optionally generate a row of column titles.</p>
<p>If 'parse numerical values' option is checked, string numerical values will be returned as numbers, ie. middle value '1,"1.5",2'.</p>
<p>If 'include empty strings' option is checked, empty strings will be returned in result, ie. middle value '"1","",3'.</p>

View File

@@ -20,6 +20,7 @@
<p><code>msg</code><code>msg.payload</code></p>
<p>通常コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します後続フローの実行を停止したい場合はオブジェクトを返却しなくてもかまいません</p>
<p>Node-REDの開始時もしくはフローの設定をデプロイした際実行される初期化コードを<b>初期化処理</b><b></b></p>
<p>初期化処理タブの返却値としてPromiseを返却すると入力メッセージの処理を開始する前にその完了を待ちます</p>
<h3>詳細</h3>
<p>コードの書き方の詳細については<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a></p>
<h4>メッセージの送信</h4>
@@ -29,6 +30,7 @@
<li>単一メッセージオブジェクト - 最初の出力に接続されたノードに渡されます</li>
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
</ul>
<p>: 初期化処理の実行はノードの初期化中に行われますそのため初期化処理タブにsendを記述した場合に後続ードでメッセージを受け取れないことがあります</p>
<p>配列要素が配列の場合には複数のメッセージを対応する出力に送出します</p>
<p>返却方法が単一値か配列要素かにかかわらず返却値がnullの場合メッセージの送出は行いません</p>
<h4>ログ出力とエラー処理</h4>

View File

@@ -19,6 +19,8 @@
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">数値</span></dt>
<dd>メッセージに適用する遅延時間をミリ秒で設定します設定されたデフォルトの遅延間隔をメッセージが上書きできる様に本ノードが設定されている場合のみこのオプションが適用されます</dd>
<dt class="optional">reset</dt>
<dd>このプロパティを持つメッセージを受け取ると仕掛かり中の待機や繰り返しをクリアしメッセージの送信は行いません</dd>
</dl>
@@ -27,6 +29,7 @@
<p>フロー内でタイムアウトを作成するのに利用しますメッセージを受け取るとデフォルトでは<code>payload</code><code>1</code>250ms<code>payload</code><code>0</code>2Raspberry PiGPIOLED</p>
<p>各送信メッセージのペイロードはさまざまな種類の値に設定できます再送信データなしとすることも可能です例えば再送信データを<i>なし</i>trigger</p>
<p>ペイロードに<i>文字列</i>mustache</p>
<p>メッセージ送信間の遅延時間は本ノードのオプションが有効な場合 <code>msg.delay</code> </p>
<p><code>reset</code><code>payload</code></p>
<p>受信メッセージでリセットするまで一定間隔でメッセージを再送するように指定することもできます</p>
<p>msgプロパティ(デフォルトは<code>msg.topic</code>)</p>

View File

@@ -320,6 +320,7 @@
"h": "時間"
},
"extend": "新たなメッセージを受け取った時に遅延を延長",
"override": "msg.delayを用いて遅延時間を上書き",
"second": "2つ目の出力端子に2番目のメッセージを送信",
"label": {
"trigger": "trigger",
@@ -402,13 +403,13 @@
"label": {
"method": "メソッド",
"url": "URL",
"doc": "Docs",
"doc": "ドキュメント",
"return": "出力形式",
"upload": "ファイルのアップロード",
"status": "ステータスコード",
"headers": "ヘッダ",
"other": "その他",
"paytoqs" : {
"paytoqs": {
"ignore": "無視",
"query": "クエリパラメータに追加",
"body": "リクエストボディとして送信"

View File

@@ -0,0 +1,52 @@
<!--
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/html" data-help-name="inject">
<p>
Вбрасывает сообщение в поток вручную или через равные промежутки времени. Данные в сообщении могут быть различных типов, включая строку, объект JavaScript или метку текущего времени.
</p>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">разные</span></dt>
<dd>Настроенные данные сообщения.</dd>
<dt class="optional">topic <span class="property-type">строка</span></dt>
<dd>Необязательное свойство темы сообщения, которое можно настроить в узле.</dd>
</dl>
<h3>Подробности</h3>
<p>
Узел Inject может инициировать выполнение потока с определенными данными (значение payload). Данные по умолчанию - это метка текущего времени в миллисекундах, прошедших с 1 января 1970 года.
</p>
<p>
Узел также поддерживает вывод строк, чисел, логических значений, объектов JavaScript или значений потоковых/глобальных контекстов.
</p>
<p>
По умолчанию узел запускается вручную при нажатии его кнопки в редакторе. Его также можно настроить на автоматический запуск через равные промежутки времени или по расписанию.
</p>
<p>
Он также может быть настроен однократный вброс сообщения при каждом (пере)запуске потоков.
</p>
<p>
Максимальный <i>интервал</i>, который можно указать, составляет около 596 часов / 24 дней. Однако если Вам нужны интервалы, превышающие один день, Вам следует рассмотреть возможность использования функций планировщика в узле, которые смогут корректно работать с перебоями электроэнергии и перезапусками.
</p>
<p>
<b>Примечание</b>: В параметрах <i>"с интервалом в промежутке"</i> и <i>"в определенное время"</i> используется стандартная система "cron". Это означает, что "20 минут" будут в следующем часу, 20 минут спустя и 40 минут спустя - а не через 20 минут. Если нужен вброс сообщений каждые 20 минут - используйте параметр <i>"с интервалом"</i>.
</p>
<p>
<b>Примечание</b>: Чтобы включить многострочный текст в строковое значение, необходимо использовать узел Function для формирования данных.
</p>
</script>

View File

@@ -0,0 +1,39 @@
<!--
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/html" data-help-name="debug">
<p>
Отображает выбранные свойства получаемых узлом сообщения на боковой панели во вкладке отладки и, при необходимости, журнале среды выполнения. По умолчанию отображается содержимое <code>msg.payload</code>, но узел можно настроить на отображение любого свойства, всех свойств сообщения или результата выражения JSONata.
</p>
<h3>Подробности</h3>
<p>
Вкладка отладки на боковой панели обеспечивает структурированное представление полученных узлом сообщений, что упрощает исследование их структуры.
</p>
<p>
Объекты и массивы JavaScript могут быть свернуты и развернуты по мере необходимости. Буферы могут отображаться в виде данных как есть или в виде строки, когда это возможно.
</p>
<p>
Рядом с каждым сообщением отладочная панель показывает информацию о времени получения сообщения, узле, который его отправил, и типе данных.
Нажатие на идентификатор узла-источника покажет этот узел в рабочей области.
</p>
<p>
Кнопка на узле может использоваться для включения или отключения вывода информации о получаемых сообщениях. Рекомендуется отключать или удалять любые отладочные узлы, которые не используются.
</p>
<p>
Узел также может быть настроен на отправку всех сообщений в журнал выполнения или отправку короткого (32 символа) текста в статус под узлом.
</p>
</script>

View File

@@ -0,0 +1,35 @@
<!--
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/html" data-help-name="complete">
<p>
Инициирует запуск потока, когда другой узел завершает обработку сообщения.
</p>
<h3>Подробности</h3>
<p>
Если узел сообщает среде выполнения о завершении обработки сообщения, этот узел можно использовать для запуска второго потока.
</p>
<p>
Например, его можно использовать вместе с узлом, у которого нет выходного порта, таким как узел Email, для продолжения потока.
</p>
<p>
Этот узел должен быть настроен на отслеживание событий выбранных узлов в потоке. В отличие от узла Catch, у него нет режима 'обрабатывать все' для автоматического применения ко всем узлам в потоке.
</p>
<p>
Не все узлы могут инициировать запуск потока по завршению обработки сообщения. все зависит от того, была ли в них реализована поддержка этой функции, добавленной в Node-RED 1.0, или нет.
</p>
</script>

View File

@@ -0,0 +1,50 @@
<!--
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/html" data-help-name="catch">
<p>
Ловит ошибки, выбрасываемые узлами на той же вкладке.
</p>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>error.message <span class="property-type">строка</span></dt>
<dd>сообщение об ошибке.</dd>
<dt>error.source.id <span class="property-type">строка</span></dt>
<dd>идентификатор узла, выдавшего ошибку.</dd>
<dt>error.source.type <span class="property-type">строка</span></dt>
<dd>тип узла, выдавшего ошибку.</dd>
<dt>error.source.name <span class="property-type">строка</span></dt>
<dd>имя узла, выдавшего ошибку, если было настроено.</dd>
</dl>
<h3>Подробности</h3>
<p>
Если узел выбрасывает ошибку во время обработки сообщения, поток обычно останавливается. Этот узел можно использовать для отлова и обработки таких ошибок с помощью отдельного потока.
</p>
<p>
По умолчанию узел будет отлавливать ошибки, генерируемые любым узлом на той же вкладке. По желанию он может быть нацелен на определенные узлы или настроен на перехват только тех ошибок, которые не были перехвачены 'нацеленным' Catch узлом.
</p>
<p>
Когда выдается ошибка, все соответствующие Catch узлы получат сообщение.
</p>
<p>
Если ошибка выбрасывается в подпотоке, она будет обработана любыми Catch узлами внутри подпотока. Если таковых нет, ошибка будет распространена до вкладки, на которой находится экземпляр подпотока.
</p>
<p>
Если сообщение уже имеет свойство <code>error</code>, оно копируется в <code>_error</code>.
</p>
</script>

View File

@@ -0,0 +1,41 @@
<!--
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/html" data-help-name="status">
<p>
Инициирует запуск потока при изменении статуса других узлов на той же вкладке.
</p>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>status.text <span class="property-type">строка</span></dt>
<dd>текст статуса.</dd>
<dt>status.source.type <span class="property-type">строка</span></dt>
<dd>тип узла, сообщившего о статусе.</dd>
<dt>status.source.id <span class="property-type">строка</span></dt>
<dd>идентификатор узла, сообщившего о статусе.</dd>
<dt>status.source.name <span class="property-type">строка</span></dt>
<dd>имя узла, сообщившего о статусе, если настроено.</dd>
</dl>
<h3>Подробности</h3>
<p>
Этот узел не создает <code>payload</code> данные.
</p>
<p>
По умолчанию узел сообщает о статусах всех узлов на той же вкладке в рабочей области. Его можно настроить на выборочное отслеживание статуса только отдельных узлов.
</p>
</script>

View 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.
-->
<script type="text/html" data-help-name="link in">
<p>
Создает виртуальный провод между потоками.
</p>
<h3>Подробности</h3>
<p>
Этот узел может быть подключен к любому <code>link out</code> узлу на любой вкладке. После подключения они ведут себя так, как если бы они были соединены вместе обычным проводом.
</p>
<p>
Связи между link-узлами отображаются, только когда выбран один из соединенных link узлов. Если есть какие-либо провода, ведущие на другие вкладки, они отображаются в виде виртуального узла, по которому можно кликнуть, чтобы перейти на соответствующую вкладку.
</p>
<p>
<b>Примечание:</b> Провод не может вести внутрь подпотока или изнутри подпотока наружу.
</p>
</script>
<script type="text/html" data-help-name="link out">
<p>
Создает виртуальный провод между потоками.
</p>
<h3>Подробности</h3>
<p>
Узел может быть подключен к любому <code>link in</code> узлу на любой вкладке. После подключения они ведут себя так, как если бы они были соединены вместе обычным проводом.
</p>
<p>
Связи между link-узлами отображаются, только когда выбран один из соединенных link узлов. Если есть какие-либо провода, ведущие на другие вкладки, они отображаются в виде виртуального узла, по которому можно кликнуть, чтобы перейти на соответствующую вкладку.
</p>
<p>
<b>Примечание:</b> Провод не может вести внутрь подпотока или изнутри подпотока наружу.
</p>
</script>

View File

@@ -0,0 +1,26 @@
<!--
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/html" data-help-name="comment">
<p>
Узел, который можно использовать для добавления комментариев к вашим потокам.
</p>
<h3>Подробности</h3>
<p>
Окно редактирования поддерживает синтаксис Markdown. Текст будет отображен на информационной вкладке боковой панели в секции 'описание'.
</p>
</script>

View File

@@ -0,0 +1,37 @@
<!--
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/html" data-help-name="unknown">
<p>
Тип этого узла неизвестен вашему Node-RED.
</p>
<h3>Подробности</h3>
<p>
<i>
Если вы развернете узел в этом состоянии, его настройки будут сохранены, но поток не будет запущен до тех пор, пока не будет установлен отсутствующий тип.
</i>
</p>
<p>
Используйте опцию <code>Меню - Управление палитрой</code> для поиска и установки узлов или <b>npm install &lt;модуль&gt;</b> для установки отсутствующих модулей. Затем перезапустите Node-RED и повторно импортируйте узлы.
</p>
<p>
Возможно, этот тип узла уже установлен, но отсутствуют какие-то из его зависимостей. Проверьте журнал выполнения Node-RED на наличие сообщений об ошибках, связанных с отсутствующим типом узла.
</p>
<p>
В противном случае вам следует связаться с автором потока, чтобы получить отсутствующий тип узла.
</p>
</script>

View File

@@ -0,0 +1,90 @@
<!--
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/html" data-help-name="function">
<p>
Исполняет JavaScript функцию (введенную в настройках, во вкладке <b>Функция</b>) для всех получаемых узлом сообщений.
</p>
<p>
Сообщения передаются в виде объекта JavaScript с именем <code>msg</code>.
</p>
<p>
Обычно у объекта есть свойство <code>msg.payload</code>, содержащее тело сообщения.
</p>
<p>
Ожидается, что функция вернет объект сообщения (или несколько объектов сообщения), которые будут отправлены следующим узлам в потоке, но может также ничего не возвращать, чтобы остановить поток.
</p>
<p>
Код настройки, выполняемый один раз при запуске сервера или при развертывании новой конфигурации потока, можно ввести во вкладке <b>Настройка</b>. Также во вкладке <b>Закрытие</b> можно ввести код очистки, выполняемый при остановке или повторном развертывании узла.
</p>
<p>
Если код настройки возвращает Promise объект, тогда обработка входящих сообщений узлом начнется после его завершения.
</p>
<h3>Подробности</h3>
<p>
Смотрите <a target="_blank" href="http://nodered.org/docs/writing-functions.html">онлайн-документацию</a> для получения дополнительной информации по написанию функций.
</p>
<h4>Отправка сообщений</h4>
<p>
Функция может либо вернуть сообщения, которые она хочет передать следующим узлам в потоке, либо вызвать <code>node.send(сообщения)</code>.
</p>
<p>
Она может вернуть/отправить:
</p>
<ul>
<li>один объект сообщения - передается узлам, подключенным к первому порту выхода</li>
<li>массив объектов сообщений - передается на узлы, подключенные к соответствующим портам выхода</li>
</ul>
<p>
Примечание: код настройки выполняется во время инициализации узлов. Таким образом, если на вкладке настройки кода вызывается <code>node.send</code>, последующие узлы могут не получить это сообщение.
</p>
<p>
Если какой-либо элемент массива сам является массивом сообщений, тогда на соответствующий выход отправляется несколько сообщений.
</p>
<p>
Если возвращен null, либо сам по себе, либо как элемент массива, тогда сообщение не передается.
</p>
<h4>Ведение журнала и обработка ошибок</h4>
<p>
Для добавления информации в журнал или сообщения об ошибке доступны следующие функции:
</p>
<ul>
<li><code>node.log("Сообщение для журнала")</code></li>
<li><code>node.warn("Предупреждение")</code></li>
<li><code>node.error("Ошибка")</code></li>
</ul>
<p>
Также узел Catch может использоваться для обработки ошибок. Чтобы можно было ловить оповещения об ошибке, при вызове <code>node.error</code> передайте <code>msg</code> в качестве второго аргумента:
</p>
<pre>node.error("Ошибка", msg);</pre>
<h4>Доступ к информации об узле</h4>
<p>
В функции можно обращаться к идентификатору и имени узла, используя следующие свойства:
</p>
<ul>
<li><code>node.id</code> - идентификатор узла</li>
<li><code>node.name</code> - имя узла</li>
</ul>
<h4>Использование переменных среды</h4>
<p>
Доступ к переменным среды можно получить с помощью <code>env.get("MY_ENV_VAR")</code>.
</p>
</script>

View File

@@ -0,0 +1,59 @@
<!--
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/html" data-help-name="switch">
<p>
Направляет сообщения по разным ветвям потока, в завсимости от значений свойств сообщения или его позиции в последовательности.
</p>
<h3>Подробности</h3>
<p>
Когда приходит сообщение, узел выполняет проверку соответствия сообщения каждому из установленных правил и перенаправляет сообщение на соответствующие выходы.
</p>
<p>
При желании узел может быть настроен на прекращение проверки правил после того как найдено первое подходящее.
</p>
<p>
Правила могут применяться к свойству сообщения, свойству потокового или глобального контекста, переменной среды или результату выражения JSONata.
</p>
<h4>Правила</h4>
<p>
Существует четыре типа правил:
</p>
<ol>
<li>Правила категории <b>value rules</b> сравнивают значение указанного свойства сообщения</li>
<li>Правила категории <b>sequence rules</b> могут применяться для последовательностей сообщений, таких как сгенерированные узлом Split</li>
<li><b>Выражение JSONata</b> исполняется для сообщения и считается подходящим, если оно возвращает истинное значение</li>
<li>Правило <b>иначе</b> используется для сообщений, не подходящих ни под одно из предыдущих правил.</li>
</ol>
<h4>Примечание</h4>
<p>
Правила <code>равно true/false</code> и <code>равно null</code> проводят строгое сравнение с этими типами. Они не конвертируются между типами.
</p>
<p>
Правила <code>пустое</code> и <code>не пустое</code> могут быть использованы для проверки длины строк, массивов и буферов, или количества свойств, которые содержит объект. Эти правила не подходят, если тестируемое свойство содержит значение <code>логического типа</code>, <code>null</code> или <code>undefined</code>.
</p>
<h4>Обработка последовательностей сообщений</h4>
<p>
По умолчанию узел не изменяет свойство <code>msg.parts</code> у сообщений, являющихся частью последовательности.
</p>
<p>
Можно включить параметр <b>пересоздавать последовательности сообщений</b> для создания новых последовательностей сообщений для каждого соответствующего правила. В этом режиме узел будет помещать в буфер всю входящую последовательность перед отправкой новых последовательностей. Настройка <code>nodeMessageBufferMaxLength</code> может быть использована для ограничения количества сообщений в буфере.
</p>
</script>

View File

@@ -0,0 +1,42 @@
<!--
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/html" data-help-name="change">
<p>
Устанавливает, изменяет, удаляет или перемещает свойства сообщения, контекста потока или глобального контекста.
</p>
<p>
В узле можно указать несколько операций, которые будут применяться в том порядке, в котором они заданы.
</p>
<h3>Подробности</h3>
<p>
Доступные операции:
</p>
<dl class="message-properties">
<dt>Установить</dt>
<dd>устанавливает свойство. Значение может быть различных типов или может быть взято из существующего свойства сообщения или контекста.</dd>
<dt>Изменить</dt>
<dd>ищет и заменяет части текста в свойстве сообщения. Если используется регулярное выражение, настройка &quot;заменить на&quot; может включать группы захвата, например <code>$1</code>. При полном совпадении заменяет только тип.</dd>
<dt>Удалить</dt>
<dd>удаляет свойство.</dd>
<dt>Переместить</dt>
<dd>перемещает или переименовывает свойство.</dd>
</dl>
<p>
Тип свойства &quot;выражение&quot; использует язык запросов и выражений <a href="http://jsonata.org/" target="_new">JSONata</a>.
</p>
</script>

View File

@@ -0,0 +1,59 @@
<!--
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/html" data-help-name="range">
<p>
Соотносит значение одного числового диапазона с другим числовым диапазоном.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">число</span></dt>
<dd>Данные <i>должны</i> быть числом. Данные другого типа будут преобразованы в число и отклонены, если это не удастся.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">число</span></dt>
<dd>Значение, соотнесенное с новым диапазоном.</dd>
</dl>
<h3>Подробности</h3>
<p>
Этот узел будет линейно масштабировать полученное значение. По умолчанию результат не ограничен диапазоном, определенным в узле.
</p>
<p>
<i>Масштабировать и ограничить целевым диапазоном</i> означает, что результат никогда не будет выходить за пределы диапазона, указанного в целевом диапазоне.
</p>
<p>
<i>Масштабировать и обернуть в целевой диапазон</i> означает, что результат будет обернут вокруг целевого диапазона:
</p>
<p>
Например, если входные 0 - 10 сопоставляются с 0 - 100:
</p>
<table style="outline-width:#888 solid thin">
<tr><th width="80px">режим</th><th width="80px">вход</th><th width="80px">выход</th></tr>
<tr><td><center>масштабировать</center></td><td><center>2</center></td><td><center>20</center></td></tr>
<tr><td><center>ограничить</center></td><td><center>2</center></td><td><center>20</center></td></tr>
<tr><td><center>обернуть</center></td><td><center>2</center></td><td><center>20</center></td></tr>
<tr><td><center>масштабировать</center></td><td><center>12</center></td><td><center>120</center></td></tr>
<tr><td><center>ограничить</center></td><td><center>12</center></td><td><center>100</center></td></tr>
<tr><td><center>обернуть</center></td><td><center>12</center></td><td><center>20</center></td></tr>
<tr><td><center>масштабировать</center></td><td><center>18</center></td><td><center>180</center></td></tr>
<tr><td><center>ограничить</center></td><td><center>18</center></td><td><center>100</center></td></tr>
<tr><td><center>обернуть</center></td><td><center>18</center></td><td><center>80</center></td></tr>
</table>
</script>

View File

@@ -0,0 +1,63 @@
<!--
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/html" data-help-name="template">
<p>
Генерирует текст по установленному шаблону и присваивает его выбранному свойству сообщения.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">объект</span></dt>
<dd>Объект сообщения msg, содержащий информацию для заполнения шаблона.</dd>
<dt class="optional">шаблон <span class="property-type">строка</span></dt>
<dd>Шаблон текста для заполнения данными из сообщения msg. Если шаблон не введен на панели редактирования, тогда он может быть установлен через свойство msg.template.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">объект</span></dt>
<dd>Сообщение msg, у которого выбранному свойству присвоено тексктовое значение, полученное после заполнения шаблона данными входящего сообщения.</dd>
</dl>
<h3>Подробности</h3>
<p>
По умолчанию используется формат <i><a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache</a></i>. При необходимости это можно отключить.
</p>
<p>
Например, когда шаблон:
</p>
<pre>Привет, {{payload.name}}. Сегодня {{date}}.</pre>
<p>
получает сообщение msg, содержащее:
</p>
<pre>{
date: "понедельник",
payload: {
name: "Иван"
}
}</pre>
<p>
Выбранному свойству будет присвоен текст:
</p>
<pre>Привет, Иван. Сегодня понедельник.</pre>
<p>
Можно использовать свойство из контекста потока или глобального контекста. Просто используйте <code>{{flow.name}}</code> или <code>{{global.name}}</code>, или для постоянного хранилища <code>store</code> используйте <code>{{flow[store].name}}</code> или <code>{{global[store].name}}</code>.
</p>
<p>
<b>Примечание:</b> по умолчанию <i>mustache</i> заменяет определенные символы их escape-кодами для безопасного использования в HTML. Чтобы это не происходило, вы можете использовать тройные фигурные скобки <code>{{{triple}}}</code>.
</p>
</script>

View File

@@ -0,0 +1,40 @@
<!--
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/html" data-help-name="delay">
<p>
Задерживает каждое сообщение, проходящее через узел, или ограничивает скорость, с которой они могут проходить.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">число</span></dt>
<dd>Устанавливает задержку в миллисекундах, которая будет применена к сообщению. Этот параметр применяется только в том случае, если узел настроен так, чтобы разрешать сообщению переопределять установленный интервал задержки по умолчанию.</dd>
<dt class="optional">reset</dt>
<dd>Если в полученном сообщении этому свойству присвоено какое-либо значение, все ожидающие сообщения, удерживаемые узлом, сбрасываются без дальнейшей отправки.</dd>
<dt class="optional">flush</dt>
<dd>Если в полученном сообщении этому свойству присвоено какое-либо значение, все ожидающие сообщения, удерживаемые узлом, немедленно отправляются далее.</dd>
</dl>
<h3>Подробности</h3>
<p>
Когда узел настроен на задержку сообщений, интервал задержки может быть фиксированным значением, случайным значением в пределах диапазона или динамически установленным для каждого сообщения. Каждое сообщение задерживается независимо от любых других сообщений, основываясь на времени его прибытия в узел.
</p>
<p>
Когда узел настроен на ограничение скорости сообщений, их доставка распределяется по установленному периоду времени. Статус показывает количество сообщений, находящихся в данный момент в очереди. При необходимости узел может быть настроен на отбрасывание промежуточных сообщений по мере их поступления.
</p>
<p>
Ограничение скорости может применяться ко всем сообщениям или группам сообщений в соответствии с их значением темы (<code>msg.topic</code>). При группировании промежуточные сообщения автоматически отбрасываются. В каждом интервале времени узел может либо выпустить самое последнее сообщение для всех тем, либо выпустить самое последнее сообщение для следующей темы.
</p>
</script>

View File

@@ -0,0 +1,55 @@
<!--
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/html" data-help-name="trigger">
<p>
При срабатывании может отправить сообщение, а затем дополнительно второе сообщение, если не было сделано продление или сброс.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">число</span></dt>
<dd>Устанавливает задержку в миллисекундах, которая будет применяться к сообщению. Этот параметр применяется только в том случае, если узел настроен так, чтобы сообщение могло отменять настроенный интервал задержки по умолчанию.</dd>
<dt class="optional">reset</dt>
<dd>При получении сообщения с этим свойством, любой тайм-аут или повтор, находящиеся в обработке в текущий момент, будут сброшены, а сообщение не сработает.</dd>
</dl>
<h3>Подробности</h3>
<p>
Этот узел можно использовать для создания тайм-аута внутри потока. По умолчанию, когда узел получает сообщение, он отправляет сообщение с <code>payload</code> равным <code>1</code>. Затем он ждет 250 мс, прежде чем отправить второе сообщение с <code>payload</code> равным <code>0</code>. Это можно использовать, например, для мигания светодиодом, подключеным к выходу GPIO у Raspberry Pi.
</p>
<p>
Данные каждого отправленного сообщения могут быть настроены на различные значения, включая возможность ничего не отправлять. Например, если установить первоначальное сообщение на <i>ничего</i> и выбрать опцию продления таймера с каждым новым сообщением, узел будет действовать как сторожевой таймер, отправляя сообщение только в том случае, если ничего не получено в течение установленного интервала.
</p>
<p>
Если установлен тип <i>строка</i>, узел поддерживает синтаксис шаблона mustache.
</p>
<p>
Задержка между отправкой сообщений может быть изменена с помощью <code>msg.delay</code>, если эта опция включена в узле. Значение должно быть указано в миллисекундах.
</p>
<p>
Если узел получает сообщение со свойством <code>reset</code> или <code>payload</code>, который совпадает с настроенным в узле, любой тайм-аут или повтор, находящийся в обработке в текущий момент, будет сброшен, и сообщение не сработает.
</p>
<p>
Узел может быть настроен на повторную отправку сообщения с регулярным интервалом, пока не будет произведен сброс отправкой на него сообщения.
</p>
<p>
При желании узел может быть настроен на обработку сообщений, как если бы они были отдельными потоками, используя свойство msg для идентификации каждого потока. По умолчанию <code>msg.topic</code>.
</p>
<p>
Статус показывает - активен ли узел в данный момент. Если работает в многопоточном режиме, статус показывает количество удерживаемых потоков.
</p>
</script>

View File

@@ -0,0 +1,106 @@
<!--
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/html" data-help-name="exec">
<p>
Запускает системную команду и возвращает ее вывод.
</p>
<p>
Узел может быть настроен либо на ожидание завершения выполнения команды, либо на отправку выходных данных по мере их генерации в ходе выполнения.
</p>
<p>
Выполняемая команда может быть установлена в настройках узла или полученным сообщением.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">payload <span class="property-type">строка</span></dt>
<dd>будет добавлено к выполняемой команде, если узел настроен так делать.</dd>
<dt class="optional">kill <span class="property-type">строка</span></dt>
<dd>тип сигнала уничтожения для отправки существующему процессу узла exec.</dd>
<dt class="optional">pid <span class="property-type">число|строка</span></dt>
<dd>идентификатор существующего процесса узла exec для уничтожения.</dd>
</dl>
<h3>Выводит</h3>
<ol class="node-ports">
<li>Стандартный вывод
<dl class="message-properties">
<dt>payload <span class="property-type">строка</span></dt>
<dd>стандартный вывод команды.</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">объект</span></dt>
<dd>только в exec режиме, копия объекта кода возврата (также доступна по 3-му порту)</dd>
</dl>
</li>
<li>Стандартный вывод ошибок
<dl class="message-properties">
<dt>payload <span class="property-type">строка</span></dt>
<dd>стандартная ошибка команды.</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">объект</span></dt>
<dd>только в exec режиме, копия объекта кода возврата (также доступна по 3-му порту)</dd>
</dl>
</li>
<li>Код возврата
<dl class="message-properties">
<dt>payload <span class="property-type">объект</span></dt>
<dd>объект, содержащий код возврата и, возможно, свойства <code>message</code>, <code>signal</code>.</dd>
</dl>
</li>
</ol>
<h3>Подробности</h3>
<p>
По умолчанию используется системный вызов <code>exec</code>, который вызывает команду, ожидает ее завершения и возвращает результат. Например, успешная команда должна иметь код возврата <code>{code: 0}</code>.
</p>
<p>
При желании вместо этого можно использовать <code>spawn</code>, который возвращает выходные данные из stdout и stderr по ходу выполнения команды, обычно по одной строке за раз. После завершения он возвращает объект на 3-й порт. Например, успешная команда должна вернуть <code>{code: 0}</code>.
</p>
<p>
Ошибки могут возвращать на 3-й порт дополнительную информацию в <code>msg.payload</code>, такую как строка <code>message</code>, строка <code>signal</code>.
</p>
<p>
Выполняемая команда настраивается в узле, с возможностью добавления к ней <code>msg.payload</code> и дополнительного набора параметров.
</p>
<p>
Команды или параметры с пробелами должны быть заключены в кавычки - <code>"Это один параметр"</code>
</p>
<p>
Возвращаемый <code>payload</code> обычно представляет собой <i>строку</i>, пока не обнаружены символы, отличные от UTF8, в этом случае возвращаемое значение будет иметь тип <i>буфер</i>.
</p>
<p>
Значок статуса узла и PID будут видны, когда узел активен. Изменения в статусе можно отслеживать узлом <code>Status</code>.
</p>
<h4>
Уничтожения процессов
</h4>
<p>
Отправка <code>msg.kill</code> уничтожит один активный процесс. <code>msg.kill</code> должен быть строкой, содержащей тип передаваемого сигнала, например, <code>SIGINT</code>, <code>SIGQUIT</code> или <code>SIGHUP</code>. По умолчанию будет передан <code>SIGTERM</code>, если задана пустая строка.
</p>
<p>
Если узлом запущено более одного процесса, тогда в <code>msg.pid</code> также должно быть установлено значение PID процесса для уничтожения.
</p>
<p>
Если в поле <code>Тайм-аут</code> введено значение, тогда, если процесс не завершится по истечении указанного количества секунд, он будет автоматически уничтожен.
</p>
<p>
Совет: если вы запускаете Python приложение, вам может потребоваться использование параметра <code>-u</code>, чтобы остановить буферизацию вывода.
</p>
</script>

View File

@@ -0,0 +1,969 @@
{
"common": {
"label": {
"payload": "Данные",
"topic": "Тема",
"name": "Имя",
"username": "Имя польз.",
"password": "Пароль",
"property": "Свойство",
"selectNodes": "Выберите узлы...",
"expand": "Развернуть"
},
"status": {
"connected": "подключен",
"not-connected": "не подключен",
"disconnected": "соединение разорвано",
"connecting": "идет подключение",
"error": "ошибка",
"ok": "OK"
},
"notification": {
"error": "<strong>Ошибка</strong>: __message__",
"errors": {
"not-deployed": "узел не развернут",
"no-response": "нет ответа от сервера",
"unexpected": "непредвиденная ошибка (__status__) __message__"
}
},
"errors": {
"nooverride": "Предупреждение: свойства msg больше не могут переопределять установленные свойства узла. Смотрите bit.ly/nr-override-msg-props"
}
},
"inject": {
"inject": "запустить",
"repeat": "повторы = __repeat__",
"crontab": "crontab = __crontab__",
"stopped": "остановлено",
"failed": "Не удалось запустить: __error__",
"label": {
"properties": "Свойства",
"repeat": "Повторять",
"flow": "контекст потока",
"global": "глобальный контекст",
"str": "строка",
"num": "число",
"bool": "логический тип",
"json": "объект",
"bin": "буфер",
"date": "метка времени",
"env": "переменная среды",
"object": "объект",
"string": "строка",
"boolean": "логический тип",
"number": "число",
"Array": "массив",
"invalid": "Неверный объект JSON"
},
"timestamp": "метка времени",
"none": "нет",
"interval": "с интервалом",
"interval-time": "с интервалом в промежутке",
"time": "в определенное время",
"seconds": "сек",
"minutes": "мин",
"hours": "час",
"between": "между",
"previous": "предыдущее значение",
"at": "в",
"and": "и",
"every": "каждые",
"days": [
"пн",
"вт",
"ср",
"чт",
"пт",
"сб",
"вс"
],
"on": "по",
"onstart": "Отправить через",
"onceDelay": "сек, затем",
"success": "Успешно отправлено: __label__",
"errors": {
"failed": "запуск не удался, смотрите подробности в журнале",
"toolong": "Интервал слишком большой",
"invalid-expr": "Неверное выражение JSONata: __error__"
}
},
"catch": {
"catch": "ловить: все",
"catchNodes": "ловить: __number__",
"catchUncaught": "ловить: непойманные",
"label": {
"source": "Ловить ошибки",
"selectAll": "выбрать все",
"uncaught": "Игнорировать ошибки, пойманные другими узлами Catch"
},
"scope": {
"all": "всех узлов",
"selected": "выбранных узлов"
}
},
"status": {
"status": "статус: все",
"statusNodes": "статус: __number__",
"label": {
"source": "Получать статус",
"sortByType": "сортировать по типу"
},
"scope": {
"all": "всех узлов",
"selected": "выбранных узлов"
}
},
"complete": {
"completeNodes": "завершение: __number__"
},
"debug": {
"output": "Выводить",
"status": "статус",
"none": "Нет",
"invalid-exp": "Неверное выражение JSONata: __error__",
"msgprop": "свойство сообщения",
"msgobj": "весь msg объект сообщения",
"autostatus": "то, что выводит этот узел",
"to": "В",
"debtab": "вкладка отладки",
"tabcon": "вкладка отладки и консоль",
"toSidebar": "окно отладки",
"toConsole": "системную консоль",
"toStatus": "статус узла (32 символа)",
"severity": "Уровень",
"notification": {
"activated": "Успешно активирован: __label__",
"deactivated": "Успешно деактивирован: __label__"
},
"sidebar": {
"label": "отладка",
"name": "Отладочные сообщения",
"filterAll": "все узлы",
"filterSelected": "выбранные узлы",
"filterCurrent": "текущий поток",
"debugNodes": "Отладочные узлы",
"clearLog": "Очистить журнал",
"filterLog": "Фильтровать журнал",
"openWindow": "Открыть в новом окне",
"copyPath": "Копировать путь",
"copyPayload": "Копировать значение",
"pinPath": "Закрепить видимость"
},
"messageMenu": {
"collapseAll": "Свернуть все пути",
"clearPinned": "Очистить закреп. пути",
"filterNode": "Фильтровать этот узел",
"clearFilter": "Очистить фильтр"
}
},
"link": {
"linkIn": "связь (вход)",
"linkOut": "связь (выход)"
},
"tls": {
"tls": "Конфигурация TLS",
"label": {
"use-local-files": "Использовать ключ и сертификаты из локальных файлов",
"upload": "Загрузить",
"cert": "Сертификат",
"key": "Закрытый ключ",
"passphrase": "Пароль",
"ca": "CA сертификат",
"verify-server-cert":"Проверить сертификат сервера",
"servername": "Имя сервера"
},
"placeholder": {
"cert":"путь к сертификату (формат PEM)",
"key":"путь к закрытому ключу (формат PEM)",
"ca":"путь к сертификату CA (формат PEM)",
"passphrase":"пароль закрытого ключа (необязательно)",
"servername":"для использования с SNI"
},
"error": {
"missing-file": "Файл сертификата/ключа не предоставлен"
}
},
"exec": {
"exec": "выполнить",
"spawn": "выполнить в новом процессе",
"label": {
"command": "Команда",
"append": "Добавить",
"timeout": "Тайм-аут",
"timeoutplace": "необяз",
"return": "Вывод",
"seconds": "сек",
"stdout": "стандартный вывод",
"stderr": "стандартный вывод ошибок",
"retcode": "код возврата"
},
"placeholder": {
"extraparams": "дополнительные параметры"
},
"opt": {
"exec": "когда команда завершена - exec режим",
"spawn": "пока команда работает - spawn режим"
},
"oldrc": "Использовать вывод в старом стиле (режим совместимости)"
},
"function": {
"function": "",
"label": {
"function": "Функция",
"initialize": "Настройка",
"finalize": "Закрытие",
"outputs": "Выходы"
},
"text": {
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",
"finalize": "// Добавленный здесь код будет исполняться при\n// остановке узла или повторном развертывании.\n"
},
"error": {
"inputListener":"Невозможно добавить слушателя к событию 'input' в функции",
"non-message-returned":"Функция пыталась отправить сообщение типа __type__"
}
},
"template": {
"template": "шаблон",
"label": {
"template": "Шаблон",
"property": "Свойство",
"format": "Подсветка синтаксиса",
"syntax": "Формат",
"output": "Вывести как",
"mustache": "Mustache шаблон",
"plain": "Простой текст",
"json": "JSON",
"yaml": "YAML",
"none": "нет"
},
"templatevalue": "А вот и данные: {{payload}} !"
},
"delay": {
"action": "Действие",
"for": "На",
"delaymsg": "Задержка каждого сообщения",
"delayfixed": "Фиксированная задержка",
"delayvarmsg": "Переопределять задержку с msg.delay",
"randomdelay": "Случайная задержка",
"limitrate": "Ограничение скорости",
"limitall": "Все сообщения",
"limittopic": "Для каждого msg.topic",
"fairqueue": "Отправлять темы по очереди",
"timedqueue": "Отправлять все темы",
"milisecs": "мсек",
"secs": "сек",
"sec": "сек",
"mins": "мин",
"min": "мин",
"hours": "час",
"hour": "час",
"days": "сут",
"day": "сут",
"between": "Между",
"and": "и",
"rate": "Скорость",
"msgper": "сообщений в",
"dropmsg": "без промежуточных сообщений",
"label": {
"delay": "задержка",
"variable": "переменная",
"limit": "ограничение",
"limitTopic": "ограничение темы",
"random": "случайный",
"units" : {
"second": {
"plural" : "сек",
"singular": "сек"
},
"minute": {
"plural" : "мин",
"singular": "мин"
},
"hour": {
"plural" : "час",
"singular": "час"
},
"day": {
"plural" : "сут",
"singular": "сут"
}
}
},
"error": {
"buffer": "буфер превысил 1000 сообщений",
"buffer1": "буфер превысил 10000 сообщений"
}
},
"trigger": {
"send": "Отправить",
"then": "затем",
"then-send": "затем отправить",
"output": {
"string": "строку",
"number": "число",
"existing": "существующий объект сообщения",
"original": "оригинальный объект сообщения",
"latest": "последний объект сообщения",
"nothing": "ничего"
},
"wait-reset": "ждать сброс",
"wait-for": "ждать",
"wait-loop": "переотправлять его каждые",
"for": "Обрабатывать",
"bytopics": "каждый",
"alltopics": "все сообщения",
"duration": {
"ms": "мсек",
"s": "сек",
"m": "мин",
"h": "час"
},
"extend": " продлить при поступлении нового сообщения",
"override": "заменить задержку через msg.delay",
"second": " отправить второе сообщение на отдельный выход",
"label": {
"trigger": "триггер",
"trigger-block": "триггер & блок",
"trigger-loop": "переотправлять каждые",
"reset": "Сбрасывать триггер, если:",
"resetMessage":"установлен msg.reset",
"resetPayload":"msg.payload равен",
"resetprompt": "необязательно"
}
},
"comment": {
"comment": "комментарий"
},
"unknown": {
"label": {
"unknown": "неизвестный"
},
"tip": "<p>Тип этого узла неизвестен Вашей установке Node-RED.</p><p><i>Если Вы развернете узел в этом состоянии, его конфигурация будет сохранена, но поток не будет запущен, пока отсутствующий тип не будет установлен.</i></p><p>Дополнительную справку смотрите в информационной вкладке на боковой панели</p>"
},
"mqtt": {
"label": {
"broker": "Сервер",
"example": "например, localhost",
"output": "Выход",
"qos": "QoS",
"retain": "Хранить",
"clientid": "ID клиента",
"port": "Порт",
"keepalive": "Keep-alive время (сек)",
"cleansession": "Использовать чистую сессию",
"use-tls": "Включить безопасное (SSL/TLS) соединение",
"tls-config":"Конфигурация TLS",
"verify-server-cert":"Проверить сертификат сервера",
"compatmode": "Использовать устаревшую поддержку MQTT 3.1"
},
"sections-label":{
"birth-message": "Сообщение отправляемое при подключении (birth сообщение)",
"will-message":"Сообщение отправляемое при неожиданном отключении (will message)",
"close-message":"Сообщение отправляемое перед отключением (close сообщение)"
},
"tabs-label": {
"connection": "Соединение",
"security": "Безопасность",
"messages": "Сообщения"
},
"placeholder": {
"clientid": "Оставьте пустым для автоматически сгенерированного",
"clientid-nonclean":"Должен быть установлен для не чистых сессий",
"will-topic": "Оставьте пустым, чтобы отключить will сообщение",
"birth-topic": "Оставьте пустым, чтобы отключить birth сообщение",
"close-topic": "Оставьте пустым, чтобы отключить close сообщение"
},
"state": {
"connected": "Подключен к брокеру: __broker__",
"disconnected": "Отключен от брокера: __broker__",
"connect-failed": "Не удалось подключиться к брокеру: __broker__"
},
"retain": "Хранить",
"output": {
"buffer": "буфер",
"string": "строка",
"base64": "строка в кодировке Base64",
"auto": "автоопределение (строка или буфер)",
"json": "объект JSON"
},
"true": "да",
"false": "нет",
"tip": "Совет: Оставьте тему, qos или хранение пустыми, если Вы хотите устанавливать их через свойства msg.",
"errors": {
"not-defined": "тема не определена",
"missing-config": "отсутствует конфигурация брокера",
"invalid-topic": "Указана неверная тема",
"nonclean-missingclientid": "ID клиента не установлен, используется чистая сессия",
"invalid-json-string": "Неверная строка JSON",
"invalid-json-parse": "Не удалось проанализировать строку JSON"
}
},
"httpin": {
"label": {
"method": "Метод",
"url": "URL",
"doc": "Docs",
"return": "Возврат",
"upload": "Принимать загрузки файлов?",
"status": "Код состояния",
"headers": "Заголовки",
"other": "другое",
"paytoqs": {
"ignore": "Игнорировать",
"query": "Добавлять к параметрам строки запроса",
"body": "Отправлять как тело запроса"
},
"utf8String": "Строка UTF8",
"binaryBuffer": "двоичный буфер",
"jsonObject": "объект JSON",
"authType": "Тип",
"bearerToken": "Токен"
},
"setby": "- устанавливается через msg.method -",
"basicauth": "Использовать аутентификацию",
"use-tls": "Включить безопасное (SSL/TLS) соединение",
"tls-config":"Конфигурация TLS",
"basic": "basic аутентификация",
"digest": "digest аутентификация",
"bearer": "bearer authentication",
"use-proxy": "Использовать прокси",
"persist": "Включить keep-alive соединение",
"proxy-config": "Конфигурация прокси",
"use-proxyauth": "Использовать прокси-аутентификацию",
"noproxy-hosts": "Игнор. хосты",
"utf8": "строка UTF-8",
"binary": "двоичный буфер",
"json": "объект JSON",
"tip": {
"in": "URL будет относительно ",
"res": "Сообщения, отправляемые на этот узел <b>должны</b> отправляться с узла <i>http input</i>",
"req": "Совет: Если анализ JSON не удается, полученная строка возвращается как есть."
},
"httpreq": "http запрос",
"errors": {
"not-created": "Невозможно создать узел http-in, когда httpNodeRoot установлено в false",
"missing-path": "пропущен путь",
"no-response": "Нет объекта ответа",
"json-error": "Ошибка анализа JSON",
"no-url": "URL не указан",
"deprecated-call":"Устаревший вызов __method__",
"invalid-transport":"запрошен не-http транспорт",
"timeout-isnan": "Значение тайм-аута не является действительным числом, проигнорировано",
"timeout-isnegative": "Значение тайм-аута отрицательно, проигнорировано",
"invalid-payload": "Неверные данные"
},
"status": {
"requesting": "запрос"
}
},
"websocket": {
"label": {
"type": "Тип",
"path": "Путь",
"url": "URL"
},
"listenon": "Слушать на ...",
"connectto": "Присоединиться к ...",
"sendrec": "Отправить/Получить",
"payload": "msg.payload данные",
"message": "весь msg объект сообщение",
"tip": {
"path1": "По умолчанию <code>payload</code> будет содержать данные, которые будут отправлены или получены из websocket. Слушатель может быть настроен на отправку или получение всего объекта сообщения в виде строки в формате JSON.",
"path2": "Путь будет относительно <code>__path__</code>.",
"url1": "URL должен использовать схему ws:&#47;&#47; или wss:&#47;&#47; и указывать на существующего слушателя websocket.",
"url2": "По умолчанию <code>payload</code> будет содержать данные, которые будут отправлены или получены из websocket. Клиент может быть настроен на отправку или получение всего объекта сообщения в виде строки в формате JSON."
},
"status": {
"connected": "подключен __count__",
"connected_plural_2": "подключено __count__",
"connected_plural_5": "подключено __count__"
},
"errors": {
"connect-error": "Произошла ошибка в соединении ws: ",
"send-error": "Произошла ошибка при отправке: ",
"missing-conf": "Отсутствует конфигурация сервера",
"duplicate-path": "Не может быть двух слушателей WebSocket по одному пути: __path__"
}
},
"watch": {
"watch": "наблюдение",
"label": {
"files": "Файл(ы)",
"recursive": "Наблюдать за подкаталогами рекурсивно"
},
"placeholder": {
"files": "Разделенный запятыми список файлов и/или каталогов"
},
"tip": "В Windows Вы должны использовать двойную обратную косую черту \\\\ в любых именах каталогов."
},
"tcpin": {
"label": {
"type": "Тип",
"output": "Вывод",
"port": "порт",
"host": "к хосту",
"payload": "данные",
"delimited": "разделены с",
"close-connection": "Закрывать соединение после отправки каждого сообщения?",
"decode-base64": "Расшифровать сообщение Base64?",
"server": "Сервер",
"return": "Возврат",
"ms": "мсек",
"chars": "симв."
},
"type": {
"listen": "Слушать",
"connect": "Подключиться",
"reply": "Ответить на TCP"
},
"output": {
"stream": "поток",
"single": "одиночный",
"buffer": "буфер",
"string": "строка",
"base64": "строка Base64"
},
"return": {
"timeout": "по истечении времени ожидания",
"character": "когда получен символ",
"number": "по получении N символов",
"never": "никогда - держать соединение открытым",
"immed": "немедленно - не ждать ответа"
},
"status": {
"connecting": "подключение к __host__:__port__",
"connected": "подключен к __host__:__port__",
"listening-port": "прослушивание порта __port__",
"stopped-listening": "прослушивание порта остановлено",
"connection-from": "соединение от __host__:__port__",
"connection-closed": "закрыто соединение от __host__:__port__",
"connections": "__count__ соединение",
"connections_plural_2": "__count__ соединения",
"connections_plural_5": "__count__ соединений"
},
"errors": {
"connection-lost": "потеряно соединение с __host__:__port__",
"timeout": "сокет на порту __port__ закрыт из-за превышения времени ожидания",
"cannot-listen": "невозможно прослушивать порт __port__, ошибка: __error__",
"error": "ошибка: __error__",
"socket-error": "ошибка сокета от __host__:__port__",
"no-host": "Хост и/или порт не установлены",
"connect-timeout": "превышено время ожидания подключения",
"connect-fail": "подключение не удалось"
}
},
"udp": {
"label": {
"listen": "Слушать",
"onport": "на порте",
"using": "используя",
"output": "Выход",
"group": "Группа",
"interface": "Локал. IF",
"send": "Отправлять",
"toport": "на порт",
"address": "Адрес",
"decode-base64": "Декодировать данные кодированные в Base64?"
},
"placeholder": {
"interface": "(необяз) локальный интерфейс или адрес для привязки",
"interfaceprompt": "(необяз) локальный интерфейс или адрес для привязки",
"address": "IP-адрес назначения"
},
"udpmsgs": "UDP сообщения",
"mcmsgs": "многоадресные сообщения",
"udpmsg": "UDP сообщение",
"bcmsg": "широковещательное сообщение",
"mcmsg": "многоадресное сообщение",
"output": {
"buffer": "буфер",
"string": "строка",
"base64": "строка Base64"
},
"bind": {
"random": "привязать к случайному локальному порту",
"local": "привязать к локальному порту",
"target": "привязать к целевому порту"
},
"tip": {
"in": "Совет: убедитесь, что Ваш брандмауэр разрешит вхождение данных.",
"out": "Совет: оставьте адрес и порт пустыми, если вы хотите установить их, используя <code>msg.ip</code> и <code>msg.port</code>.",
"port": "Уже используемые порты: "
},
"status": {
"listener-at": "слушатель udp на __host__:__port__",
"mc-group": "группа многоадресной рассылки udp __group__",
"listener-stopped": "слушатель udp остановлен",
"output-stopped": "выход udp остановлен",
"mc-ready": "многоадресная рассылка udp готова: __iface__:__outport__ -> __host__:__port__",
"bc-ready": "широковещательная рассылка udp готова: __outport__ -> __host__:__port__",
"ready": "udp готов: __outport__ -> __host__:__port__",
"ready-nolocal": "udp готов: __host__:__port__",
"re-use": "сокет повторного использования udp: __outport__ -> __host__:__port__"
},
"errors": {
"access-error": "Ошибка доступа UDP, Вам может потребоваться доступ с правами root для портов ниже 1024",
"error": "ошибка: __error__",
"bad-mcaddress": "Неверный адрес многоадресной рассылки",
"interface": "Должен быть IP-адрес требуемого интерфейса",
"ip-notset": "UDP: IP-адрес не установлен",
"port-notset": "UDP: порт не установлен",
"port-invalid": "UDP: номер порта недействителен",
"alreadyused": "UDP: порт __port__ уже используется",
"ifnotfound": "UDP: интерфейс __iface__ не найден"
}
},
"switch": {
"switch": "направить",
"label": {
"property": "Свойство",
"rule": "правило",
"repair": "воссоздать последовательность сообщений"
},
"previous": "предыдущее значение",
"and": "и",
"checkall": "проверка всех правил",
"stopfirst": "остановка после первого совпадения",
"ignorecase": "игнорировать регистр",
"rules": {
"btwn": "между",
"cont": "содержит",
"regex": "подходит под регул. выраж.",
"true": "равно true",
"false": "равно false",
"null": "равно null",
"nnull": "не равно null",
"istype": "является типом",
"empty": "пустое",
"nempty": "не пустое",
"head": "первые N",
"tail": "последние N",
"index": "индекс между",
"exp": "выраж. JSONata",
"else": "иначе",
"hask": "имеет ключ"
},
"errors": {
"invalid-expr": "Неверное выражение JSONata: __error__",
"too-many": "слишком много ожидающих сообщений в узле switch"
}
},
"change": {
"label": {
"rules": "Правила",
"rule": "правило",
"set": "установить __property__",
"change": "изменить __property__",
"delete": "удалить __property__",
"move": "переместить __property__",
"changeCount": "изменить: __count__ правило",
"changeCount_plural_2": "изменить: __count__ правила",
"changeCount_plural_5": "изменить: __count__ правил",
"regex": "Использовать регул. выражение"
},
"action": {
"set": "Установить",
"change": "Изменить",
"delete": "Удалить",
"move": "Переместить",
"to": "в",
"search": "Искать",
"replace": "Заменить на"
},
"errors": {
"invalid-from": "Неверное свойство 'from': __error__",
"invalid-json": "Неверное свойство JSON 'to'",
"invalid-expr": "Неверное выражение JSONata: __error__",
"no-override": "Невозможно установить свойство необъектного типа: __property__"
}
},
"range": {
"range": "Диапазон",
"label": {
"action": "Действие",
"inputrange": "Сопоставить входной диапазон",
"resultrange": "с целевым диапазоном",
"from": "от",
"to": "до",
"roundresult": "Округлять результат до ближайшего целого числа?"
},
"placeholder": {
"min": "напр. 0",
"maxin": "напр. 99",
"maxout": "напр. 255"
},
"scale": {
"payload": "Масштабировать msg-свойство",
"limit": "Масштабировать и ограничить целевым диапазоном",
"wrap": "Масштабировать и обернуть в целевой диапазон"
},
"tip": "Совет: этот узел работает ТОЛЬКО с числами.",
"errors": {
"notnumber": "Не число"
}
},
"csv": {
"label": {
"columns": "Столбцы",
"separator": "Разделитель",
"c2o": "Опции CSV -> Объект",
"o2c": "Опции Объект -> CSV",
"input": "Вход",
"skip-s": "Пропускать первые",
"skip-e": "строк(и)",
"firstrow": "первый ряд содержит имена столбцов",
"output": "Выход",
"includerow": "включать ряд с именами столбцов",
"newline": "Новая строка",
"usestrings": "разбирать числовые значения",
"include_empty_strings": "включать пустые строковые значения",
"include_null_values": "включать null-значения"
},
"placeholder": {
"columns": "имена столбцов через запятую"
},
"separator": {
"comma": "запятая",
"tab": "табуляция",
"space": "пробел",
"semicolon": "точка с запятой",
"colon": "двоеточие",
"hashtag": "хэштег",
"other": "другой..."
},
"output": {
"row": "сообщение для каждой строки",
"array": "одно сообщение [массив]"
},
"newline": {
"linux": "Linux (\\n)",
"mac": "Mac (\\r)",
"windows": "Windows (\\r\\n)"
},
"hdrout": {
"none": "никогда не отправлять заголовки столбцов",
"all": "всегда отправлять заголовки столбцов",
"once": "отправлять заголовки один раз, до msg.reset"
},
"errors": {
"csv_js": "Этот узел обрабатывает только CSV-строки или объекты js.",
"obj_csv": "Не указан шаблон столбцов для Объект -> CSV.",
"bad_csv": "Неверно сформированный CSV-файл - возможно, выход поврежден."
}
},
"html": {
"label": {
"select": "Селектор",
"output": "Выход",
"in": "в"
},
"output": {
"html": "html-контент элементов",
"text": "только текстовый контент элементов",
"attr": "объект любых атрибутов элементов"
},
"format": {
"single": "одним сообщением [массив]",
"multi": "по сообщению для каждого элемента"
}
},
"json": {
"errors": {
"dropped-object": "Данные не-объектного типа проигнорированы",
"dropped": "Данные неподдерживаемого типа проигнорированы",
"dropped-error": "Не удалось преобразовать данные",
"schema-error": "Ошибка схемы JSON",
"schema-error-compile": "Ошибка схемы JSON: не удалось скомпилировать схему"
},
"label": {
"o2j": "Опции Объект -> JSON",
"pretty": "Форматировать строку JSON",
"action": "Действие",
"property": "Свойство",
"actions": {
"toggle": "Преобразовывать в любую сторону",
"str":"Всегда преобразовывать в строку JSON",
"obj":"Всегда преобразовывать в объект JavaScript"
}
}
},
"yaml": {
"errors": {
"dropped-object": "Данные не-объектного типа проигнорированы",
"dropped": "Данные неподдерживаемого типа проигнорированы",
"dropped-error": "Не удалось преобразовать данные"
}
},
"xml": {
"label": {
"represent": "Имя свойства для атрибутов XML-тега",
"prefix": "Имя свойства для текстового содержимого тега",
"advanced": "Расширенные опции",
"x2o": "Опции XML -> Объект"
},
"errors": {
"xml_js": "Этот узел обрабатывает только строки XML или объекты JS."
}
},
"file": {
"label": {
"filename": "Имя файла",
"action": "Действие",
"addnewline": "Добавлять новую строку (\\n) к данным?",
"createdir": "Создать каталог, если он не существует?",
"outputas": "Выход",
"breakchunks": "Разбить файл на части",
"breaklines": "Разбить на строки",
"filelabel": "файл",
"sendError": "Отправлять сообщение при ошибке (устаревший режим)",
"encoding": "Кодировка",
"deletelabel": "удалить __file__",
"utf8String": "строка UTF8",
"binaryBuffer": "двоичный буфер"
},
"action": {
"append": "добавить в файл",
"overwrite": "перезаписать файл",
"delete": "удалить файл"
},
"output": {
"utf8": "одна ut8-строка",
"buffer": "один объект буфера",
"lines": "сообщение для каждой строчки",
"stream": "поток буферов"
},
"status": {
"wrotefile": "записано в файл: __file__",
"deletedfile": "удален файл: __file__",
"appendedfile": "добавлено в файл: __file__"
},
"encoding": {
"none": "по умолчанию",
"native": "Нативная",
"unicode": "Юникод",
"japanese": "Японская",
"chinese": "Китайская",
"korean": "Корейская",
"taiwan": "Тайвань/Гонконг",
"windows": "Кодовые страницы Windows",
"iso": "Кодовые страницы ISO",
"ibm": "Кодовые страницы IBM",
"mac": "Кодовые страницы Mac",
"koi8": "Кодовые страницы KOI8",
"misc": "Разные"
},
"errors": {
"nofilename": "Не указано имя файла",
"invaliddelete": "Предупреждение: неверное удаление. Пожалуйста, используйте конкретную опцию удаления в диалоге конфигурации.",
"deletefail": "не удалось удалить файл: __error__",
"writefail": "не удалось записать в файл: __error__",
"appendfail": "не удалось добавить в файл: __error__",
"createfail": "не удалось создать файл: __error__"
},
"tip": "Подсказка: имя файла должно быть абсолютным путем, иначе он будет относительно рабочего каталога процесса Node-RED."
},
"split": {
"split": "разделить",
"intro":"Разделить <code>msg.payload</code> в зависимости от типа:",
"object":"<b>Объект</b>",
"objectSend":"Отправлять сообщение для каждой пары ключ/значение",
"strBuff":"<b>Строка</b> / <b>Буфер</b>",
"array":"<b>Массив</b>",
"splitUsing":"С помощью",
"splitLength":"Фикс. длина",
"stream":"Обрабатывать как поток сообщений",
"addname":" Копировать ключ в "
},
"join": {
"join": "соединить",
"mode": {
"mode": "Режим",
"auto": "автоматический",
"merge": "объединение последовательности",
"reduce": "агрегация последовательности",
"custom": "ручной"
},
"combine": "Объединить каждый",
"completeMessage": "полное сообщение",
"create": "чтобы создать",
"type": {
"string": "строку",
"array": "массив",
"buffer": "буфер",
"object": "объект ключей/значений",
"merged": "объединенный объект"
},
"using": "используя значение",
"key": "как ключ",
"joinedUsing": "соединяя с помощью",
"send": "Отправить сообщение:",
"afterCount": "после ряда частей сообщения",
"count": "кол-во",
"subsequent": "и каждое последующее сообщение.",
"afterTimeout": "по истечении времени с 1го сообщения",
"seconds": "сек",
"complete": "после сообщения с установленным свойством <code>msg.complete</code>",
"tip": "В этом режиме предполагается, что этот узел либо связан с узлом <i>split</i>, либо полученные сообщения будут иметь правильно настроенное свойство <code>msg.parts</code>.",
"too-many": "слишком много ожидающих сообщений в узле join",
"merge": {
"topics-label": "Объединенные темы",
"topics": "темы",
"topic": "тема",
"on-change": "Отправлять объединенное сообщение по прибытии новой темы"
},
"reduce": {
"exp": "Агрегирующее выражение",
"exp-value": "выражение",
"init": "Начальное значение",
"right": "Выполнять в обратном порядке (от последнего к первому)",
"fixup": "Исправляющее выражение"
},
"errors": {
"invalid-expr": "Неверное выражение JSONata: __error__",
"invalid-type": "Невозможно присоединить __error__ к буферу"
}
},
"sort" : {
"sort": "сортировать",
"target" : "Сортировать",
"seq" : "последовательность сообщений",
"key" : "Ключ",
"elem" : "значение элемента",
"order" : "Порядок",
"ascending" : "восходящий",
"descending" : "нисходящий",
"as-number" : "как число",
"invalid-exp" : "Неверное выражение JSONata в узле sort: __message__",
"too-many" : "Слишком много ожидающих сообщений в узле sort",
"clear" : "очистить ожидающее сообщение в узле sort"
},
"batch" : {
"batch": "группировать",
"mode": {
"label" : "Режим",
"num-msgs" : "Группировать по количеству сообщений",
"interval" : "Группировать по интервалу времени",
"concat" : "Объединять последовательности"
},
"count": {
"label" : "Количество сообщений",
"overlap" : "Совпадения",
"count" : "кол-во",
"invalid" : "Неверные количество и совпадения"
},
"interval": {
"label" : "Интервал",
"seconds" : "сек",
"empty" : "отправить пустое сообщение, когда сообщение не приходит"
},
"concat": {
"topics-label": "Темы",
"topic" : "тема"
},
"too-many" : "Слишком много ожидающих сообщений в узле batch",
"unexpected" : "неожиданный режим",
"no-parts" : "в сообщении нет свойства parts"
}
}

View File

@@ -0,0 +1,19 @@
<!--
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/html" data-help-name="tls-config">
<p>Параметры конфигурации для TLS соединений.</p>
</script>

View File

@@ -0,0 +1,26 @@
<!--
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/html" data-help-name="http proxy">
<p>
Параметры конфигурации для HTTP-прокси.
</p>
<h3>Подробности</h3>
<p>
При обращении к хосту, находящемуся в списке игнорируемых хостов, прокси не будет использоваться.
</p>
</script>

View File

@@ -0,0 +1,113 @@
<!--
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/html" data-help-name="mqtt in">
<p>
Подключается к MQTT брокеру и подписывается на сообщения указанной темы.
</p>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">строка | буфер</span></dt>
<dd>строка, если не обнаружено как двоичный буфер.</dd>
<dt>topic <span class="property-type">строка</span></dt>
<dd>тема MQTT, использует / в качестве разделителя иерархии.</dd>
<dt>qos <span class="property-type">число</span> </dt>
<dd>0: приходит не более одного раза, 1: приходит не менее одного раза, 2: приходит только один раз.</dd>
<dt>retain <span class="property-type">логич.тип</span></dt>
<dd>значение true указывает, что сообщение было сохранено и может быть устаревшим.</dd>
</dl>
<h3>Подробности</h3>
<p>
Тема подписки может включать подстановочные знаки MQTT, + для одного уровня, # для нескольких уровней.
</p>
<p>
Для этого узла требуется соединение с брокером MQTT. Это настраивается нажатием на значок карандаша.
</p>
<p>
Несколько MQTT узлов (in или out) могут совместно использовать одно и то же соединение с брокером, если это необходимо.
</p>
</script>
<script type="text/html" data-help-name="mqtt out">
<p>
Подключается к MQTT брокеру и публикует сообщения.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">строка | буфер</span></dt>
<dd>данные для публикации. Если это свойство не установлено, сообщение не будет отправлено. Чтобы отправить пустое сообщение, установите для этого свойства пустую строку.</dd>
<dt class="optional">topic <span class="property-type">строка</span></dt>
<dd>тема MQTT для публикации.</dd>
<dt class="optional">qos <span class="property-type">number</span></dt>
<dd>0: приходит не более одного раза, 1: приходит не менее одного раза, 2: приходит только один раз. По умолчанию 0.</dd>
<dt class="optional">retain <span class="property-type">boolean</span></dt>
<dd>установите значение true, чтобы сохранить сообщение в брокере. По умолчанию false.</dd>
</dl>
<h3>Подробности</h3>
<p>
Свойство <code>msg.payload</code> используется в качестве данных опубликованного сообщения. Если оно содержит объект, то он будет преобразован в строку JSON перед отправкой. Если оно содержит двоичный буфер, сообщение будет опубликовано как есть.
</p>
<p>
Используемая тема может быть настроена в узле или, если оставить ее пустой, может быть установлена с помощью <code>msg.topic</code>.
</p>
<p>
Аналогично, значения QoS и сохранения могут быть сконфигурированы в узле или, если они оставлены пустыми, установлены с помощью <code>msg.qos</code> и <code>msg.retain</code> соответственно. Чтобы удалить ранее сохраненную тему из брокера, отправьте пустое сообщение в эту тему с установленным флагом сохранения.
</p>
<p>
Для этого узла требуется соединение с брокером MQTT. Это настраивается нажатием на значок карандаша.
</p>
<p>
Несколько узлов MQTT (in или out) могут совместно использовать одно и то же соединение с брокером, если это необходимо.
</p>
</script>
<script type="text/html" data-help-name="mqtt-broker">
<p>
Конфигурация для подключения к MQTT брокеру.
</p>
<p>
Эта конфигурация создаст одно соединение с посредником, которое затем может быть повторно использовано узлами <code>MQTT In</code> и <code>MQTT Out</code>.
</p>
<p>
Узел сгенерирует случайный идентификатор клиента, если он не задан, а узел настроен на использование соединения с чистым сеансом. Если идентификатор клиента установлен, он должен быть уникальным для брокера, к которому вы подключаетесь.
</p>
<h4>Birth сообщение</h4>
<p>
Это сообщение будет опубликовано в настроенной теме при каждом установлении соединения.
</p>
<h4>Close сообщение</h4>
<p>
Это сообщение будет опубликовано в настроенной теме перед тем, как соединение будет закрыто обычным образом, либо путем повторного развертывания узла, либо остановкой.
</p>
<h4>Will сообщение</h4>
<p>
Это сообщение, которое будет опубликовано брокером в случае, если узел неожиданно потеряет соединение.
</p>
<h4>WebSockets</h4>
<p>
Узел может быть настроен на использование WebSocket соединения. Для этого в поле Сервер должен быть указан полный URI для соединения. Например:
</p>
<pre>ws://example.com:4000/mqtt</pre>
</script>

View File

@@ -0,0 +1,107 @@
<!--
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/html" data-help-name="http in">
<p>
Создает конечную точку HTTP для веб-службы.
</p>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload</dt>
<dd>Для GET-запроса содержит объект с любыми параметрами строки запроса. В противном случае содержит тело HTTP-запроса.</dd>
<dt>req<span class="property-type">объект</span></dt>
<dd>Объект HTTP-запроса. Этот объект содержит несколько свойств, которые предоставляют информацию о запросе.
<ul>
<li><code>body</code> - тело входящего запроса. Формат будет зависеть от запроса.</li>
<li><code>headers</code> - объект, содержащий заголовки HTTP-запроса.</li>
<li><code>query</code> - объект, содержащий любые параметры строки запроса.</li>
<li><code>params</code> - объект, содержащий любые параметры маршрута.</li>
<li><code>cookies</code> - объект, содержащий куки запроса.</li>
<li><code>files</code> - если включено в узле, объект, содержащий любые файлы, загруженные как часть POST-запроса.</li>
</ul>
</dd>
<dt>res<span class="property-type">объект</span></dt>
<dd>Объект ответа HTTP. Это свойство не должно использоваться напрямую. Для ответа на входящий HTTP запрос используется узел ответа <code>HTTP Response</code>. Это свойство должно оставаться в сообщении вплоть до передачи узлу ответа.</dd>
</dl>
<h3>Подробности</h3>
<p>
По настроенному пути узел будет принимать запросы определенного типа. Путь может быть указан конкретно, например <code>/user</code>, или включать именованные параметры, которые принимают любое значение, например <code>/user/:name</code>. Когда используются именованные параметры, их фактическое значение в запросе будет доступно в <code>msg.req.params</code>.
</p>
<p>
Для запросов, которые содержат тело, такие как POST или PUT, содержимое запроса доступно в <code>msg.payload</code>.
</p>
<p>
Если тип содержимого запроса может быть определен, тело будет преобразовано в любой подходящий тип. Например, <code>application/json</code> будет преобразован в объект JavaScript.
</p>
<p>
<b>Примечание:</b> этот узел не отправляет никакого ответа на запрос. Поток должен включать узел ответа HTTP Response для завершения запроса.
</p>
</script>
<script type="text/html" data-help-name="http response">
<p>
Отправляет ответ на запрос, полученный от узла HTTP Input.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">строка</span></dt>
<dd>Тело ответа.</dd>
<dt class="optional">statusCode <span class="property-type">число</span></dt>
<dd>Если установлено, то используется как код состояния ответа. По умолчанию: 200.</dd>
<dt class="optional">headers <span class="property-type">объект</span></dt>
<dd>Если установлено, предоставляет заголовки HTTP для включения в ответ.</dd>
<dt class="optional">cookies <span class="property-type">объект</span></dt>
<dd>Если установлено, может использоваться для записи или удаления куков.</dd>
</dl>
<h3>Подробности</h3>
<p>
Свойства <code>statusCode</code> и <code>headers</code> также могут быть установлены внутри самого узла, настройками 'код состояния' и 'заголовки' соответственно. Если свойство установлено в узле, оно не может быть переопределено соответствующим свойством сообщения.
</p>
<h4>Обработка куков</h4>
<p>
Свойство <code>cookies</code> должно быть объектом пар имя/значение. Значением может быть либо строка для установки значения куки с параметрами по умолчанию, либо это может быть объект параметров.
</p>
<p>
В следующем примере устанавливаются два куки - один с именем <code>name</code> и значением <code>nick</code>, другой с именем <code>session</code> и значением <code>1234</code> и сроком действия в 15 минут.
</p>
<pre>
msg.cookies = {
name: 'nick',
session: {
value: '1234',
maxAge: 900000
}
}</pre>
<p>
Допустимые параметры включают в себя:
</p>
<ul>
<li><code>domain</code> - (Строка) доменное имя для куки</li>
<li><code>expires</code> - (Дата) срок годности по Гринвичу. Если не указан или установлен в 0, создает сессионный куки</li>
<li><code>maxAge</code> - (Строка) дата истечения срока действия относительно текущего времени в миллисекундах</li>
<li><code>path</code> - (Строка) путь для куки. По умолчанию /</li>
<li><code>value</code> - (Строка) значение, используемое для куки</li>
</ul>
<p>
Чтобы удалить куки, установите для его <code>value</code> значение <code>null</code>.
</p>
</script>

View File

@@ -0,0 +1,106 @@
<!--
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/html" data-help-name="http request">
<p>
Отправляет HTTP-запрос и возвращает ответ.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">url <span class="property-type">строка</span></dt>
<dd>Если 'URL' не установлен в узле, это необязательное свойство устанавливает URL запроса.</dd>
<dt class="optional">method <span class="property-type">строка</span></dt>
<dd>Если 'метод' не установлен в узле, это необязательное свойство устанавливает HTTP-метод запроса. Должно быть <code>GET</code>, <code>PUT</code>, <code>POST</code>, <code>PATCH</code> или <code>DELETE</code>.</dd>
<dt class="optional">headers <span class="property-type">объект</span></dt>
<dd>Устанавливает заголовки HTTP запроса.</dd>
<dt class="optional">cookies <span class="property-type">объект</span></dt>
<dd>Если установлено, может использоваться для отправки куки с запросом.</dd>
<dt class="optional">payload</dt>
<dd>Отправляется как тело запроса.</dd>
<dt class="optional">rejectUnauthorized</dt>
<dd>Если установлено значение <code>false</code>, разрешает отправлять запросы на сайты https, которые используют самозаверенные сертификаты.</dd>
<dt class="optional">followRedirects</dt>
<dd>Если установлено значение <code>false</code>, запрещает переадресацию (HTTP 301). По умолчанию <code>true</code>.</dd>
<dt class="optional">requestTimeout</dt>
<dd>Если задано положительное число миллисекунд, будет переопределен глобально заданный параметр <code>httpRequestTimeout</code>.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">строка | объект | буфер</span></dt>
<dd>Тело ответа. Узел можно настроить так, чтобы он возвращал тело в виде строки, пытался проанализировать его как строку JSON или оставлял его в виде двоичного буфера.</dd>
<dt>statusCode <span class="property-type">число</span></dt>
<dd>Код статуса ответа или код ошибки, если запрос не может быть выполнен.</dd>
<dt>headers <span class="property-type">объект</span></dt>
<dd>Объект, содержащий заголовки ответа.</dd>
<dt>responseUrl <span class="property-type">строка</span></dt>
<dd>Если при обработке запроса произошли перенаправления, это свойство является окончательным перенаправленным URL-адресом. В противном случае, URL исходного запроса.</dd>
<dt>responseCookies <span class="property-type">объект</span></dt>
<dd>Если ответ содержит куки, это свойство является объектом пар имя/значение для каждого из них.</dd>
<dt>redirectList <span class="property-type">массив</span></dt>
<dd>Если запрос был перенаправлен один или несколько раз, накопленная информация будет добавлена в это свойство. `location` - это следующий пункт назначения перенаправления. `cookies` - это куки, возвращаемые из источника перенаправления.</dd>
</dl>
<h3>Подробности</h3>
<p>
При настройке внутри узла свойство URL может содержать <a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache</a>-теги. Это позволяет построить URL-адрес, используя значения входящего сообщения. Например, если для URL-адреса задано значение <code>example.com/{{{topic}}}</code>, то автоматически будет вставлено значение <code>msg.topic</code>. Использование {{{...}}} предотвращает HTML-кодирование таких символов, как / & и т.д.
</p>
<p>
Узел может также автоматически кодировать <code>msg.payload</code> как параметры для GET-запроса. В этом случае <code>msg.payload</code> должен быть объектом.
</p>
<p>
<b>Примечание</b>. При работе через прокси-сервер следует либо установить стандартную переменную среды <code>http_proxy=...</code> и перезапустить Node-RED, либо использовать конфигурацию прокси-сервера. Если была установлена конфигурация прокси, то она имеет приоритет над переменной среды.
</p>
<h4>Использование нескольких узлов HTTP-запросов</h4>
<p>
Чтобы использовать несколько таких узлов в одном потоке, нужно позаботиться о свойстве <code>msg.headers</code>. Первый узел установит это свойство с заголовками ответа. Затем следующий узел будет использовать эти заголовки для своего запроса - обычно это неправильный подход. Если свойство <code>msg.headers</code> остается неизменным между узлами, оно будет проигнорировано вторым узлом. Чтобы установить свои заголовки, сначала необходимо удалить <code>msg.headers</code> или сбросить это свойство до пустого объекта: <code>{}</code>.
</p>
<h4>Обработка куки</h4>
<p>
Свойство <code>cookies</code>, передаваемое узлу, должно быть объектом из пар имя/значение. Значением может быть либо строка для установки значения куки, либо это может быть объект с единственным свойством <code>value</code>.
</p>
<p>
Все куки, возвращаемые запросом, передаются обратно в свойстве <code>responseCookies</code>.
</p>
<h4>Обработка типов контента</h4>
<p>
Если <code>msg.payload</code> является объектом, узел автоматически установит тип содержимого запроса в <code>application/json</code> и закодирует тело соответствующим образом.
</p>
<p>
Чтобы закодировать запрос как данные формы, для <code>msg.headers["content-type"]</code> должно быть установлено <code>application/x-www-form-urlencoded</code>.
</p>
<h4>Загрузка файла</h4>
<p>
Чтобы выполнить загрузку файла, для <code>msg.headers["content-type"]</code> должно быть установлено значение <code>multipart/form-data</code>, а <code>msg.payload</code> переданный на узел должен быть объектом со следующей структурой:
</p>
<pre><code>{
"КЛЮЧ": {
"value": СОДЕРЖИМОЕАЙЛА,
"options": {
"filename": МЯ_ФАЙЛА"
}
}
}</code></pre>
<p>
На местах <code>КЛЮЧ</code>, <code>СОДЕРЖИМОЕ_ФАЙЛА</code> и <code>ИМЯ_ФАЙЛА</code> должны быть установлены соответствующие значения.
</p>
</script>

View File

@@ -0,0 +1,52 @@
<!--
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/html" data-help-name="websocket in">
<p>
Входящий узел WebSocket.
</p>
<p>
По умолчанию данные, полученные из WebSocket, будут в <code>msg.payload</code>. Сокет можно настроить так, чтобы он ожидал правильно сформированную строку JSON. В этом случае он будет анализировать JSON и отправлять полученный объект как полное сообщение.
</p>
</script>
<script type="text/html" data-help-name="websocket out">
<p>
Исходящий узел WebSocket.
</p>
<p>
По умолчанию <code>msg.payload</code> будет отправлено через WebSocket. Сокет может быть сконфигурирован для кодирования всего объекта <code>msg</code> в виде строки JSON и отправки его через WebSocket.
</p>
<p>
Если сообщение, поступающее на этот узел, было начато в потоке узлом WebSocket In, сообщение будет отправлено обратно клиенту, который запустил поток. В противном случае сообщение будет передано всем подключенным клиентам.
</p>
<p>
Если Вы хотите передать сообщение, которое началось с узла WebSocket In, всем подключенным клиентам, тогда вам нужно удалить свойство <code>msg._session</code> перед тем как передавать его этому узлу.
</p>
</script>
<script type="text/html" data-help-name="websocket-listener">
<p>
Этот узел конфигурации создает конечную точку WebSocket-сервера, используя указанный путь.
</p>
</script>
<script type="text/html" data-help-name="websocket-client">
<p>
Этот узел конфигурации соединяет WebSocket-клиент с указанным URL-адресом.
</p>
</script>

View File

@@ -0,0 +1,57 @@
<!--
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/html" data-help-name="tcp in">
<p>
Предоставляет выбор из нескольких входящих TCP-узлов. Можно либо подключаться к удаленному TCP-порту, либо принимать входящие подключения.
</p>
<p>
<b>Примечание.</b> В некоторых системах вам могут потребоваться права root или администратора для доступа к портам ниже 1024.
</p>
</script>
<script type="text/html" data-help-name="tcp out">
<p>
Предоставляет выбор из нескольких исходящих TCP-узлов. Может подключаться к удаленному TCP-порту, принимать входящие подключения или отвечать на сообщения, полученные от узла TCP In.
</p>
<p>
Отправляются только данные <code>msg.payload</code>.
</p>
<p>
Если <code>msg.payload</code> является строкой, содержащей Base64-кодировку двоичных данных, опция Base64-декодирования приведет к ее преобразованию обратно в двоичный файл перед отправкой.
</p>
<p>
Если <code>msg._session</code> отсутствует, данные отправляется <b>всем</b> подключенным клиентам.
</p>
<p>
<b>Примечание.</b> В некоторых системах вам могут потребоваться права root или администратора для доступа к портам ниже 1024.
</p>
</script>
<script type="text/html" data-help-name="tcp request">
<p>
Узел TCP-запроса - отправляет <code>msg.payload</code> на tcp-порт сервера и ожидает ответа.
</p>
<p>
Подключается, отправляет &quot;запрос&quot; и читает &quot;ответ&quot;. Он может либо подсчитать количество возвращенных символов в фиксированный буфер, сопоставить указанный символ перед возвратом, дождаться фиксированного времени ожидания от первого ответа и затем вернуться, сидеть и дожидаться данных, или отправить, а затем немедленно закрыть соединение, не дожидаясь ответа.
</p>
<p>
Ответ будет возвращен в <code>msg.payload</code> в виде буфера, поэтому вам может понадобиться применить к нему .toString(), если нужно преобразование в строку.
</p>
<p>
Если вы оставите tcp-хост или порт пустыми, они должны быть установлены с помощью свойств <code>msg.host</code> и <code>msg.port</code> в каждом сообщении, отправляемом узлу.
</p>
</script>

View File

@@ -0,0 +1,42 @@
<!--
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/html" data-help-name="udp in">
<p>
Входящий UDP-узел, который создает <code>msg.payload</code>, содержащий буфер, строку или base64-строку. Поддерживает многоадресную рассылку.
</p>
<p>
Он также предоставляет <code>msg.ip</code> и <code>msg.port</code> для IP-адреса и порта, с которого было получено сообщение.
</p>
<p>
<b>Примечание</b>. В некоторых системах вам могут потребоваться права root или администратора для доступа к портам ниже 1024 и/или широковещательной рассылки.
</p>
</script>
<script type="text/html" data-help-name="udp out">
<p>
Этот узел отправляет <code>msg.payload</code> на назначенный UDP-хост и порт. Поддерживает многоадресную рассылку.
</p>
<p>
Вы также можете использовать <code>msg.ip</code> и <code>msg.port</code> для установки значений пункта назначения, но статически настроенные значения имеют приоритет.
</p>
<p>
Если Вы выберете широковещательную рассылку, то либо задайте в качестве адреса локальный широковещательный IP-адрес, либо попробуйте 255.255.255.255, который является глобальным широковещательным адресом.
</p>
<p>
<b>Примечание</b>. В некоторых системах вам могут потребоваться права root или администратора для доступа к портам ниже 1024 и/или широковещательной рассылки.
</p>
</script>

View File

@@ -0,0 +1,72 @@
<!--
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/html" data-help-name="csv">
<p>
Выполняет преобразования между строкой в CSV формате и ее представлением в JavaScript-объекте, в любом направлении.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | массив | строка</span></dt>
<dd>JavaScript объект, массив или CSV-строка.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | массив | строка</span></dt>
<dd>
<ul>
<li>Если на входе значение строкового типа, узел попытается проанализировать его как CSV и создает объект JavaScript из пар ключ/значение для каждой строки. Затем узел либо отправит сообщение для каждой строки или одно сообщение, содержащее массив объектов.</li>
<li>Если на входе JavaScript объект, узел попробует построить CSV-строку.</li>
<li>Если на входе массив простых значений, узел построит однострочную CSV-строку.</li>
<li>Если на входе массив массивов или массив объектов, создается многострочная CSV-строка.</li>
</ul>
</dd>
</dl>
<h3>Подробности</h3>
<p>
Шаблон столбцов может содержать упорядоченный список имен столбцов. При преобразовании CSV в объект имена столбцов будут использоваться в качестве имен свойств. Кроме того, имена столбцов могут быть взяты из первой строки CSV.
</p>
<p>
При преобразовании в CSV шаблон столбцов используется для определения того, какие свойства извлекать из объекта и в каком порядке.
</p>
<p>
Если шаблон пуст, то узел может использовать простой список свойств, разделенных запятыми, предоставленных в <code>msg.columns</code>, чтобы определить, что извлечь. Если его нет, то все свойства объекта выводятся в том порядке, в котором они были найдены в первой строке.
</p>
<p>
Если входные данные являются массивом, то шаблон столбцов используется только для необязательного генерирования строки с заголовками столбцов.
</p>
<p>
Если выбрана опция 'разбирать числовые значения', строковые числовые значения будут возвращаться в виде чисел. К примеру, среднее значение в CSV-строке '1,"1,5",2'.
</p>
<p>
Если выбрана опция 'включать пустые строковые значения', пустые строки будут возвращениы в результате. К примеру, среднее значение в CSV-строке '"1","",3'.
</p>
<p>
Если выбрана опция 'включить null-значения', null-значения будут возвращениы в результате. К примеру, среднее значение в CSV-строке '"1",,3'.
</p>
<p>
Узел может принимать входные данные, состоящие из нескольких частей, при условии, что свойство <code>parts</code> установлено правильно, например, из узла file-in или узла split.
</p>
<p>
При выводе нескольких сообщений они будут иметь свойство <code>parts</code> и формировать полную последовательность сообщений.
</p>
<p>
<b>Примечание.</b> В шаблоне столбцов должна использоваться запятая для разделения - даже если для данных выбран другой разделитель.
</p>
</script>

View File

@@ -0,0 +1,40 @@
<!--
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/html" data-help-name="html">
<p>
Извлекает элементы из HTML-документа, хранящегося в <code>msg.payload</code>, с помощью CSS-селектора.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">строка</span></dt>
<dd>HTML-строка, из которой извлекать элементы.</dd>
<dt class="optional">select <span class="property-type">строка</span></dt>
<dd>если селектор не настроен на панели редактирования узла, то он может быть установлен как свойство msg.</dd>
</dl>
<h3>Выход</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">массив | строка</span></dt>
<dd>Результатом может быть либо одно сообщение, в котором payload содержит массив найденных элементов, либо несколько сообщений, каждое из которых содержит найденный элемент. Если отправлено несколько сообщений, у них также будет установлен <code>parts</code>.</dd>
</dl>
<h3>Подробности</h3>
<p>
Этот узел поддерживает комбинацию селекторов CSS и jQuery. См. <a href="https://github.com/fb55/CSSselect#user-content-supported-selectors" target="_blank">документацию css-select</a> для получения дополнительной информации о поддерживаемом синтаксисе.
</p>
</script>

View 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.
-->
<script type="text/html" data-help-name="json">
<p>
Выполняет преобразования между строкой в JSON формате и ее представлением в JavaScript-объекте, в любом направлении.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка</span></dt>
<dd>JavaScript объект или JSON-строка.</dd>
<dt>schema<span class="property-type">объект</span></dt>
<dd>Необязательный объект JSON-схемы для проверки данных. Свойство будет удалено перед отправкой <code>msg</code> следующему узлу.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка</span></dt>
<dd>
<ul>
<li>Если вход является JSON-строкой, узел пытается проанализировать ее как JavaScript объект.</li>
<li>Если вход является JavaScript объектом, узел создает JSON-строку. Строка может быть при желании отформатирована.</li>
</ul>
</dd>
<dt>schemaError<span class="property-type">массив</span></dt>
<dd>Если проверка JSON-схемы завершится неудачно, узлом catch можно получить свойство <code>schemaError</code>, содержащее массив ошибок.</dd>
</dl>
<h3>Подробности</h3>
<p>
По умолчанию узел работает с <code>msg.payload</code>, но его можно настроить для преобразования любого свойства сообщения.
</p>
<p>
Узел также может быть сконфигурирован для обеспечения конкретной кодировки вместо переключения между ними. Это можно использовать, например, при работе с узлом <code>HTTP In</code>, чтобы гарантировать, что данные payload всегда будут являться объектом, даже если входящий запрос неправильно установил свой тип содержимого для узла HTTP In, чтобы выполнить преобразование.
</p>
<p>
Если узел настроен так, чтобы свойство кодировалось как строка, и он получает строку, дальнейшие проверки этого свойства выполняться не будут. Он не будет проверять, является ли строка допустимым JSON, и не будет переформатировать ее, если выбрана опция форматирования.
</p>
<p>
Подробнее о JSON-схеме Вы можете узнать в спецификации <a href="http://json-schema.org/latest/json-schema-validation.html">здесь</a>.
</p>
</script>

View File

@@ -0,0 +1,60 @@
<!--
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/html" data-help-name="xml">
<p>
Выполняет преобразования между строкой в XML формате и ее представлением в JavaScript-объекте, в любом направлении.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка</span></dt>
<dd>JavaScript объект или XML-строка.</dd>
<dt class="optional">options <span class="property-type">объект</span></dt>
<dd>Это необязательное свойство может использоваться для передачи любых параметров, поддерживаемых библиотекой, которая используется для преобразования в/из XML. См. <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">документацию xml2js</a> для получения дополнительной информации.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка</span></dt>
<dd>
<ul>
<li>Если на входе значение строкового типа, узел пытается проанализировать его как XML и создает объект JavaScript.</li>
<li>Если на входе JavaScript объект, узел пытается построить XML-строку.</li>
</ul>
</dd>
</dl>
<h3>Подробности</h3>
<p>
При преобразовании между XML и объектом любые XML-атрибуты по умолчанию добавляются как свойство с именем <code>$</code>. Любое текстовое содержимое добавляется как свойство с именем <code>_</code>. Эти имена свойств могут быть указаны в конфигурации узла.
</p>
<p>
Например, следующий XML:
</p>
<pre>&lt;p class="tag"&gt;Hello World&lt;/p&gt;</pre>
<p>
будет преобразован в:
</p>
<pre>{
"p": {
"$": {
"class": "tag"
},
"_": "Hello World"
}
}</pre>
</script>

View File

@@ -0,0 +1,38 @@
<!--
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/html" data-help-name="yaml">
<p>
Выполняет преобразования между строкой в YAML формате и ее представлением в JavaScript-объекте, в любом направлении.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка</span></dt>
<dd>JavaScript объект или YAML-строка.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка</span></dt>
<dd>
<ul>
<li>Если на входе YAML-строка, узел пытается проанализировать ее как JavaScript объект.</li>
<li>Если на входе JavaScript объект, узел создает YAML-строку.</li>
</ul>
</dd>
</dl>
</script>

View File

@@ -0,0 +1,175 @@
<!--
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/html" data-help-name="split">
<p>
Разбивает сообщение на последовательность сообщений.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">объект | строка | массив | буфер</span></dt>
<dd>Поведение узла определяется типом <code>msg.payload</code>:
<ul>
<li><b>строка</b>/<b>буфер</b> - сообщение разделяется с помощью указанного символа (по умолчанию: <code>\n</code>), последовательности буфера или по фиксированной длине.</li>
<li><b>массив</b> - сообщение разбивается на отдельные элементы массива или массивы фиксированной длины.</li>
<li><b>объект</b> - сообщение отправляется для каждой пары ключ/значение объекта.</li>
</ul>
</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>parts<span class="property-type">объект</span></dt>
<dd>Это свойство содержит информацию о том, как сообщение было отделено от исходного сообщения. При передаче на узел <b>join</b> последовательность может быть собрана обратно в одно сообщение. Объект содержит следующие свойства:
<ul>
<li><code>id</code> - идентификатор группы сообщений</li>
<li><code>index</code> - позиция в группе</li>
<li><code>count</code> - если известно, общее количество сообщений в группе. Смотрите 'потоковый режим' ниже.</li>
<li><code>type</code> - тип сообщения: строка = string; массив = array; объект = object; буфер = buffer</li>
<li><code>ch</code> - для строки или буфера данные, использованные для разделения сообщения, в виде строки или массива байтов</li>
<li><code>key</code> - для объекта - ключ свойства, из которого было создано это сообщение. Узел также может быть сконфигурирован для копирования этого значения в другие свойства сообщения, такие как <code>msg.topic</code>.</li>
<li><code>len</code> - длина каждого сообщения при разделении с использованием значения фиксированной длины</li>
</ul>
</dd>
</dl>
<h3>Подробности</h3>
<p>
Этот узел облегчает создание потока, который выполняет общие действия над последовательностью сообщений, перед тем как с помощью узла <b>join</b> объединить последовательность обратно в одно сообщение.
</p>
<p>
Он использует свойство <code>msg.parts</code> для отслеживания отдельных частей последовательности.
</p>
<h4>Потоковый режим</h4>
<p>
Узел также может использоваться для переформатирования потока сообщений. Например, последовательное устройство, которое отправляет завершенные новой строкой команды, может доставлять одно сообщение с частичной командой в конце. В 'потоковом режиме' этот узел будет разбивать сообщение и отправлять каждый завершенный сегмент. Если в конце есть частичный сегмент, узел удержит его и добавит к следующему полученному сообщению.
</p>
<p>
При работе в этом режиме узел не будет устанавливать свойство <code>msg.parts.count</code>, так как он не знает, сколько сообщений ожидать в потоке. Это означает, что его нельзя использовать вместе с узлом <b>join</b> в его автоматическом режиме.
</p>
</script>
<script type="text/html" data-help-name="join">
<p>
Объединяет последовательности сообщений в одно сообщение.
</p>
<p>
Доступны три режима:
</p>
<dl>
<dt>автоматический</dt>
<dd>При использовании с узлом <b>split</b> он автоматически объединит сообщения, чтобы восстановить структуру сообщения, которая была до разделения.</dd>
<dt>ручной</dt>
<dd>Объединяет последовательности сообщений различными способами.</dd>
<dt>агрегация последовательности</dt>
<dd>Применяет JSONata-выражение ко всем сообщениям в последовательности, чтобы свести его к одному сообщению.</dd>
</dl>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">parts<span class="property-type">объект</span></dt>
<dd>Чтобы автоматически соединить последовательность сообщений, у них всех должно быть установлено это свойство. Узел <b>split</b> генерирует это свойство, но его можно создать вручную. Оно имеет следующие свойства:
<ul>
<li><code>id</code> - идентификатор группы сообщений</li>
<li><code>index</code> - позиция в группе</li>
<li><code>count</code> - общее количество сообщений в группе</li>
<li><code>type</code> - тип сообщения: строка = string; массив = array; объект = object; буфер = buffer</li>
<li><code>ch</code> - для строки или буфера данные, использованные для разделения сообщения, в виде строки или массива байтов</li>
<li><code>key</code> - для объекта - ключ свойства, из которого было создано это сообщение</li>
<li><code>len</code> - длина каждого сообщения при разделении с использованием значения фиксированной длины</li>
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>
Если установлено, узел добавит payload, а затем отправит выходное сообщение в своем текущем состоянии. Если вы не хотите добавлять payload, удалите его из msg.
</dd>
</dl>
<h3>Подробности</h3>
<h4>Автоматический режим</h4>
<p>
В автоматическом режиме используется свойство <code>parts</code> входящих сообщений, чтобы определить способ объединения последовательности. Это позволяет автоматически выполнять обратное действие для узла <b>split</b>.
</p>
<h4>Ручной режим</h4>
<p>
Когда узел настроен на соединение в ручном режиме, он может объединять последовательности сообщений в различные результаты:
</p>
<ul>
<li><b>строка</b> или <b>буфер</b> - создается путем объединения выбранного свойства каждого сообщения с указанными символами соединения или буфером.</li>
<li><b>массив</b> - создается путем добавления каждого выбранного свойства или всего сообщения в выходной массив.</li>
<li><b>объект ключей/значений</b> - создается с использованием свойства каждого сообщения для определения ключа, под которым хранится требуемое значение.</li>
<li><b>слитый объект</b> - создается путем объединения свойства каждого сообщения в один объект.</li>
</ul>
<p>
Другие свойства исходящего сообщения берутся из последнего сообщения, полученного перед отправкой результата.
</p>
<p>
Свойство <i>кол-во</i> может быть установлено для количества сообщений, которое должно быть получено перед генерацией выходного сообщения. Для выходных данных объекта, когда это число достигнуто, узел может быть настроен на отправку сообщения для каждого последующего полученного сообщения.
</p>
<p>
Свойство <i>время (сек)</i> может быть установлено, чтобы инициировать отправку нового сообщения с использованием всего, что было получено до сих пор.
</p>
<p>
Если сообщение получено с установленным свойством <b>msg.complete</b>, выходное сообщение завершается и отправляется. Это сбрасывает любой подсчет частей.
</p>
<p>
Если сообщение получено с установленным свойством <b>msg.reset</b>, частично завершенное сообщение удаляется и не отправляется. Это сбрасывает любой подсчет частей.
</p>
<h4>Режим агрегации последовательности</h4>
<p>
Когда настроено объединение в режиме агрегирования, выражение применяется к каждому сообщению в последовательности, и результат накапливается для создания одного сообщения.
</p>
<dl class="message-properties">
<dt>Начальное значение</dt>
<dd>Начальное значение накопленного значения (<code>$A</code>).</dd>
<dt>Агрегирующее выражение</dt>
<dd>Выражение JSONata, которое вызывается для каждого сообщения в последовательности. Результат передается следующему вызову выражения как накопленное значение. В выражении могут использоваться следующие специальные переменные:
<ul>
<li><code>$A</code>: накопленное значение, </li>
<li><code>$I</code>: индекс сообщения в последовательности, </li>
<li><code>$N</code>: количество сообщений в последовательности.</li>
</ul>
</dd>
<dt>Исправляющее выражение</dt>
<dd>Необязательное выражение JSONata, которое применяется после того, как агрегирующее выражение было применено ко всем сообщениям в последовательности. В выражении могут использоваться следующие специальные переменные:
<ul>
<li><code>$A</code>: накопленное значение, </li>
<li><code>$N</code>: количество сообщений в последовательности.</li>
</ul>
</dd>
<p>
По умолчанию агрегирующее выражение применяется по порядку, от первого до последнего сообщения последовательности. При желании его можно применять в обратном порядке.
</p>
</dl>
<p>
<b>Пример:</b> следующие параметры, при получении последовательности числовых значений, рассчитывают среднее значение:
<ul>
<li><b>Агрегирующее выражение</b>: <code>$A+payload</code></li>
<li><b>Начальное значение</b>: <code>0</code></li>
<li><b>Исправляющее выражение</b>: <code>$A/$N</code></li>
</ul>
</p>
<h4>Хранение сообщений</h4>
<p>
Этот узел будет буферизировать сообщения внутри, чтобы работать между последовательностями. Параметр <code>nodeMessageBufferMaxLength</code> можно использовать для ограничения количества сообщений, которые узел будут буферизовать.
</p>
</script>

View 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.
-->
<script type="text/html" data-help-name="sort">
<p>
Функция, которая сортирует свойство сообщения или последовательность сообщений.
</p>
<p>
Когда узел настроен сортировать свойство сообщения, он сортирует данные массива в указанном свойстве сообщения.
</p>
<p>
Когда узел настроен сортировать последовательность сообщений, он будет переупорядочивать сообщения.
</p>
<p>
Порядок сортировки может быть:
</p>
<ul>
<li><b>восходящий</b>,</li>
<li><b>нисходящий</b>.</li>
</ul>
<p>
Для чисел, числовое упорядочивание можно указать с помощью флажка.
</p>
<p>
Когда выбрана сортировка свойства, ключом сортировки может быть значение элемента или выражение JSONata. Когда выбрана сортировка последовательности сообщений, ключом сортировка может быть свойство сообщения или выражение JSONata.
</p>
<p>
При сортировке последовательности сообщений узел сортировки полагается на полученные сообщения, чтобы установить <code>msg.parts</code>. Узел split генерирует это свойство, но его можно создать вручную. Оно имеет следующие свойства:
</p>
<p>
<ul>
<li><code>id</code> - идентификатор группы сообщений</li>
<li><code>index</code> - позиция в группе</li>
<li><code>count</code> - общее количество сообщений в группе</li>
</ul>
</p>
<p>
<b>Примечание.</b> Этот узел буферизирует сообщения внутри для своей работы. Чтобы предотвратить непредвиденное использование памяти, можно указать максимальное количество хранимых сообщений. По умолчанию количество сообщений не ограничено.
<ul>
<li>Свойство <code>nodeMessageBufferMaxLength</code> устанавливается в <b>settings.js</b>.</li>
</ul>
</p>
</script>

View File

@@ -0,0 +1,45 @@
<!--
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/html" data-help-name="batch">
<p>
Создает последовательности сообщений на основе различных правил.
</p>
<h3>Подробности</h3>
<p>
Существует три режима создания последовательностей сообщений:
</p>
<dl>
<dt>Количество сообщений</dt>
<dd>группирует сообщения в последовательности заданной длины. Параметр <b>совпадения</b> указывает, сколько сообщений в конце одной последовательности следует повторить в начале следующей последовательности.</dd>
<dt>Интервал времени</dt>
<dd>группирует сообщения, поступающие в указанный интервал. Если в течение интервала сообщения не поступают, узел может при желании отправлять пустое сообщение.</dd>
<dt>Объединение последовательностей</dt>
<dd>создает последовательность сообщений путем объединения входящих последовательностей. Каждое сообщение должно иметь свойство <code>msg.topic</code> и свойство <code>msg.parts</code>, определяющие его последовательность. Узел настраивается со списком значений <code>topic</code> для идентификации порядка объединения последовательностей.
</dd>
</dl>
<h4>Хранение сообщений</h4>
<p>
Этот узел будет буферизировать сообщения внутри, чтобы работать с последовательностями. Параметр <code>nodeMessageBufferMaxLength</code> можно использовать для ограничения количества сообщений, которые узел будут буферизовать.
</p>
<p>
Если сообщение получено с установленным свойством <b>msg.reset</b>, буферизованные сообщения удаляются и не отправляются.
</p>
</script>

View File

@@ -0,0 +1,86 @@
<!--
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/html" data-help-name="file">
<p>
Записывает <code>msg.payload</code> в файл, либо добавлением в конец, либо заменой существующего контента. Кроме того, им можно удалять файл.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">строка</span></dt>
<dd>Если не настроено в узле, это необязательное свойство устанавливает имя файла, который будет обновлен.</dd>
</dl>
<h3>Выход</h3>
<p>
По завершении записи входное сообщение отправляется на выходной порт.
</p>
<h3>Подробности</h3>
<p>
Данные каждого сообщения будут добавлены в конец файла, при желании добавляя символ новой строки (\n) между каждым.
</p>
<p>
Если используется <code>msg.filename</code>, файл будет закрыт после каждой записи. Для лучшей производительности используйте фиксированное имя файла.
</p>
<p>
Он может быть настроен на перезапись всего файла, а не на добавление. Например, при записи двоичных данных (типа изображения) в файл, следует использовать эту опцию и отключить опцию добавления новой строки.
</p>
<p>
Кодировка данных, записанных в файл, может быть выбрана в списке кодировок.
</p>
<p>
Кроме того, этот узел может быть настроен на удаление файла.
</p>
</script>
<script type="text/html" data-help-name="file in">
<p>
Читает содержимое файла как строку или двоичный буфер.
</p>
<h3>Принимает</h3>
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">строка</span></dt>
<dd>это свойство устанавливает имя файла для чтения, если оно не задано в настройках узла.</dd>
</dl>
<h3>Выводит</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">строка | буфер</span></dt>
<dd>Содержимое файла в виде строки или двоичного буфера.</dd>
<dt class="optional">filename <span class="property-type">строка</span></dt>
<dd>Если не настроено в узле, это необязательное свойство устанавливает имя файла для чтения.</dd>
</dl>
<h3>Подробности</h3>
<p>
Имя файла должно быть абсолютным путем к файлу, иначе оно будет путем относительно рабочего каталога процесса Node-RED.
</p>
<p>
В Windows может быть необходимо кодировать разделители пути двойной косой чертой, например: <code>\\Users\\myUser</code>.
</p>
<p>
При желании текстовый файл можно разбить на строки, выводя по одному сообщению для каждой строки, или двоичный файл разбить на более мелкие фрагменты буфера - размер блока зависит от операционной системы, но обычно составляет 64 КБ (Linux/Mac) или 41 КБ (Windows).
</p>
<p>
При разбиении на несколько сообщений каждое сообщение будет иметь свойство <code>parts</code>, формирующее полную последовательность сообщений.
</p>
<p>
Кодировка входных данных может быть выбрана из списка кодировок, если выходной формат - строка.
</p>
</script>

View File

@@ -0,0 +1,39 @@
<!--
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/html" data-help-name="watch">
<p>
Наблюдает за изменениями директории или файла.
</p>
<p>
Вы можете ввести список разделенных запятыми директорий и/или файлов. Вам нужно взять в кавычки "..." те из них, в которых есть пробелы.
</p>
<p>
В Windows вы должны использовать двойную обратную косую черту \\ вместо одной в именах директорий.
</p>
<p>
Полное имя фактически измененного файла помещается в <code>msg.payload</code> и <code>msg.filename</code>, а строковая версия списка наблюдения возвращается в <code>msg.topic</code>.
</p>
<p>
<code>msg.file</code> содержит только краткое имя файла, который изменился. <code>msg.type</code> содержит тип измененной единицы, обычно это <i>file</i> для файла или <i>directory</i> для директории, тогда как <code>msg.size</code> содержит размер файла в байтах.
</p>
<p>
В Linux <i>все</i> является файлами, и может быть под наблюдением...
</p>
<p>
<b>Примечание.</b> Наблюдаемые директория или файл должны существовать. Если файл или директория будут удалены, они могут перестать отслеживаться, даже если они затем будут созданы заново.
</p>
</script>

View File

@@ -19,6 +19,8 @@
<h3>输入</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">数值</span></dt>
<dd>设置要应用于消息的延迟(以毫秒为单位)仅当节点配置为允许消息去覆盖设置的的默认延迟间隔时此选项才适用</dd>
<dt class="optional">reset</dt>
<dd>如果收到带有此属性的消息则将清除当前正在进行的任何超时或重复且不会触发任何消息</dd>
</dl>
@@ -27,6 +29,7 @@
<p>该节点可用于在流中创建一个超时 默认情况下当它收到一条消息时它将发送一条带有<code>1</code>250<code>0</code>使Raspberry Pi GPIOLED</p>
<p>可以将发送的每个消息的有效荷载配置为各种值包括不发送任何内容的选项例如将初始消息设置为<i>nothing</i></p>
<p>如果设置为<i>字符串</i>类型,则该节点支持<i>mustache</i>模板语法</p>
<p>如果节点中启用了该选项则可以通过<code> msg.delay </code></p>
<p>如果节点收到具有<code>reset</code><code></code></p>
<p>可以将节点配置为以固定的时间间隔重新发送消息直到被收到的消息重置为止</p>
<p>可选可以将节点配置为将带有<code>msg.topic</code></p>

View File

@@ -321,6 +321,7 @@
"h": "小时"
},
"extend": " 如有新信息,延长延迟",
"override": "使用msg.delay覆盖延迟时间",
"second": " 发送第二条消息到单独的输出",
"label": {
"trigger": "触发",

View File

@@ -19,6 +19,8 @@
<h3>输入</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">数值</span></dt>
<dd>設置要應用於消息的延遲(以毫秒為單位)僅當節點配置為允許消息去覆蓋設置的的默認延遲間隔時此選項才適用</dd>
<dt class="optional">reset</dt>
<dd>如果收到带有此属性的消息则将清除当前正在进行的任何超时或重复且不会触发任何消息</dd>
</dl>
@@ -27,6 +29,7 @@
<p>该节点可用于在流程中创建一个超时 默认情况下当它收到一条消息时它将发送一条带有<code>1</code>250<code>0</code>使Raspberry Pi GPIOLED</p>
<p>可以将发送的每个消息的有效荷载配置为各种值包括不发送任何内容的选项例如将初始消息设置为<i>nothing</i></p>
<p>如果设置为<i>字符串</i>类型,则该节点支持<i>mustache</i>模板语法</p>
<p>如果節點中啟用了該選項則可以通過<code> msg.delay </code></p>
<p>如果节点收到具有<code>reset</code><code></code></p>
<p>可以将节点配置为以固定的时间间隔重新发送消息直到被收到的消息重置为止</p>
<p>可选可以将节点配置为将带有<code>msg.topic</code></p>

View File

@@ -321,6 +321,7 @@
"h": "小時"
},
"extend": " 如有新資訊,延長延遲",
"override": "使用msg.delay覆蓋延遲時間",
"second": " 發送第二條消息到單獨的輸出",
"label": {
"trigger": "觸發",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "1.2.0-beta.1",
"version": "1.2.8",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -15,7 +15,7 @@
}
],
"dependencies": {
"ajv": "6.12.5",
"ajv": "6.12.6",
"body-parser": "1.19.0",
"cheerio": "0.22.0",
"content-type": "1.0.4",
@@ -23,7 +23,7 @@
"cookie": "0.4.1",
"cors": "2.8.5",
"cron": "1.7.2",
"denque": "1.4.1",
"denque": "1.5.0",
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
@@ -31,9 +31,9 @@
"is-utf8": "0.2.1",
"js-yaml": "3.14.0",
"media-typer": "1.1.0",
"mqtt": "4.2.1",
"mqtt": "4.2.6",
"multer": "1.4.2",
"mustache": "4.0.1",
"mustache": "4.1.0",
"on-headers": "1.0.2",
"raw-body": "2.4.1",
"request": "2.88.0",

View File

@@ -35,7 +35,7 @@ var settings;
const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/;
const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/;
const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//;
const localtgzRe = /^\/.+tgz$/;
const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/;
function init(runtime) {
events = runtime.events;
@@ -103,7 +103,7 @@ function installModule(module,version,url) {
installName = url;
} else {
log.warn(log._("server.install.install-failed-url",{name:module,url:url}));
e = new Error("Invalid url");
const e = new Error("Invalid url");
e.code = "invalid_module_url";
reject(e);
return;
@@ -120,7 +120,7 @@ function installModule(module,version,url) {
module = info.name;
} else {
log.warn(log._("server.install.install-failed-name",{name:module}));
e = new Error("Invalid module name");
const e = new Error("Invalid module name");
e.code = "invalid_module_name";
reject(e);
return;
@@ -136,7 +136,7 @@ function installModule(module,version,url) {
}
var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var args = ['install','--no-audit','--no-update-notifier','--no-fund','--save','--save-prefix="~"','--production',installName];
var args = ['install','--no-audit','--no-update-notifier','--no-fund','--save','--save-prefix=~','--production',installName];
log.trace(npmCommand + JSON.stringify(args));
exec.run(npmCommand,args,{
cwd: installDir

View File

@@ -28,17 +28,19 @@ function getFlowsFromPath(path) {
fs.readdir(path,function(err,files) {
var promises = [];
var validFiles = [];
files.forEach(function(file) {
var fullPath = fspath.join(path,file);
var stats = fs.lstatSync(fullPath);
if (stats.isDirectory()) {
validFiles.push(file);
promises.push(getFlowsFromPath(fullPath));
} else if (/\.json$/.test(file)){
validFiles.push(file);
promises.push(Promise.resolve(file.split(".")[0]))
}
})
if (files) {
files.forEach(function(file) {
var fullPath = fspath.join(path,file);
var stats = fs.lstatSync(fullPath);
if (stats.isDirectory()) {
validFiles.push(file);
promises.push(getFlowsFromPath(fullPath));
} else if (/\.json$/.test(file)){
validFiles.push(file);
promises.push(Promise.resolve(file.split(".")[0]))
}
})
}
var i=0;
Promise.all(promises).then(function(results) {
results.forEach(function(r) {

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "1.2.0-beta.1",
"version": "1.2.8",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,10 +16,10 @@
}
],
"dependencies": {
"@node-red/util": "1.2.0-beta.1",
"@node-red/util": "1.2.8",
"semver": "6.3.0",
"tar": "6.0.5",
"uglify-js": "3.11.0",
"uglify-js": "3.12.4",
"when": "3.7.8"
}
}

View File

@@ -38,12 +38,20 @@ function handleCommsEvent(event) {
publish(event.topic,event.data,event.retain);
}
function handleStatusEvent(event) {
var status = {
text: event.status.text,
fill: event.status.fill,
shape: event.status.shape
};
publish("status/"+event.id,status,true);
if (!event.status) {
delete retained["status/"+event.id]
} else if (!event.status.text && !event.status.fill && !event.status.shape) {
if (retained["status/"+event.id]) {
publish("status/"+event.id,{},false);
}
} else {
var status = {
text: event.status.text,
fill: event.status.fill,
shape: event.status.shape
};
publish("status/"+event.id,status,true);
}
}
function handleRuntimeEvent(event) {
runtime.log.trace("runtime event: "+JSON.stringify(event));

View File

@@ -99,6 +99,10 @@ var api = module.exports = {
return new Promise(function(resolve,reject) {
var id = opts.id;
var lang = opts.lang;
if (/[^a-z\-\*]/i.test(opts.lang)) {
reject(new Error("Invalid language: "+opts.lang));
return
}
var result = runtime.nodes.getNodeConfig(id,lang);
if (result) {
runtime.log.audit({event: "nodes.config.get",id:id}, opts.req);
@@ -124,6 +128,10 @@ var api = module.exports = {
getNodeConfigs: function(opts) {
return new Promise(function(resolve,reject) {
runtime.log.audit({event: "nodes.configs.get"}, opts.req);
if (/[^a-z\-\*]/i.test(opts.lang)) {
reject(new Error("Invalid language: "+opts.lang));
return
}
return resolve(runtime.nodes.getNodeConfigs(opts.lang));
});
},
@@ -398,6 +406,10 @@ var api = module.exports = {
var namespace = opts.module;
var lang = opts.lang;
var prevLang = runtime.i18n.i.language;
if (/[^a-z\-\*]/i.test(lang)) {
reject(new Error("Invalid language: "+lang));
return
}
// Trigger a load from disk of the language if it is not the default
runtime.i18n.i.changeLanguage(lang, function(){
var nodeList = runtime.nodes.getNodeList();
@@ -427,6 +439,10 @@ var api = module.exports = {
return new Promise(function(resolve,reject) {
var namespace = opts.module;
var lang = opts.lang;
if (/[^a-z\-\*]/i.test(lang)) {
reject(new Error("Invalid language: "+lang));
return
}
var prevLang = runtime.i18n.i.language;
// Trigger a load from disk of the language if it is not the default
runtime.i18n.i.changeLanguage(lang, function(){

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