Compare commits

...

134 Commits

Author SHA1 Message Date
Dave Conway-Jones
c256e27a83 simplistic detect can't write settings and set readOnly flag 2018-04-06 17:00:34 +01:00
Dave Conway-Jones
3f41036919 add node-red to project with minor server tolerance. 2018-04-06 16:46:54 +01:00
Dave Conway-Jones
95753ce5cd add "add node-red core" button to dependencies panel 2018-04-06 15:32:53 +01:00
Dave Conway-Jones
1906818c87 much simpler to always add start
whether node-red is s deep or not…  as if not it would need to be there
anyway….
2018-04-06 09:06:35 +01:00
Dave Conway-Jones
02765f8aad run by calling node-red script
handles npm start better after both clone and npm pack
2018-04-05 23:24:22 +01:00
Dave Conway-Jones
89f1dedf20 Add .config.json to .gitignore 2018-04-05 23:21:28 +01:00
Dave Conway-Jones
7a8906535e add --credentialSecret -k to command-line options 2018-04-05 14:48:47 +01:00
Dave Conway-Jones
499d22daca Add start script to default project package 2018-04-05 11:30:16 +01:00
Dave Conway-Jones
838c7a5e89 make debug slightly larger to pass WCAG AA rating 2018-04-05 11:25:08 +01:00
Dave Conway-Jones
89bfc90f40 Make core nodes labels more consistent, to close #1673
and make them translateable
2018-03-30 14:31:59 +01:00
Dave Conway-Jones
acad9f57f9 Add "not available" to common messages 2018-03-30 14:03:04 +01:00
Fabien Marchewka
0d08dc410e Prevent Following Redirect (#615) (#1684) 2018-03-29 08:28:44 +01:00
Nick O'Leary
ebb3fb96cd Merge pull request #1670 from node-red-hitachi/subflow-icon-change
Enable user defined icon for subflow
2018-03-27 10:22:20 +01:00
Nick O'Leary
f31f23ff07 Allow template node to be updated more than once
Fixes #1671
2018-03-27 10:14:39 +01:00
Kazuki-Nakanishi
8b0e76dd55 Hide the subflow check logic inside getDefaultNodeIcon function 2018-03-22 14:14:09 +09:00
Dave Conway-Jones
884618adfe remove down carat from typed input with only 1 type 2018-03-20 21:01:10 +00:00
Nick O'Leary
98f7271ac8 Merge pull request #1657 from node-red-hitachi/move-i18n-info-text
move i18n info text of core nodes under nodes/core/locales directory
2018-03-20 20:44:54 +00:00
Dave Conway-Jones
087cd121b8 add debug and trace to function node (#1654) 2018-03-20 20:40:36 +00:00
Kazuki Nakanishi
2d52527fb4 Don't mark a subflow changed when actually modified nothing (#1665) 2018-03-20 20:39:46 +00:00
Kazuki Nakanishi
fe289e62b5 Fix the problem that output labels of switch node sometimes disappear (#1664) 2018-03-20 20:37:29 +00:00
Nick O'Leary
2845475e3f Keep backup of .config.json 2018-03-20 00:04:52 +00:00
Nick O'Leary
b307492487 Add warning if using _credentialSecret 2018-03-20 00:04:52 +00:00
Nick O'Leary
d48284f7ea Remove unused references to settings 2018-03-20 00:04:52 +00:00
Dave Conway-Jones
7e416797e9 make trigger test a bit more robust 2018-03-19 17:33:18 +00:00
Kroderia
5d54ca7477 Chinese translations for core nodes (#1607)
* Fix typo

* Fix and Update some Chinese translations.

* Fix and Add Chinese translations to match all en-US's items
2018-03-17 17:49:17 +00:00
Qi Xiu
b979b4e61a Master chinese3 (#1666)
* Translated jsonata.json to Chinese

* Translated file jsonata.json to Chinese
2018-03-17 17:48:01 +00:00
Kazuki Nakanishi
2527f7984a Translate rpi-gpio node (#1669)
Thanks
2018-03-17 17:46:44 +00:00
Kazuki-Nakanishi
d9350b2362 Enable user defined icon for subflow 2018-03-14 13:51:50 +09:00
Kazuhito Yokoi
bd0b903f1a Fix typo in info messages of file node 2018-03-14 01:19:37 +00:00
Kazuhito Yokoi
f243c0df19 Fix typo in info messages of json node 2018-03-14 01:18:00 +00:00
Kazuhito Yokoi
7482978953 Fix typo in info messages of html node 2018-03-14 01:16:59 +00:00
Kazuhito Yokoi
77966689d4 Fix typo in info messages of csv node 2018-03-14 01:15:36 +00:00
Kazuhito Yokoi
cf43939d65 Fix typo in info messages of split node 2018-03-14 01:11:11 +00:00
Kazuhito Yokoi
391ac4b351 Fix typo in info messages of change node 2018-03-14 01:09:29 +00:00
Kazuhito Yokoi
e1e48aadd9 Fix typo in info messages of switch node 2018-03-14 01:08:10 +00:00
Kazuhito Yokoi
0681f206c4 Fix typo in info messages of udp node 2018-03-14 01:05:38 +00:00
Kazuhito Yokoi
d257c6f3d3 Fix typo in info messages of tcpin node 2018-03-14 01:04:21 +00:00
Kazuhito Yokoi
fa45c82cdc Fix typo in info messages of watch node 2018-03-14 01:01:58 +00:00
Kazuhito Yokoi
e805b58da6 Fix typo in info messages of websocket node 2018-03-14 01:00:13 +00:00
Kazuhito Yokoi
943976d207 Fix typo in info messages of trigger node 2018-03-14 00:49:44 +00:00
Kazuhito Yokoi
3a2e5a6ccd Fix typo in info messages of exec node 2018-03-14 00:47:50 +00:00
Kazuhito Yokoi
35ef036246 Fix typo in info messages of debug node 2018-03-14 00:46:07 +00:00
Kazuhito Yokoi
e09c3bbdd3 Fix typo in info messages of inject node 2018-03-14 00:41:07 +00:00
Nick O'Leary
3b12076d4b Ignore subflow debug nodes when building filter
Fixes #1660

As the editor doesn't know the ids of subflow instance debug nodes
there's no easy way to build a list of them as part of the filter
options. So for now, disable the filter option if we don't know
about the debug node.
2018-03-03 22:41:02 +00:00
Hiroyasu Nishiyama
cfcf78ae28 fix failure of node installation (#1658) 2018-03-03 07:35:17 +00:00
Hiroyasu Nishiyama
341ff9bf5c move i18n info text of core nodes under nodes/core/locales directory 2018-03-03 10:39:11 +09:00
Dave Conway-Jones
4ebb5d099e add trigger reset test for null on 2nd output 2018-03-01 14:00:14 +00:00
Dave Conway-Jones
1e82b66bf0 remove octalbonescript example line from settings as no longer supported 2018-03-01 11:41:53 +00:00
Nick O'Leary
06a5e4273b Move all event emitting into runtime side, not api side 2018-02-28 11:24:12 +00:00
Dave Conway-Jones
e123e7b0b0 Fix pi gpio output of boolean to actually send 1/0
rather than true/false
2018-02-27 23:26:32 +00:00
Nick O'Leary
aeadc40c65 Bump for 0.18.4 2018-02-27 16:41:10 +00:00
Nick O'Leary
7ef418ec52 Ensure sshkey file path is properly escaped on Windows 2018-02-27 13:05:10 +00:00
Nick O'Leary
2ed52820b6 Fix fs/fspath reference 2018-02-27 11:11:02 +00:00
Nick O'Leary
e8fd7484b6 Normalize ssh key paths for Windows file names 2018-02-27 10:58:54 +00:00
Nick O'Leary
ce5242cfe8 Ensure userDir is an absolute path when used with sshkeygen 2018-02-26 23:46:08 +00:00
Nick O'Leary
af947879d8 Merge pull request #1614 from node-red-hitachi/no-tabs
Fix the problem that the last flow tab can be deleted
2018-02-22 19:02:12 -08:00
Kazuki-Nakanishi
3ed112cde6 Changed coding style 2018-02-23 11:48:40 +09:00
Nick O'Leary
99c6a9eccd Merge pull request #1646 from node-red-hitachi/no-defaults-node
Fixed the problems when using a node without defaults
2018-02-22 18:12:41 -08:00
Nick O'Leary
2029f6ea0a Merge pull request #1638 from node-red-hitachi/i18n-info-jp
add Japanese info text of core nodes
2018-02-22 18:01:56 -08:00
Nick O'Leary
e984e1f30f Merge pull request #1616 from node-red-hitachi/fix-i18n-message-lookup
fix message lookup for core nodes in case of i18 locales directory ex…
2018-02-22 17:59:52 -08:00
Kazuki-Nakanishi
f21260370f Fixed the problems when using a node without defaults 2018-02-22 14:10:31 +09:00
Dave Conway-Jones
fdae75c99b ensure trigger gets reset when 2nd output is null
to fix #1644
2018-02-21 21:56:03 +00:00
Nick O'Leary
a0489f2a0d Fix tests for existing file flag in settings 2018-02-21 08:38:52 -08:00
Nick O'Leary
0123eacbdb Merge pull request #1642 from node-red-hitachi/subflow-icon
Disable user defined icon for subflow
2018-02-21 08:24:41 -08:00
Nick O'Leary
53401b6aa7 Fix merging a remote diff 2018-02-20 15:01:45 -08:00
Nick O'Leary
9a5139f452 Detect if there are no existing flows to migrate into a project 2018-02-20 14:30:37 -08:00
Nick O'Leary
2ee0c8c228 Use relative urls when retriving flow history 2018-02-20 14:27:47 -08:00
Kazuki-Nakanishi
c53562cc9c Disable user defined icon for subflow 2018-02-20 15:29:52 +09:00
Nick O'Leary
ec5d7c2e5c Add credentialSecret to clone pane 2018-02-18 17:09:19 +00:00
Nick O'Leary
d6fc258485 Delay clearing inflight when changing credentials key 2018-02-18 16:43:40 +00:00
Nick O'Leary
f953612695 Mark deploy inflight when reverting a file change 2018-02-18 16:30:47 +00:00
Kazuki-Nakanishi
2ab93acca8 Revise the fix for the problem that the last flow tab can be deleted 2018-02-16 11:54:52 +09:00
Nick O'Leary
326c6c496e Handle missing_flow_file error on clone properly 2018-02-15 22:47:07 +00:00
Nick O'Leary
9f7f50664c Remote project from cached list on delete so it can be reused 2018-02-15 22:46:36 +00:00
Nick O'Leary
f6f1436123 getDefaultNodeIcon should handle subflow instance nodes
Fixes #1635
2018-02-15 15:34:15 +00:00
Hiroyasu Nishiyama
c3c519419d merge i18n-info-jp-storage 2018-02-15 22:47:15 +09:00
Hiroyasu Nishiyama
e569a80b72 merge i18n-info-jp-parsers 2018-02-15 22:47:05 +09:00
Hiroyasu Nishiyama
284f437c1a merge i18n-info-jp-logic 2018-02-15 22:46:58 +09:00
Hiroyasu Nishiyama
1fd44a9958 merge i18n-info-jp-io 2018-02-15 22:46:46 +09:00
Hiroyasu Nishiyama
cad34742f6 merge i18n-info-jp-core 2018-02-15 22:46:18 +09:00
Hiroyasu Nishiyama
323359b3c8 merge i18n-info-jp-analysis 2018-02-15 22:46:10 +09:00
Hiroyasu Nishiyama
35db8b45f0 add Japanese info text for io category nodes 2018-02-15 22:39:46 +09:00
Nick O'Leary
50ae815ceb Update changelog 2018-02-14 13:53:55 +00:00
Nick O'Leary
1a4389c90d Fix offset calculation when dragging node from palette 2018-02-14 13:37:24 +00:00
Nick O'Leary
fdaa5ce1da Merge pull request #1624 from node-red/library-extra-element
let library createUi accept elements other than node-input-name
2018-02-14 13:16:39 +00:00
Nick O'Leary
09d9936aed Change remote-diff shortcut and add it to keymap
Fixes #1628
2018-02-14 09:54:07 +00:00
Nick O'Leary
b3f6109b1c Update changelog and bump package 2018-02-13 23:51:16 +00:00
Nick O'Leary
5fb3ffc240 Merge pull request #1627 from node-red-hitachi/fix-batch-concat-mode-msg-modification
fixed message modificcation of concat mode of BATCH node
2018-02-13 23:45:19 +00:00
Nick O'Leary
360db252bb Merge pull request #1626 from node-red-hitachi/fix-typo-in-jp-message-catalog
fix typo in Japanese message catalog
2018-02-13 23:44:48 +00:00
Nick O'Leary
0b6e290271 Merge pull request #1625 from node-red-hitachi/fix-typo-in-info-text
Fix typo in info text
2018-02-13 23:44:35 +00:00
Nick O'Leary
7f0174e6db Merge pull request #1617 from node-red-hitachi/fix-backquote-in-info
Fix backquote in info text
2018-02-13 23:43:56 +00:00
Nick O'Leary
a25dad6c2e Ensure debug tools show for 'complete msg object' 2018-02-13 23:42:22 +00:00
Nick O'Leary
6191a49ed3 Use flow-diff to resolve merge conflicts 2018-02-13 23:09:51 +00:00
Hiroyasu Nishiyama
6252b075bc fixed message modificcation of concat mode of BATCH node 2018-02-13 20:55:03 +09:00
Hiroyasu Nishiyama
7face138fd add Japanese info text for analysis category nodes 2018-02-12 14:04:29 +09:00
Hiroyasu Nishiyama
382b83b093 add Japanese info text for parsers category nodes 2018-02-12 12:24:03 +09:00
Hiroyasu Nishiyama
691687d1bc add Japanese info text for storage category nodes 2018-02-11 23:07:07 +09:00
Hiroyasu Nishiyama
5814b80a72 add Japanese info text for logic category nodes 2018-02-11 20:59:01 +09:00
Hiroyasu Nishiyama
e147fbb1fa add Japanese info text for core category nodes 2018-02-11 20:52:44 +09:00
Hiroyasu Nishiyama
b9e256adfa fix typo in Japanese message catalog 2018-02-11 02:11:29 +09:00
Hiroyasu Nishiyama
3b7bf04e22 fix typo in info text of DELAY node 2018-02-11 02:07:51 +09:00
Hiroyasu Nishiyama
43408a724c fix unmatched tag in info text of BATCH node 2018-02-11 02:06:28 +09:00
Dave Conway-Jones
5fbd5bf9e2 handle other fields in library - by only changing prefix
(rather than whole property  - so ...-name is still the name required)
2018-02-10 16:49:47 +00:00
Dave Conway-Jones
5e87828b29 let library createUi accept elements other than node-input-name 2018-02-10 16:16:49 +00:00
Nick O'Leary
9066cedc29 Better merge-conflict commit button layout 2018-02-09 09:35:47 +00:00
Nick O'Leary
aa1cf0b228 Avoid git fetch when refreshing local status 2018-02-08 23:30:07 +00:00
Nick O'Leary
06a6a4408f Handle allow-unrelated-histories option on pull 2018-02-08 23:21:14 +00:00
Nick O'Leary
d5619d2b9d Fix up merge conflict handling 2018-02-08 22:22:58 +00:00
Nick O'Leary
2f6ac42efe Add comment blocks to GitHub templates to reduce clutter 2018-02-08 14:39:58 +00:00
Hiroyasu Nishiyama
0bba3dd83d merge upstream/master 2018-02-08 23:22:00 +09:00
Hiroyasu Nishiyama
abe60b62e6 change backquote in info text to <code>...</code> 2018-02-08 23:20:53 +09:00
Nick O'Leary
555b7df986 Handle more git 2.1 differences 2018-02-07 13:47:09 +00:00
Nick O'Leary
b3786700e6 Handle changing case of git error messages between versions 2018-02-07 13:10:04 +00:00
Hiroyasu Nishiyama
ce9643d21b fix message lookup for core nodes in case of i18 locales directory exists 2018-02-07 21:59:58 +09:00
Nick O'Leary
4a5cb7f2f5 Ensure commit list has a refs object even if empty 2018-02-07 11:33:07 +00:00
Nick O'Leary
42a7e902e6 Handle host key verification as auth error 2018-02-07 11:32:50 +00:00
Nick O'Leary
aebe080e85 Add support for GIT_SSH on older levels of git 2018-02-07 10:50:32 +00:00
Kazuki-Nakanishi
c316284924 Fix the problem that the last flow tab can be deleted 2018-02-07 14:19:18 +09:00
Nick O'Leary
8d98b228ab Bump 0.18.2 2018-02-06 15:28:43 +00:00
Nick O'Leary
5b4c42ff05 Update changelog 2018-02-06 14:30:31 +00:00
Dave Conway-Jones
a596a4551a undo exec node change (investigate test fail) 2018-02-06 11:42:33 +00:00
Dave Conway-Jones
0968f96982 add a default keepalive to tcp client mode
to address #1469
2018-02-06 11:36:14 +00:00
Dave Conway-Jones
5931e13b9c move node.send in exec and httprequest nodes
just in case
2018-02-06 11:36:13 +00:00
Nick O'Leary
415c768ae4 Filter out %D from git log command for older git versions 2018-02-06 11:00:11 +00:00
Nick O'Leary
b4c8bf21d5 Ensure projects are created as logged in user 2018-02-06 10:38:41 +00:00
Nick O'Leary
5fe5db603d Better error handling/reporting in project creation 2018-02-05 15:59:11 +00:00
Nick O'Leary
9f7dd7f5d4 Add Project Settings menu option 2018-02-05 10:58:09 +00:00
Nick O'Leary
e6d32aab7b Refresh vc sidebar on remote add/remove 2018-02-05 10:10:26 +00:00
Dave Conway-Jones
08bd6d963c Ensure send is last thing trigger does 2018-02-04 21:25:25 +00:00
Dave Conway-Jones
ff05fb14a6 ensure trigger doesn't set two simultaneous timeouts 2018-02-04 20:17:43 +00:00
Nick O'Leary
22d942b705 Fix auth prompt for ssh repos 2018-02-03 23:44:19 +00:00
Nick O'Leary
0526372f28 Bump rbe dependency 2018-02-03 20:48:43 +00:00
Dave Conway-Jones
f99051906a add missing property select var to HTML node 2018-02-02 23:40:01 +00:00
Nick O'Leary
d1f7fd8bfd Prevent http git urls from including username/pword 2018-02-02 22:43:29 +00:00
116 changed files with 3246 additions and 875 deletions

View File

@@ -1,3 +1,4 @@
<!--
## Before you hit that Submit button....
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
@@ -14,6 +15,7 @@ That way the whole Node-RED user community can help, rather than rely on the cor
## So you have a real issue to raise...
To help us understand the issue, please fill-in as much of the following information as you can:
-->
### What are the steps to reproduce?

View File

@@ -1,3 +1,4 @@
<!--
## Before you hit that Submit button....
Please read our [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
@@ -6,23 +7,26 @@ before submitting a pull-request.
## Types of changes
What types of changes does your code introduce?
_Put an `x` in the boxes that apply_
Put an `x` in the boxes that apply
-->
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
<!--
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it **may well get rejected** if it hasn't been discussed on
the [mailing list](https://groups.google.com/forum/#!forum/node-red) or
[slack team](https://nodered.org/slack) first.
-->
## Proposed changes
Describe the nature of this change. What problem does it address?
<!-- Describe the nature of this change. What problem does it address? -->
## Checklist
_Put an `x` in the boxes that apply_
<!-- Put an `x` in the boxes that apply -->
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
- [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team.

View File

@@ -1,3 +1,87 @@
#### 0.18.4: Maintenance Release
Projects
- Ensure sshkey file path is properly escaped on Windows
- Normalize ssh key paths for Windows file names
- Ensure userDir is an absolute path when used with sshkeygen
- Detect if there are no existing flows to migrate into a project
- Use relative urls when retriving flow history
- Add credentialSecret to clone pane
- Delay clearing inflight when changing credentials key
- Mark deploy inflight when reverting a file change
- Handle missing_flow_file error on clone properly
- Remote project from cached list on delete so it can be reused
- Fix tests for existing file flag in settings
Editor Fixes
- Fix merging a remote diff
- Fixed the problems when using a node without defaults
- Disable user defined icon for subflow
- getDefaultNodeIcon should handle subflow instance nodes Fixes #1635
- Add Japanese info text for core nodes
- Fix message lookup for core nodes in case of i18 locales directory exists
- Prevent the last tab from being deleted
Node Fixes
- Ensure trigger gets reset when 2nd output is null
#### 0.18.3: Maintenance Release
Projects
- Fix permissions on git/ssh scripts
- Add support for GIT_SSH on older levels of git
- Handle host key verification as auth error
- Ensure commit list has a refs object even if empty
- Make git error detection case-insensitive
- Fix up merge conflict handling
- Use flow-diff when looking at flow file changes
Node Fixes
- Ensure debug tools show for 'complete msg object'
- Fix msg.parts handling in concat mode of Batch node
Editor Fixes
- Fix offset calculation when dragging node from palette
- Allow a library entry to use non-default node-input- prefixes
- Change remote-diff shortcut and add it to keymap Fixes #1628
#### 0.18.2: Maintenance Release
Projects
- Filter out %D from git log command for older git versions
- Ensure projects are created as logged in user
- Better error handling/reporting in project creation
- Add Project Settings menu option
- Refresh vc sidebar on remote add/remove
- Fix auth prompt for ssh repos
- Prevent http git urls from including username/pword
- Fix fetch auth handling on non-default remote
- Avoid exception if git not installed
- Check version of git client on startup
- Fix pull/push when no tracked branch
- Add git_pull_unrelated_history handling
- Handle delete of last remote in project settings
Node Fixes
- Fix and Add some Chinese translations
- Update sort/batch docs
- Don't assume node has defaults when exporting icon property
- Ensure send is last thing trigger does
- Ensure trigger doesn't set two simultaneous timeouts
- Add missing property select var to HTML node
- Add a default keepalive to tcp client mode
- Move node.send in exec and httprequest nodes
#### 0.18.1: Maintenance Release
Projects

View File

@@ -392,9 +392,9 @@ module.exports = function(grunt) {
mode: '755'
},
release: {
// Target-specific file/dir lists and/or options go here.
src: [
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*')
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'),
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh')
]
}
},

View File

@@ -191,7 +191,7 @@ RED.history = (function() {
} else if (ev.t == "edit") {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
if (ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
// This is a config node property
var currentConfigNode = RED.nodes.node(ev.node[i]);
if (currentConfigNode) {
@@ -229,10 +229,12 @@ RED.history = (function() {
}
});
}
RED.editor.validateNode(ev.node);
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
n.inputs = ev.node.in.length;
n.outputs = ev.node.out.length;
RED.editor.updateNodeProperties(n);
RED.editor.validateNode(n);
});
} else {
var outputMap;

View File

@@ -14,7 +14,7 @@
"ctrl-i": "core:show-import-dialog",
"ctrl-space": "core:toggle-sidebar",
"ctrl-,": "core:show-user-settings",
"ctrl-alt-r": "core:show-remote-diff",
"ctrl-alt-n": "core:new-project",
"ctrl-alt-o": "core:open-project",
"ctrl-g v": "core:show-version-control-tab"

View File

@@ -67,6 +67,7 @@
if (!activeProject) {
// Projects enabled but no active project
RED.menu.setDisabled('menu-item-projects-open',true);
RED.menu.setDisabled('menu-item-projects-settings',true);
if (activeProject === false) {
// User previously decline the migration to projects.
} else { // null/undefined
@@ -130,11 +131,12 @@
var project = RED.projects.getActiveProject();
var message = {
"change-branch":"Change to local branch '"+project.git.branches.local+"'",
"abort-merge":"Git merge aborted",
"merge-abort":"Git merge aborted",
"loaded":"Project '"+msg.project+"' loaded",
"updated":"Project '"+msg.project+"' updated",
"pull":"Project '"+msg.project+"' reloaded",
"revert": "Project '"+msg.project+"' reloaded"
"revert": "Project '"+msg.project+"' reloaded",
"merge-complete":"Git merge completed"
}[msg.action];
RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh()
@@ -218,6 +220,20 @@
}
]
}
} else if (msg.error === "git_merge_conflict") {
RED.nodes.clear();
RED.sidebar.versionControl.refresh(true);
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: "Show merge conflicts",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.sidebar.versionControl.showLocalChanges();
}
}
]
}
}
}
if (!persistentNotifications.hasOwnProperty(notificationId)) {
@@ -320,8 +336,9 @@
var menuOptions = [];
if (RED.settings.theme("projects.enabled",false)) {
menuOptions.push({id:"menu-item-projects-menu",label:"Projects",options:[
{id:"menu-item-projects-new",label:"New...",disabled:false,onselect:"core:new-project"},
{id:"menu-item-projects-open",label:"Open...",disabled:false,onselect:"core:open-project"}
{id:"menu-item-projects-new",label:"New",disabled:false,onselect:"core:new-project"},
{id:"menu-item-projects-open",label:"Open",disabled:false,onselect:"core:open-project"},
{id:"menu-item-projects-settings",label:"Project Settings",disabled:false,onselect:"core:show-project-settings"}
]});
}

View File

@@ -355,7 +355,7 @@ RED.nodes = (function() {
RED.nodes.registerType("subflow:"+sf.id, {
defaults:{name:{value:""}},
info: sf.info,
icon:"subflow.png",
icon: function() { return sf.icon||"subflow.png" },
category: "subflows",
inputs: sf.in.length,
outputs: sf.out.length,
@@ -550,7 +550,11 @@ RED.nodes = (function() {
if (node.out.length > 0 && n.outputLabels && !/^\s*$/.test(n.outputLabels.join(""))) {
node.outputLabels = n.outputLabels.slice();
}
if (n.icon) {
if (n.icon !== "node-red/subflow.png") {
node.icon = n.icon;
}
}
return node;
}

View File

@@ -116,7 +116,9 @@
this.options.types = this.options.types||Object.keys(allOptions);
this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect);
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
if (this.options.types.length > 1) {
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
}
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
this.types(this.options.types);

View File

@@ -408,9 +408,12 @@ RED.deploy = (function() {
delete confNode.credentials;
}
});
RED.nodes.eachSubflow(function(subflow) {
subflow.changed = false;
});
RED.nodes.eachWorkspace(function(ws) {
ws.changed = false;
})
});
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();

View File

@@ -9,29 +9,30 @@ RED.diff = (function() {
// RED.actions.add("core:show-current-diff",showLocalDiff);
RED.actions.add("core:show-remote-diff",showRemoteDiff);
// RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff");
RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
// RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
RED.actions.add("core:show-test-flow-diff-1",function(){showTestFlowDiff(1)});
RED.keyboard.add("*","ctrl-shift-f 1","core:show-test-flow-diff-1");
RED.actions.add("core:show-test-flow-diff-2",function(){showTestFlowDiff(2)});
RED.keyboard.add("*","ctrl-shift-f 2","core:show-test-flow-diff-2");
RED.actions.add("core:show-test-flow-diff-3",function(){showTestFlowDiff(3)});
RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
// RED.actions.add("core:show-test-flow-diff-1",function(){showTestFlowDiff(1)});
// RED.keyboard.add("*","ctrl-shift-f 1","core:show-test-flow-diff-1");
//
// RED.actions.add("core:show-test-flow-diff-2",function(){showTestFlowDiff(2)});
// RED.keyboard.add("*","ctrl-shift-f 2","core:show-test-flow-diff-2");
// RED.actions.add("core:show-test-flow-diff-3",function(){showTestFlowDiff(3)});
// RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
}
function createDiffTable(container) {
function createDiffTable(container,CurrentDiff) {
var diffList = $('<ol class="node-dialog-view-diff-diff"></ol>').appendTo(container);
diffList.editableList({
addButton: false,
height: "auto",
scrollOnAdd: false,
addItem: function(container,i,object) {
var localDiff = object.diff;
var remoteDiff = object.remoteDiff;
var tab = object.tab.n;
var def = object.def;
var conflicts = currentDiff.conflicts;
var conflicts = CurrentDiff.conflicts;
var tabDiv = $('<div>',{class:"node-diff-tab"}).appendTo(container);
tabDiv.addClass('collapsed');
@@ -150,10 +151,10 @@ RED.diff = (function() {
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
selectState = CurrentDiff.resolutions[tab.id];
}
// Tab properties row
createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState);
createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState,CurrentDiff);
}
}
// var stats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(titleRow);
@@ -162,14 +163,14 @@ RED.diff = (function() {
var seen = {};
object.tab.nodes.forEach(function(node) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
createNodeDiffRow(node,flowStats,CurrentDiff).appendTo(nodesDiv)
});
if (object.newTab) {
localNodeCount = object.newTab.nodes.length;
object.newTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
createNodeDiffRow(node,flowStats,CurrentDiff).appendTo(nodesDiv)
}
});
}
@@ -177,7 +178,7 @@ RED.diff = (function() {
remoteNodeCount = object.remoteTab.nodes.length;
object.remoteTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
createNodeDiffRow(node,flowStats,CurrentDiff).appendTo(nodesDiv)
}
});
}
@@ -269,12 +270,12 @@ RED.diff = (function() {
if (flowStats.conflicts > 0) {
titleRow.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
selectState = CurrentDiff.resolutions[tab.id];
}
if (tab.id) {
var hide = !(flowStats.conflicts > 0 &&(localDiff.deleted[tab.id] || remoteDiff.deleted[tab.id]));
// Tab parent row
createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, hide, selectState);
createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, hide, selectState, CurrentDiff);
}
}
@@ -291,11 +292,8 @@ RED.diff = (function() {
var diffHeaders = $('<div class="node-dialog-view-diff-headers"></div>').appendTo(diffPanel);
if (options.mode === "merge") {
diffPanel.addClass("node-dialog-view-diff-panel-merge");
var toolbar = $('<div class="node-diff-toolbar">'+
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
'</div>').prependTo(diffPanel);
}
var diffList = createDiffTable(diffPanel);
var diffList = createDiffTable(diffPanel, diff);
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
@@ -512,10 +510,10 @@ RED.diff = (function() {
$('<span>',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv);
return nodeTitleDiv;
}
function createNodeDiffRow(node,stats) {
var localDiff = currentDiff.localDiff;
var remoteDiff = currentDiff.remoteDiff;
var conflicted = currentDiff.conflicts[node.id];
function createNodeDiffRow(node,stats,CurrentDiff) {
var localDiff = CurrentDiff.localDiff;
var remoteDiff = CurrentDiff.remoteDiff;
var conflicted = CurrentDiff.conflicts[node.id];
var hasChanges = false; // exists in original and local/remote but with changes
var unChanged = true; // existing in original,local,remote unchanged
@@ -703,10 +701,10 @@ RED.diff = (function() {
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[node.id];
selectState = CurrentDiff.resolutions[node.id];
}
// Node row
createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState);
createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState,CurrentDiff);
row.click(function(evt) {
$(this).parent().toggleClass('collapsed');
});
@@ -982,7 +980,7 @@ RED.diff = (function() {
});
return nodePropertiesDiv;
}
function createNodeConflictRadioBoxes(node,row,localDiv,remoteDiv,propertiesTable,hide,state) {
function createNodeConflictRadioBoxes(node,row,localDiv,remoteDiv,propertiesTable,hide,state,diff) {
var safeNodeId = "node-diff-selectbox-"+node.id.replace(/\./g,'-')+(propertiesTable?"-props":"");
var className = "";
if (node.z||propertiesTable) {
@@ -1019,7 +1017,7 @@ RED.diff = (function() {
row.addClass("node-diff-select-remote");
row.removeClass("node-diff-select-local");
}
refreshConflictHeader();
refreshConflictHeader(diff);
}
var localSelectDiv = $('<label>',{class:"node-diff-selectbox",for:safeNodeId+"-local"}).click(function(e) { e.stopPropagation();}).appendTo(localDiv);
@@ -1037,7 +1035,7 @@ RED.diff = (function() {
}
}
function refreshConflictHeader() {
function refreshConflictHeader(currentDiff) {
var resolutionCount = 0;
$(".node-diff-selectbox>input:checked").each(function() {
if (currentDiff.conflicts[$(this).data('node-id')]) {
@@ -1053,6 +1051,7 @@ RED.diff = (function() {
}
if (conflictCount === resolutionCount) {
$("#node-diff-view-diff-merge").removeClass('disabled');
$("#node-diff-view-resolve-diff").removeClass('disabled');
}
}
function getRemoteDiff(callback) {
@@ -1231,7 +1230,7 @@ RED.diff = (function() {
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
var conflicts = diff.conflicts;
currentDiff = diff;
// currentDiff = diff;
var trayOptions = {
title: options.title||"Review Changes", //TODO: nls
@@ -1250,7 +1249,11 @@ RED.diff = (function() {
},
open: function(tray) {
var trayBody = tray.find('.editor-tray-body');
var diffTable = buildDiffPanel(trayBody,diff,options);
var toolbar = $('<div class="node-diff-toolbar">'+
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
'</div>').prependTo(trayBody);
var diffContainer = $('<div class="node-diff-container"></div>').appendTo(trayBody);
var diffTable = buildDiffPanel(diffContainer,diff,options);
diffTable.list.hide();
if (remoteDiff) {
$("#node-diff-view-diff-merge").show();
@@ -1262,7 +1265,7 @@ RED.diff = (function() {
} else {
$("#node-diff-view-diff-merge").hide();
}
refreshConflictHeader();
refreshConflictHeader(diff);
// console.log("--------------");
// console.log(localDiff);
// console.log(remoteDiff);
@@ -1290,8 +1293,8 @@ RED.diff = (function() {
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-diff-merge").hasClass('disabled')) {
refreshConflictHeader();
mergeDiff(currentDiff);
refreshConflictHeader(diff);
mergeDiff(diff);
RED.tray.close();
}
}
@@ -1302,7 +1305,7 @@ RED.diff = (function() {
RED.tray.show(trayOptions);
}
function mergeDiff(diff) {
function applyDiff(diff) {
var currentConfig = diff.localDiff.currentConfig;
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
@@ -1356,6 +1359,20 @@ RED.diff = (function() {
}
}
}
return {
config: newConfig,
nodeChangedStates: nodeChangedStates,
localChangedStates: localChangedStates
}
}
function mergeDiff(diff) {
var appliedDiff = applyDiff(diff);
var newConfig = appliedDiff.config;
var nodeChangedStates = appliedDiff.nodeChangedStates;
var localChangedStates = appliedDiff.localChangedStates;
var historyEvent = {
t:"replace",
config: RED.nodes.createCompleteNodeSet(),
@@ -1374,7 +1391,7 @@ RED.diff = (function() {
}
})
RED.nodes.version(remoteDiff.rev);
RED.nodes.version(diff.remoteDiff.rev);
RED.view.redraw(true);
RED.palette.refresh();
@@ -1417,7 +1434,7 @@ RED.diff = (function() {
var trayBody = tray.find('.editor-tray-body');
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
var codeTable = $("<table>").appendTo(diffPanel);
var codeTable = $("<table>",{class:"node-text-diff-content"}).appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50%"><col width="50"><col width="50%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
var diffSummary = diffText(textA||"",textB||"");
@@ -1681,7 +1698,7 @@ RED.diff = (function() {
files.forEach(function(file) {
var hunks = file.hunks;
var isBinary = file.binary;
var codeTable = $("<table>").appendTo(diffPanel);
var codeTable = $("<table>",{class:"node-text-diff-content"}).appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
@@ -1700,49 +1717,82 @@ RED.diff = (function() {
var unresolvedConflicts = 0;
var resolvedConflicts = 0;
var conflictResolutions = {};
if (commitOptions.project.files && commitOptions.project.files.flow === file.file) {
if (commitOptions.unmerged) {
$('<span style="float: right;"><span id="node-diff-toolbar-resolved-conflicts"></span></span>').appendTo(content);
}
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var flowDiffContent = $('<td class="flow-diff" colspan="3"></td>').appendTo(diffRow);
if (!commitOptions.unmerged && commitOptions.project.files && commitOptions.project.files.flow === file.file) {
var tools = $('<span style="float: right;" class="button-group"></span>').appendTo(content);
$('<button class="editor-button editor-button-small">show flow diff</button>').appendTo(tools).click(function(e) {
e.preventDefault();
e.stopPropagation();
var projectName = commitOptions.project.name;
var filename = commitOptions.project.files.flow;
var oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
$.when($.getJSON(oldVersionUrl),$.getJSON(newVersionUrl)).done(function(oldVersion,newVersion) {
var oldFlow;
var newFlow;
var projectName = commitOptions.project.name;
var filename = commitOptions.project.files.flow;
var commonVersionUrl = "projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
var oldVersionUrl = "projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
var newVersionUrl = "projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
var promises = [$.Deferred(),$.Deferred(),$.Deferred()];
if (commitOptions.commonRev) {
var commonVersionUrl = "projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
$.ajax({dataType: "json",url: commonVersionUrl}).then(function(data) { promises[0].resolve(data); }).fail(function() { promises[0].resolve(null);})
} else {
promises[0].resolve(null);
}
$.ajax({dataType: "json",url: oldVersionUrl}).then(function(data) { promises[1].resolve(data); }).fail(function() { promises[1].resolve({content:"[]"});})
$.ajax({dataType: "json",url: newVersionUrl}).then(function(data) { promises[2].resolve(data); }).fail(function() { promises[2].resolve({content:"[]"});})
$.when.apply($,promises).always(function(commonVersion, oldVersion,newVersion) {
var commonFlow;
var oldFlow;
var newFlow;
if (commonVersion) {
try {
oldFlow = JSON.parse(oldVersion[0].content||"[]");
commonFlow = JSON.parse(commonVersion.content||"[]");
} catch(err) {
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
console.log("Common Version doesn't contain valid JSON:",commonVersionUrl);
console.log(err);
return;
}
try {
newFlow = JSON.parse(newVersion[0].content||"[]");
} catch(err) {
console.log("New Version doesn't contain valid JSON:",newFlow);
console.log(err);
return;
}
var localDiff = generateDiff(oldFlow,oldFlow);
var remoteDiff = generateDiff(oldFlow,newFlow);
var diff = resolveDiffs(localDiff,remoteDiff);
showDiff(diff,{
title: filename,
mode: 'view',
oldRevTitle: commitOptions.oldRevTitle,
newRevTitle: commitOptions.newRevTitle
});
// var flowDiffRow = $("<tr>").insertAfter(diffRow);
// var content = $('<td colspan="3"></td>').appendTo(flowDiffRow);
// currentDiff = diff;
// var diffTable = buildDiffPanel(content,diff,{mode:"view"}).finish();
}
try {
oldFlow = JSON.parse(oldVersion.content||"[]");
} catch(err) {
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
console.log(err);
return;
}
if (!commonFlow) {
commonFlow = oldFlow;
}
try {
newFlow = JSON.parse(newVersion.content||"[]");
} catch(err) {
console.log("New Version doesn't contain valid JSON:",newFlow);
console.log(err);
return;
}
var localDiff = generateDiff(commonFlow,oldFlow);
var remoteDiff = generateDiff(commonFlow,newFlow);
commitOptions.currentDiff = resolveDiffs(localDiff,remoteDiff);
var diffTable = buildDiffPanel(flowDiffContent,commitOptions.currentDiff,{
title: filename,
mode: commitOptions.commonRev?'merge':'view',
oldRevTitle: commitOptions.oldRevTitle,
newRevTitle: commitOptions.newRevTitle
});
})
}
diffTable.list.hide();
refreshConflictHeader(commitOptions.currentDiff);
setTimeout(function() {
diffTable.finish();
diffTable.list.show();
},300);
// var flowDiffRow = $("<tr>").insertAfter(diffRow);
// var content = $('<td colspan="3"></td>').appendTo(flowDiffRow);
// currentDiff = diff;
// var diffTable = buildDiffPanel(content,diff,{mode:"view"}).finish();
});
} else
if (isBinary) {
var diffBinaryRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
@@ -1750,6 +1800,9 @@ RED.diff = (function() {
$('<span></span>').text("Cannot show binary file contents").appendTo(binaryContent);
} else {
if (commitOptions.unmerged) {
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
}
hunks.forEach(function(hunk) {
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var content = $('<td colspan="3"></td>').appendTo(diffRow);
@@ -1768,7 +1821,7 @@ RED.diff = (function() {
// }
var actualLineNumber = hunk.diffStart + lineNumber;
var isMergeHeader = isConflict && /^..(<<<<<<<|=======$|>>>>>>>)/.test(lineText);
var isMergeHeader = isConflict && /^\+\+(<<<<<<<|=======$|>>>>>>>)/.test(lineText);
var diffRow = $('<tr>').appendTo(codeBody);
var localLineNo = $('<td class="lineno">').appendTo(diffRow);
var remoteLineNo;
@@ -1827,7 +1880,7 @@ RED.diff = (function() {
$('<span>').text(lineText.substring(prefixEnd)).appendTo(line);
} else {
diffRow.addClass("mergeHeader");
var isSeparator = /^..(=======$)/.test(lineText);
var isSeparator = /^\+\+=======$/.test(lineText);
if (!isSeparator) {
var isOurs = /^..<<<<<<</.test(lineText);
if (isOurs) {
@@ -1886,9 +1939,6 @@ RED.diff = (function() {
});
});
}
if (commitOptions.unmerged) {
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
}
});
return diffPanel;
}
@@ -1914,7 +1964,7 @@ RED.diff = (function() {
var trayBody = tray.find('.editor-tray-body');
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
var codeTable = $("<table>").appendTo(diffPanel);
var codeTable = $("<table>",{class:"node-text-diff-content"}).appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
@@ -1957,7 +2007,6 @@ RED.diff = (function() {
}
}
var trayOptions = {
title: title||"Compare Changes", //TODO: nls
width: Infinity,
@@ -1996,6 +2045,15 @@ RED.diff = (function() {
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) {
if (options.currentDiff) {
// This is a flow file. Need to apply the diff
// and generate the new flow.
var result = applyDiff(options.currentDiff);
currentResolution = {
resolutions:{}
};
currentResolution.resolutions[options.project.files.flow] = JSON.stringify(result.config,"",4);
}
if (options.onresolve) {
options.onresolve(currentResolution);
}
@@ -2047,7 +2105,7 @@ RED.diff = (function() {
} else {
lines = diff.split("\n");
}
var diffHeader = /^diff --git a\/(.*) b\/(.*)$/;
var diffHeader = /^diff (?:(?:--git a\/(.*) b\/(.*))|(?:--cc (.*)))$/;
var fileHeader = /^\+\+\+ b\/(.*)\t?/;
var binaryFile = /^Binary files /;
var hunkHeader = /^@@ -((\d+)(,(\d+))?) \+((\d+)(,(\d+))?) @@ ?(.*)$/;
@@ -2066,7 +2124,7 @@ RED.diff = (function() {
}
currentHunk = null;
currentFile = {
file: diffLine[1],
file: diffLine[1]||diffLine[3],
hunks: []
}
} else if (binaryFile.test(line)) {

View File

@@ -48,7 +48,7 @@ RED.editor = (function() {
isValid = validateNode(subflow);
hasChanged = subflow.changed;
}
node.valid = isValid;
node.valid = isValid && validateNodeProperties(node, node._def.defaults, node);
node.changed = node.changed || hasChanged;
} else if (node._def) {
node.valid = validateNodeProperties(node, node._def.defaults, node);
@@ -170,6 +170,10 @@ RED.editor = (function() {
}
}
}
validateIcon(node);
}
function validateIcon(node) {
if (node._def.hasOwnProperty("defaults") && !node._def.defaults.hasOwnProperty("icon") && node.icon) {
var iconPath = RED.utils.separateIconPath(node.icon);
var iconSets = RED.nodes.getIconSets();
@@ -188,6 +192,7 @@ RED.editor = (function() {
}
}
}
function validateNodeEditorProperty(node,defaults,property,prefix) {
var input = $("#"+prefix+"-"+property);
if (input.length > 0) {
@@ -742,7 +747,7 @@ RED.editor = (function() {
buildLabelRow().appendTo(outputsDiv);
}
if (!node._def.defaults.hasOwnProperty("icon")) {
if ((!node._def.defaults || !node._def.defaults.hasOwnProperty("icon"))) {
$('<div class="form-row"><div id="node-settings-icon"></div></div>').appendTo(dialogForm);
var iconDiv = $("#node-settings-icon");
$('<label data-i18n="editor.settingIcon">').appendTo(iconDiv);
@@ -816,9 +821,51 @@ RED.editor = (function() {
});
}
selectIconFile.prop("disabled", !iconFileList);
selectIconFile.removeClass("input-error");
selectIconModule.removeClass("input-error");
}
function updateLabels(editing_node, changes, outputMap) {
var inputLabels = $("#node-label-form-inputs").children().find("input");
var outputLabels = $("#node-label-form-outputs").children().find("input");
var hasNonBlankLabel = false;
var changed = false;
var newValue = inputLabels.map(function() {
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
return v;
}).toArray().slice(0,editing_node.inputs);
if ((editing_node.inputLabels === undefined && hasNonBlankLabel) ||
(editing_node.inputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels))) {
changes.inputLabels = editing_node.inputLabels;
editing_node.inputLabels = newValue;
changed = true;
}
hasNonBlankLabel = false;
newValue = new Array(editing_node.outputs);
outputLabels.each(function() {
var index = $(this).attr('id').substring(23); // node-label-form-output-<index>
if (outputMap && outputMap.hasOwnProperty(index)) {
index = parseInt(outputMap[index]);
if (index === -1) {
return;
}
}
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
newValue[index] = v;
});
if ((editing_node.outputLabels === undefined && hasNonBlankLabel) ||
(editing_node.outputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels))) {
changes.outputLabels = editing_node.outputLabels;
editing_node.outputLabels = newValue;
changed = true;
}
return changed;
}
function showEditDialog(node) {
var editing_node = node;
var isDefaultIcon;
@@ -1034,44 +1081,11 @@ RED.editor = (function() {
// }
var removedLinks = updateNodeProperties(editing_node,outputMap);
var inputLabels = $("#node-label-form-inputs").children().find("input");
var outputLabels = $("#node-label-form-outputs").children().find("input");
var hasNonBlankLabel = false;
newValue = inputLabels.map(function() {
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
return v;
}).toArray().slice(0,editing_node.inputs);
if ((editing_node.inputLabels === undefined && hasNonBlankLabel) ||
(editing_node.inputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels))) {
changes.inputLabels = editing_node.inputLabels;
editing_node.inputLabels = newValue;
changed = true;
}
hasNonBlankLabel = false;
newValue = new Array(editing_node.outputs);
outputLabels.each(function() {
var index = $(this).attr('id').substring(23); // node-label-form-output-<index>
if (outputMap && outputMap.hasOwnProperty(index)) {
index = parseInt(outputMap[index]);
if (index === -1) {
return;
}
}
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
newValue[index] = v;
})
if ((editing_node.outputLabels === undefined && hasNonBlankLabel) ||
(editing_node.outputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels))) {
changes.outputLabels = editing_node.outputLabels;
editing_node.outputLabels = newValue;
if (updateLabels(editing_node, changes, outputMap)) {
changed = true;
}
if (!editing_node._def.defaults.hasOwnProperty("icon")) {
if (!editing_node._def.defaults || !editing_node._def.defaults.hasOwnProperty("icon")) {
var iconModule = $("#node-settings-icon-module-hidden").val();
var iconFile = $("#node-settings-icon-file-hidden").val();
var icon = (iconModule && iconFile) ? iconModule+"/"+iconFile : "";
@@ -1675,25 +1689,25 @@ RED.editor = (function() {
editing_node.info = newDescription;
changed = true;
}
var inputLabels = $("#node-label-form-inputs").children().find("input");
var outputLabels = $("#node-label-form-outputs").children().find("input");
var newValue = inputLabels.map(function() { return $(this).val();}).toArray().slice(0,editing_node.inputs);
if (JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels)) {
changes.inputLabels = editing_node.inputLabels;
editing_node.inputLabels = newValue;
if (updateLabels(editing_node, changes, null)) {
changed = true;
}
newValue = outputLabels.map(function() { return $(this).val();}).toArray().slice(0,editing_node.outputs);
if (JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels)) {
changes.outputLabels = editing_node.outputLabels;
editing_node.outputLabels = newValue;
var iconModule = $("#node-settings-icon-module-hidden").val();
var iconFile = $("#node-settings-icon-file-hidden").val();
var icon = (iconModule && iconFile) ? iconModule+"/"+iconFile : "";
if ((editing_node.icon === undefined && icon !== "node-red/subflow.png") ||
(editing_node.icon !== undefined && editing_node.icon !== icon)) {
changes.icon = editing_node.icon;
editing_node.icon = icon;
changed = true;
}
RED.palette.refresh();
if (changed) {
var wasChanged = editing_node.changed;
editing_node.changed = true;
validateNode(editing_node);
var subflowInstances = [];
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+editing_node.id) {
@@ -1704,10 +1718,9 @@ RED.editor = (function() {
n.changed = true;
n.dirty = true;
updateNodeProperties(n);
validateNode(n);
}
});
var wasChanged = editing_node.changed;
editing_node.changed = true;
RED.nodes.dirty(true);
var historyEvent = {
t:'edit',
@@ -1786,6 +1799,7 @@ RED.editor = (function() {
$("#subflow-dialog-user-count").html(RED._("subflow.subflowInstances", {count:userCount})).show();
buildLabelForm(portLabels.content,subflow);
validateIcon(subflow);
trayBody.i18n();
},
close: function() {

View File

@@ -15,8 +15,8 @@
**/
RED.library = (function() {
var exportToLibraryDialog;
var elementPrefix = "node-input-";
function loadFlowLibrary() {
$.getJSON("library/flows",function(data) {
@@ -86,6 +86,7 @@ RED.library = (function() {
var libraryData = {};
var selectedLibraryItem = null;
var libraryEditor = null;
elementPrefix = options.elementPrefix || "node-input-";
// Orion editor has set/getText
// ACE editor has set/getValue
@@ -157,8 +158,8 @@ RED.library = (function() {
return ul;
}
$('#node-input-name').css("width","66%").after(
'<div class="btn-group" style="margin-left: 5px;">'+
$('#'+elementPrefix+"name").css("width","calc(100% - 52px)").after(
'<div class="btn-group" style="margin-left:5px;">'+
'<a id="node-input-'+options.type+'-lookup" class="editor-button" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></a>'+
'<ul class="dropdown-menu pull-right" role="menu">'+
'<li><a id="node-input-'+options.type+'-menu-open-library" tabindex="-1" href="#">'+RED._("library.openLibrary")+'</a></li>'+
@@ -187,7 +188,7 @@ RED.library = (function() {
$('#node-input-'+options.type+'-menu-save-library').click(function(e) {
//var found = false;
var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,"");
//var buildPathList = function(data,root) {
// var paths = [];
@@ -264,7 +265,7 @@ RED.library = (function() {
if (selectedLibraryItem) {
for (var i=0; i<options.fields.length; i++) {
var field = options.fields[i];
$("#node-input-"+field).val(selectedLibraryItem[field]);
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
options.editor.setValue(libraryEditor.getValue(),-1);
}
@@ -286,7 +287,7 @@ RED.library = (function() {
});
function saveToLibrary(overwrite) {
var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,"");
if (name === "") {
name = RED._("library.unnamedType",{type:options.type});
}
@@ -330,7 +331,7 @@ RED.library = (function() {
if (field == "name") {
data.name = name;
} else {
data[field] = $("#node-input-"+field).val();
data[field] = $("#"+elementPrefix+field).val();
}
}

View File

@@ -116,6 +116,12 @@ RED.palette = (function() {
el.data('popover').setContent(popOverContent);
}
function setIcon(element,sf) {
var iconElement = element.find(".palette_icon");
var icon_url = RED.utils.getNodeIcon(sf._def,sf);
iconElement.attr("style", "background-image: url("+icon_url+")");
}
function escapeNodeType(nt) {
return nt.replace(" ","_").replace(".","_").replace(":","_");
}
@@ -219,13 +225,19 @@ RED.palette = (function() {
var mouseX;
var mouseY;
var spliceTimer;
var paletteWidth;
var paletteTop;
$(d).draggable({
helper: 'clone',
appendTo: 'body',
revert: true,
revertDuration: 50,
containment:'#main-container',
start: function() {RED.view.focus();},
start: function() {
paletteWidth = $("#palette").width();
paletteTop = $("#palette").parent().position().top + $("#palette-container").position().top;
RED.view.focus();
},
stop: function() { d3.select('.link_splice').classed('link_splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}},
drag: function(e,ui) {
@@ -235,9 +247,8 @@ RED.palette = (function() {
ui.position.left += 17.5;
if (def.inputs > 0 && def.outputs > 0) {
mouseX = ui.position.left+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft();
mouseY = ui.position.top+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop();
mouseX = ui.position.left-paletteWidth+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft();
mouseY = ui.position.top-paletteTop+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop();
if (!spliceTimer) {
spliceTimer = setTimeout(function() {
var nodes = [];
@@ -259,6 +270,7 @@ RED.palette = (function() {
mouseY /= RED.view.scale();
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
}
for (var i=0;i<nodes.length;i++) {
if (d3.select(nodes[i]).classed('link_background')) {
var length = nodes[i].getTotalLength();
@@ -369,6 +381,7 @@ RED.palette = (function() {
portOutput.remove();
}
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
setIcon(paletteNode,sf);
});
}

View File

@@ -49,7 +49,7 @@ RED.projects.settings = (function() {
var tabContainer;
var trayOptions = {
title: "Project Information",// RED._("menu.label.userSettings"),, // TODO: nls
title: "Project Settings",// RED._("menu.label.userSettings"),, // TODO: nls
buttons: [
{
id: "node-dialog-ok",
@@ -143,7 +143,8 @@ RED.projects.settings = (function() {
RED.sidebar.versionControl.refresh(true);
},
400: {
'unexpected_error': function(error) {
'*': function(error) {
utils.reportUnexpectedError(error);
done(error,null);
}
},
@@ -208,7 +209,8 @@ RED.projects.settings = (function() {
done(null,data);
},
400: {
'unexpected_error': function(error) {
'*': function(error) {
utils.reportUnexpectedError(error);
done(error,null);
}
},
@@ -350,6 +352,7 @@ RED.projects.settings = (function() {
}
},{dependencies:dependencies});
}
function editDependencies(activeProject,depsJSON,container,depsList) {
var json = depsJSON||JSON.stringify(activeProject.dependencies||{},"",4);
if (json === "{}") {
@@ -378,6 +381,7 @@ RED.projects.settings = (function() {
function createDependenciesPane(activeProject) {
var pane = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>');
var nrDepButton;
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>')
.appendTo(pane)
@@ -385,6 +389,16 @@ RED.projects.settings = (function() {
evt.preventDefault();
editDependencies(activeProject,null,pane,depsList)
});
nrDepButton = $('<button class="editor-button editor-button-small" style="margin-top:10px;">add Node-RED core</button>')
.appendTo(pane)
.click(function(evt) {
evt.preventDefault();
activeProject.dependencies["node-red"] = "~"+RED.settings.version;
updateProjectDependencies(activeProject,depsList);
$(this).hide();
});
if (activeProject.dependencies.hasOwnProperty("node-red")) { nrDepButton.hide(); }
}
var depsList = $("<ol>",{style:"position: absolute;top: 60px;bottom: 20px;left: 20px;right: 20px;"}).appendTo(pane);
depsList.editableList({
@@ -471,6 +485,7 @@ RED.projects.settings = (function() {
evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies);
delete deps[entry.id];
if (entry.id === "node-red") { nrDepButton.show(); }
saveDependencies(depsList,row,deps,function(err) {
if (!err) {
row.fadeOut(200,function() {
@@ -517,7 +532,6 @@ RED.projects.settings = (function() {
updateProjectDependencies(activeProject,depsList);
return pane;
}
function showProjectFileListing(row,activeProject,current,filter,done) {
@@ -962,7 +976,7 @@ RED.projects.settings = (function() {
var done = function(err) {
spinner.remove();
if (err) {
console.log(err);
utils.reportUnexpectedError(err);
return;
}
flowFileLabelText.text(flowFileInput.val());
@@ -1005,10 +1019,6 @@ RED.projects.settings = (function() {
'credentials_load_failed': function(error) {
done(error);
},
'unexpected_error': function(error) {
console.log(error);
done(error);
},
'missing_current_credential_key': function(error) {
credentialSecretExistingInput.addClass("input-error");
popover = RED.popover.create({
@@ -1019,11 +1029,16 @@ RED.projects.settings = (function() {
autoClose: 3000
}).open();
done(error);
},
'*': function(error) {
done(error);
}
},
}
},payload).always(function() {
RED.deploy.setDeployInflight(false);
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
});
var updateForm = function() {
@@ -1142,8 +1157,8 @@ RED.projects.settings = (function() {
]
});
},
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
spinner.remove();
}
},
@@ -1193,12 +1208,19 @@ RED.projects.settings = (function() {
editRepoButton.attr('disabled',true);
addRemoteDialog.slideDown(200, function() {
addRemoteDialog[0].scrollIntoView();
if (isEmpty) {
remoteNameInput.val('origin');
remoteURLInput.focus();
} else {
remoteNameInput.focus();
}
validateForm();
});
});
var emptyItem = { empty: true };
var isEmpty = true;
var row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
var addRemoteDialog = $('<div class="projects-dialog-list-dialog"></div>').hide().appendTo(row);
row = $('<div class="user-settings-row projects-dialog-list"></div>').appendTo(repoContainer);
@@ -1256,6 +1278,7 @@ RED.projects.settings = (function() {
setTimeout(spinner.remove, 100);
if (data.remotes.length === 0) {
delete activeProject.git.remotes;
isEmpty = true;
remotesList.editableList('addItem',emptyItem);
} else {
activeProject.git.remotes = {};
@@ -1265,11 +1288,12 @@ RED.projects.settings = (function() {
activeProject.git.remotes[name] = remote;
});
}
RED.sidebar.versionControl.refresh();
});
},
400: {
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
spinner.remove();
}
},
@@ -1290,16 +1314,26 @@ RED.projects.settings = (function() {
var validateForm = function() {
var validName = /^[a-zA-Z0-9\-_]+$/.test(remoteNameInput.val());
var repo = remoteURLInput.val();
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\.git)?(?:\/?|\#[\d\w\.\-_]+?)$/.test(remoteURLInput.val());
var validRepo = !/\s/.test(remoteURLInput.val());
var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) {
remoteURLLabel.text("Do not include the username/password in the url");
validRepo = false;
} else {
remoteURLLabel.text("https://, ssh:// or file://");
}
saveButton.attr('disabled',(!validName || !validRepo))
remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName);
remoteURLInput.toggleClass('input-error',remoteURLInputChanged&&!validRepo);
if (popover) {
popover.close();
popover = null;
}
};
var popover;
var remoteNameInputChanged = false;
var remoteURLInputChanged = false;
$('<div class="projects-dialog-list-dialog-header">').text('Add remote').appendTo(addRemoteDialog);
@@ -1309,11 +1343,14 @@ RED.projects.settings = (function() {
remoteNameInputChanged = true;
validateForm();
});
var remoteNameInputChanged = false;
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text('URL').appendTo(row);
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",validateForm);
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteURLInputChanged = true;
validateForm()
});
var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row).find("small");
var hideEditForm = function() {
editRepoButton.attr('disabled',false);
@@ -1367,6 +1404,7 @@ RED.projects.settings = (function() {
activeProject.git.remotes[name] = remote;
});
updateForm();
RED.sidebar.versionControl.refresh();
done();
},
400: {
@@ -1381,14 +1419,15 @@ RED.projects.settings = (function() {
remoteNameInput.addClass('input-error');
done(error);
},
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
done(error);
}
},
}
},payload);
});
var updateForm = function() {
remotesList.editableList('empty');
var count = 0;
@@ -1400,7 +1439,8 @@ RED.projects.settings = (function() {
}
}
}
if (count === 0) {
isEmpty = (count === 0);
if (isEmpty) {
remotesList.editableList('addItem',emptyItem);
}
}

View File

@@ -19,7 +19,45 @@ RED.projects = (function() {
var dialogBody;
var activeProject;
function reportUnexpectedError(error) {
var notification;
if (error.error === 'git_missing_user') {
notification = RED.notify("<p>You Git client is not configured with a username/email.</p>",{
fixed: true,
type:'error',
buttons: [
{
text: "Cancel",
click: function() {
notification.close();
}
},
{
text: "Configure Git client",
click: function() {
RED.userSettings.show('gitconfig');
notification.close();
}
}
]
})
} else {
console.log(error);
notification = RED.notify("<p>An unexpected error occurred:</p><p>"+error.message+"</p><small>code: "+error.error+"</small>",{
fixed: true,
modal: true,
type: 'error',
buttons: [
{
text: "Close",
click: function() {
notification.close();
}
}
]
})
}
}
var screens = {};
function initScreens() {
var migrateProjectHeader = $('<div class="projects-dialog-screen-start-hero"></div>');
@@ -39,8 +77,8 @@ RED.projects = (function() {
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Hello! We have introduced 'projects' to Node-RED.").appendTo(body);
$('<p>').text("This is a new way for you to manage your flow files and includes version control of your flows.").appendTo(body);
$('<p>').text("To get started you can create your first project using your current flow files in a few easy steps.").appendTo(body);
$('<p>').text("If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu option at any time.").appendTo(body);
$('<p>').text("To get started you can create your first project or clone an existing project from a git repository.").appendTo(body);
$('<p>').text("If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.").appendTo(body);
return container;
},
@@ -275,9 +313,9 @@ RED.projects = (function() {
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Create your project files").appendTo(body);
$('<p>').text("A project contains your flow files, a README file, a package.json file and a settings file.").appendTo(body);
$('<p>').text("A project contains your flow files, a README file and a package.json file.").appendTo(body);
$('<p>').text("It can contain any other files you want to maintain in the Git repository.").appendTo(body);
if (!options.existingProject) {
if (!options.existingProject && RED.settings.files) {
$('<p>').text("Your existing flow and credential files will be copied into the project.").appendTo(body);
}
@@ -311,14 +349,14 @@ RED.projects = (function() {
var row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-file">Flow file</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row);
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || RED.settings.files.flow||"flow.json";
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || (RED.settings.files && RED.settings.files.flow)||"flow.json";
projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val(defaultFlowFile)
.on("change keyup paste",validateForm)
.appendTo(subrow);
$('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
$('<label class="projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row);
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || RED.settings.files.credentials||"flow_cred.json";
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || (RED.settings.files && RED.settings.files.credentials)||"flow_cred.json";
row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-credfile">Credentials file</label>').appendTo(row);
subrow = $('<div style="position:relative;"></div>').appendTo(row);
@@ -546,6 +584,7 @@ RED.projects = (function() {
} else {
show('create-success');
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
}
},
400: {
@@ -564,8 +603,9 @@ RED.projects = (function() {
// getRepoAuthDetails(req);
console.log("git auth error",error);
},
'unexpected_error': function(error) {
console.log("unexpected_error",error)
'*': function(error) {
reportUnexpectedError(error);
$( dialog ).dialog( "close" );
}
}
}
@@ -614,6 +654,7 @@ RED.projects = (function() {
var projectSecretSelect;
var copyProject;
var projectRepoInput;
var projectCloneSecret;
var emptyProjectCredentialInput;
var projectRepoUserInput;
var projectRepoPasswordInput;
@@ -682,7 +723,11 @@ RED.projects = (function() {
var repo = projectRepoInput.val();
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
var validRepo = !/\s/.test(repo);
var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) {
$("#projects-dialog-screen-create-project-repo-label small").text("Do not include the username/password in the url");
validRepo = false;
}
if (!validRepo) {
if (projectRepoChanged) {
projectRepoInput.addClass("input-error");
@@ -769,7 +814,11 @@ RED.projects = (function() {
validateForm();
},
delete: function(project) {
if (projectList) {
delete projectList[project.name];
}
selectedProject = null;
validateForm();
}
}).appendTo(row);
@@ -971,10 +1020,12 @@ RED.projects = (function() {
// -----------------------------------------------------
// // Secret - clone
// row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
// $('<label>Credentials encryption key</label>').appendTo(row);
// projectSecretInput = $('<input type="text"></input>').appendTo(row);
// Secret - clone
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label>Credentials encryption key</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row);
switch(options.screen||"empty") {
case "empty": createAsEmpty.click(); break;
case "open": openProject.click(); break;
@@ -1032,7 +1083,7 @@ RED.projects = (function() {
} else if (projectType === 'copy') {
projectData.copy = copyProject.name;
} else if (projectType === 'clone') {
// projectData.credentialSecret = projectSecretInput.val();
projectData.credentialSecret = projectSecretInput.val();
var repoUrl = projectRepoInput.val();
var metaData = {};
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repoUrl)) {
@@ -1082,7 +1133,6 @@ RED.projects = (function() {
projectRepoSSHKeySelect.removeClass("input-error");
projectRepoPassphrase.removeClass("input-error");
RED.deploy.setDeployInflight(true);
RED.projects.settings.switchProject(projectData.name);
@@ -1122,6 +1172,10 @@ RED.projects = (function() {
projectRepoSSHKeySelect.addClass("input-error");
projectRepoPassphrase.addClass("input-error");
},
'missing_flow_file': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'project_empty': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
@@ -1130,8 +1184,9 @@ RED.projects = (function() {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'unexpected_error': function(error) {
console.log("unexpected_error",error)
'*': function(error) {
reportUnexpectedError(error);
$( dialog ).dialog( "close" );
}
}
}
@@ -1517,7 +1572,7 @@ RED.projects = (function() {
'</div>');
var isSSH = false;
if (/^https?:\/\//) {
if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">Username</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">Password</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
@@ -1738,8 +1793,17 @@ RED.projects = (function() {
},Math.max(300-(Date.now() - start),0));
},
400: {
'git_connection_failed': function(error) {
RED.notify(error.message,'error');
},
'git_not_a_repository': function(error) {
RED.notify(error.message,'error');
},
'git_repository_not_found': function(error) {
RED.notify(error.message,'error');
},
'unexpected_error': function(error) {
console.log(error);
reportUnexpectedError(error);
}
}
}
@@ -1782,11 +1846,12 @@ RED.projects = (function() {
RED.actions.add("core:new-project",RED.projects.newProject);
RED.actions.add("core:open-project",RED.projects.selectProject);
RED.actions.add("core:show-project-settings",RED.projects.settings.show);
var projectsAPI = {
sendRequest:sendRequest,
createBranchList:createBranchList,
addSpinnerOverlay:addSpinnerOverlay
addSpinnerOverlay:addSpinnerOverlay,
reportUnexpectedError:reportUnexpectedError
};
RED.projects.settings.init(projectsAPI);
RED.projects.userSettings.init(projectsAPI);

View File

@@ -30,7 +30,6 @@ RED.sidebar.versionControl = (function() {
var unmergedContent;
var unmergedChangesList;
var commitButton;
var mergeConflictNotification;
var localChanges;
var localCommitList;
@@ -51,10 +50,6 @@ RED.sidebar.versionControl = (function() {
// done(error,null);
},
200: function(data) {
if (mergeConflictNotification) {
mergeConflictNotification.close();
mergeConflictNotification = null;
}
var title;
if (state === 'unstaged') {
title = 'Unstaged changes : '+entry.file
@@ -80,6 +75,11 @@ RED.sidebar.versionControl = (function() {
options.oldRev = "@";
options.newRev = ":0";
} else {
options.oldRevTitle = "Local";
options.newRevTitle = "Remote";
options.commonRev = ":1";
options.oldRev = ":2";
options.newRev = ":3";
options.onresolve = function(resolution) {
utils.sendRequest({
url: "projects/"+activeProject.name+"/resolve/"+encodeURIComponent(entry.file),
@@ -102,9 +102,7 @@ RED.sidebar.versionControl = (function() {
},{resolutions:resolution.resolutions[entry.file]});
}
}
options.oncancel = showMergeConflictNotification;
RED.diff.showUnifiedDiff(options);
// console.log(data.diff);
},
400: {
'unexpected_error': function(error) {
@@ -122,6 +120,18 @@ RED.sidebar.versionControl = (function() {
if (entry.label) {
row.addClass('node-info-none');
container.text(entry.label);
if (entry.button) {
container.css({
display: "inline-block",
maxWidth: "300px",
textAlign: "left"
})
var toolbar = $('<div style="float: right; margin: 5px; height: 50px;"></div>').appendTo(container);
$('<button class="editor-button editor-button-small"></button>').text(entry.button.label)
.appendTo(toolbar)
.click(entry.button.click);
}
return;
}
@@ -144,6 +154,7 @@ RED.sidebar.versionControl = (function() {
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to revert the changes to '"+entry.file+"'? This cannot be undone.", {
type: "warning",
@@ -178,7 +189,12 @@ RED.sidebar.versionControl = (function() {
}
}
}
utils.sendRequest(options);
RED.deploy.setDeployInflight(true);
utils.sendRequest(options).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
}
}
@@ -352,6 +368,7 @@ RED.sidebar.versionControl = (function() {
evt.stopPropagation();
var spinner = utils.addSpinnerOverlay(unmergedContent);
var activeProject = RED.projects.getActiveProject();
RED.deploy.setDeployInflight(true);
utils.sendRequest({
url: "projects/"+activeProject.name+"/merge",
type: "DELETE",
@@ -369,6 +386,10 @@ RED.sidebar.versionControl = (function() {
}
},
}
}).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
});
unmergedChangesList = $("<ol>",{style:"position: absolute; top: 30px; bottom: 0; right:0; left:0;"}).appendTo(unmergedContent);
@@ -376,6 +397,16 @@ RED.sidebar.versionControl = (function() {
addButton: false,
scrollOnAdd: false,
addItem: function(row,index,entry) {
if (entry === emptyMergedItem) {
entry.button = {
label: 'commit',
click: function(evt) {
evt.preventDefault();
evt.stopPropagation();
showCommitBox();
}
}
}
createChangeEntry(row,entry,entry.treeStatus,'unmerged');
},
sort: function(A,B) {
@@ -395,28 +426,32 @@ RED.sidebar.versionControl = (function() {
header = $('<div class="sidebar-version-control-change-header">Changes to commit</div>').appendTo(stagedContent);
bg = $('<div style="float: right"></div>').appendTo(header);
var showCommitBox = function() {
commitMessage.val("");
submitCommitButton.attr("disabled",true);
unstagedContent.css("height","30px");
if (unmergedContent.is(":visible")) {
unmergedContent.css("height","30px");
stagedContent.css("height","calc(100% - 60px - 175px)");
} else {
stagedContent.css("height","calc(100% - 30px - 175px)");
}
commitBox.show();
setTimeout(function() {
commitBox.css("height","175px");
},10);
stageAllButton.attr("disabled",true);
unstageAllButton.attr("disabled",true);
commitButton.attr("disabled",true);
abortMergeButton.attr("disabled",true);
commitMessage.focus();
}
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">commit</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
evt.stopPropagation();
commitMessage.val("");
submitCommitButton.attr("disabled",true);
unstagedContent.css("height","30px");
if (unmergedContent.is(":visible")) {
unmergedContent.css("height","30px");
stagedContent.css("height","calc(100% - 60px - 175px)");
} else {
stagedContent.css("height","calc(100% - 30px - 175px)");
}
commitBox.show();
setTimeout(function() {
commitBox.css("height","175px");
},10);
stageAllButton.attr("disabled",true);
unstageAllButton.attr("disabled",true);
commitButton.attr("disabled",true);
commitMessage.focus();
showCommitBox();
});
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> all</button>')
.appendTo(bg)
@@ -445,7 +480,7 @@ RED.sidebar.versionControl = (function() {
commitBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-bottom"></div>').hide().appendTo(localChanges.content);
var commitMessage = $('<textarea>')
var commitMessage = $('<textarea placeholder="Enter your commit message"></textarea>')
.appendTo(commitBox)
.on("change keyup paste",function() {
submitCommitButton.attr('disabled',$(this).val().trim()==="");
@@ -467,6 +502,8 @@ RED.sidebar.versionControl = (function() {
stageAllButton.attr("disabled",false);
unstageAllButton.attr("disabled",false);
commitButton.attr("disabled",false);
abortMergeButton.attr("disabled",false);
})
var submitCommitButton = $('<button class="editor-button">Commit</button>')
.appendTo(commitToolbar)
@@ -474,6 +511,7 @@ RED.sidebar.versionControl = (function() {
evt.preventDefault();
var spinner = utils.addSpinnerOverlay(submitCommitButton).addClass('projects-dialog-spinner-sidebar');
var activeProject = RED.projects.getActiveProject();
RED.deploy.setDeployInflight(true);
utils.sendRequest({
url: "projects/"+activeProject.name+"/commit",
type: "POST",
@@ -487,17 +525,18 @@ RED.sidebar.versionControl = (function() {
refresh(true);
},
400: {
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
}
},
}
},{
message:commitMessage.val()
});
}).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
})
})
@@ -511,7 +550,7 @@ RED.sidebar.versionControl = (function() {
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
refresh(true);
refresh(true,true);
})
var localBranchToolbar = $('<div class="sidebar-version-control-change-header" style="text-align: right;"></div>').appendTo(localHistory.content);
@@ -749,7 +788,13 @@ RED.sidebar.versionControl = (function() {
},
400: {
'git_connection_failed': function(error) {
RED.notify(error.message);
RED.notify(error.message,'error');
},
'git_not_a_repository': function(error) {
RED.notify(error.message,'error');
},
'git_repository_not_found': function(error) {
RED.notify(error.message,'error');
},
'unexpected_error': function(error) {
console.log(error);
@@ -854,54 +899,87 @@ RED.sidebar.versionControl = (function() {
});
});
var pullRemote = function(options) {
options = options || {};
var spinner = utils.addSpinnerOverlay(remoteBox).addClass("projects-dialog-spinner-contain");
var activeProject = RED.projects.getActiveProject();
var url = "projects/"+activeProject.name+"/pull";
if (activeProject.git.branches.remoteAlt) {
url+="/"+activeProject.git.branches.remoteAlt;
}
if (options.setUpstream || options.allowUnrelatedHistories) {
url+="?";
}
if (options.setUpstream) {
url += "setUpstream=true"
if (options.allowUnrelatedHistories) {
url += "&";
}
}
if (options.allowUnrelatedHistories) {
url += "allowUnrelatedHistories=true"
}
utils.sendRequest({
url: url,
type: "POST",
responses: {
0: function(error) {
console.log(error);
// done(error,null);
},
200: function(data) {
refresh(true);
closeRemoteBox();
},
400: {
'git_local_overwrite': function(err) {
RED.notify("<p>Unable to pull remote changes; your unstaged local changes would be overwritten.</p><p>Commit your changes and try again.</p>"+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000);
},
'git_pull_merge_conflict': function(err) {
refresh(true);
closeRemoteBox();
},
'git_connection_failed': function(err) {
RED.notify("Could not connect to remote repository: "+err.toString(),"warning")
},
'git_pull_unrelated_history': function(error) {
var notification = RED.notify("<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",{
type: 'error',
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
notification.close();
}
},{
text: 'Pull changes',
click: function() {
notification.close();
options.allowUnrelatedHistories = true;
pullRemote(options)
}
}
]
});
},
'*': function(error) {
utils.reportUnexpectedError(error);
}
},
}
},{}).always(function() {
spinner.remove();
});
}
$('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span>pull</span></button>')
.appendTo(row)
.click(function(e) {
e.preventDefault();
var spinner = utils.addSpinnerOverlay(remoteBox).addClass("projects-dialog-spinner-contain");
var activeProject = RED.projects.getActiveProject();
var url = "projects/"+activeProject.name+"/pull";
if (activeProject.git.branches.remoteAlt) {
url+="/"+activeProject.git.branches.remoteAlt;
}
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
url+="?u=true"
}
utils.sendRequest({
url: url,
type: "POST",
responses: {
0: function(error) {
console.log(error);
// done(error,null);
},
200: function(data) {
refresh(true);
closeRemoteBox();
},
400: {
'git_local_overwrite': function(err) {
RED.notify("Unable to pull remote changes; your unstaged local changes would be overwritten. Commit your changes and try again."+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000);
},
'git_pull_merge_conflict': function(err) {
refresh(true);
},
'git_connection_failed': function(err) {
RED.notify("Could not connect to remote repository: "+err.toString(),"warning")
},
'unexpected_error': function(error) {
console.log(error);
// done(error,null);
},
'git_pull_unrelated_history': function(error) {
RED.notify("Unable to pull remote changes; refusing to merge unrelated histories.","error");
}
},
}
},{}).always(function() {
spinner.remove();
pullRemote({
setUpstream: $("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')
});
});
@@ -1039,16 +1117,6 @@ RED.sidebar.versionControl = (function() {
// }
// }
function showMergeConflictNotification() {
if (isMerging) {
mergeConflictNotification = RED.notify("NLS: Automatic merging of remote changes failed. Fix the unmerged conflicts then commit the results."+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show merge conflicts'+'</a></p>',"error",true);
}
}
function refreshFiles(result) {
var files = result.files;
if (bulkChangeSpinner) {
@@ -1057,16 +1125,9 @@ RED.sidebar.versionControl = (function() {
}
isMerging = !!result.merging;
if (isMerging) {
if (!mergeConflictNotification) {
showMergeConflictNotification();
}
sidebarContent.addClass("sidebar-version-control-merging");
unmergedContent.show();
} else {
if (mergeConflictNotification) {
mergeConflictNotification.close();
mergeConflictNotification = null;
}
sidebarContent.removeClass("sidebar-version-control-merging");
unmergedContent.hide();
}
@@ -1173,7 +1234,7 @@ RED.sidebar.versionControl = (function() {
}
}
function refresh(full) {
function refresh(full, includeRemote) {
if (refreshInProgress) {
return;
}
@@ -1193,7 +1254,11 @@ RED.sidebar.versionControl = (function() {
var activeProject = RED.projects.getActiveProject();
if (activeProject) {
$.getJSON("projects/"+activeProject.name+"/status",function(result) {
var url = "projects/"+activeProject.name+"/status";
if (includeRemote) {
url += "?remote=true"
}
$.getJSON(url,function(result) {
refreshFiles(result);
$('#sidebar-version-control-local-branch').text(result.branches.local);
@@ -1237,6 +1302,8 @@ RED.sidebar.versionControl = (function() {
}
refreshInProgress = false;
$('.sidebar-version-control-shade').hide();
}).fail(function() {
refreshInProgress = false;
});
} else {
$('.sidebar-version-control-shade').show();

View File

@@ -476,7 +476,7 @@ RED.utils = (function() {
for (i=0;i<keys.length;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
var newPath = path;
if (newPath) {
if (newPath !== undefined) {
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(keys[i])) {
newPath += (newPath.length > 0?".":"")+keys[i];
} else {
@@ -708,7 +708,9 @@ RED.utils = (function() {
function getDefaultNodeIcon(def,node) {
var icon_url;
if (typeof def.icon === "function") {
if (node && node.type === "subflow") {
icon_url = "node-red/subflow.png";
} else if (typeof def.icon === "function") {
try {
icon_url = def.icon.call(node);
} catch(err) {
@@ -721,11 +723,26 @@ RED.utils = (function() {
var iconPath = separateIconPath(icon_url);
if (!iconPath.module) {
iconPath.module = def.set.module;
if (def.set) {
iconPath.module = def.set.module;
} else {
// Handle subflow instance nodes that don't have def.set
iconPath.module = "node-red";
}
}
return iconPath;
}
function isIconExists(iconPath) {
var iconSets = RED.nodes.getIconSets();
var iconFileList = iconSets[iconPath.module];
if (iconFileList && iconFileList.indexOf(iconPath.file) !== -1) {
return true;
} else {
return false;
}
}
function getNodeIcon(def,node) {
if (def.category === 'config') {
return "icons/node-red/cog.png"
@@ -733,18 +750,19 @@ RED.utils = (function() {
return "icons/node-red/subflow.png"
} else if (node && node.type === 'unknown') {
return "icons/node-red/alert.png"
} else if (node && node.type === 'subflow') {
return "icons/node-red/subflow.png"
} else if (node && node.icon) {
var iconPath = separateIconPath(node.icon);
var iconSets = RED.nodes.getIconSets();
var iconFileList = iconSets[iconPath.module];
if (iconFileList && iconFileList.indexOf(iconPath.file) !== -1) {
if (isIconExists(iconPath)) {
return "icons/" + node.icon;
}
}
var iconPath = getDefaultNodeIcon(def, node);
if (def.category === 'subflows') {
if (!isIconExists(iconPath)) {
return "icons/node-red/subflow.png";
}
}
return "icons/"+iconPath.module+"/"+iconPath.file;
}

View File

@@ -490,6 +490,7 @@ RED.view = (function() {
}
} else {
var subflow = RED.nodes.subflow(m[1]);
nn.name = "";
nn.inputs = subflow.in.length;
nn.outputs = subflow.out.length;
}

View File

@@ -43,7 +43,7 @@ RED.workspaces = (function() {
return ws;
}
function deleteWorkspace(ws) {
if (workspace_tabs.count() == 1) {
if (workspaceTabCount === 1) {
return;
}
removeWorkspace(ws);
@@ -65,7 +65,7 @@ RED.workspaces = (function() {
buttons: [
{
id: "node-dialog-delete",
class: 'leftButton'+((workspace_tabs.count() == 1)?" disabled":""),
class: 'leftButton'+((workspaceTabCount === 1)?" disabled":""),
text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>',
click: function() {
deleteWorkspace(workspace);
@@ -214,6 +214,7 @@ RED.workspaces = (function() {
var workspace_tabs;
var workspaceTabCount = 0;
function createWorkspaceTabs() {
workspace_tabs = RED.tabs.create({
id: "workspace-tabs",
@@ -240,18 +241,24 @@ RED.workspaces = (function() {
}
},
onadd: function(tab) {
if (tab.type === "tab") {
workspaceTabCount++;
}
$('<span class="workspace-disabled-icon"><i class="fa fa-ban"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label");
if (tab.disabled) {
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('workspace-disabled');
}
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() <= 1);
if (workspace_tabs.count() === 1) {
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
if (workspaceTabCount === 1) {
showWorkspace();
}
},
onremove: function(tab) {
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() <= 1);
if (workspace_tabs.count() === 0) {
if (tab.type === "tab") {
workspaceTabCount--;
}
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
if (workspaceTabCount === 0) {
hideWorkspace();
}
},
@@ -266,6 +273,7 @@ RED.workspaces = (function() {
addWorkspace();
}
});
workspaceTabCount = 0;
}
function showWorkspace() {
$("#workspace .red-ui-tabs").show()
@@ -334,7 +342,7 @@ RED.workspaces = (function() {
return workspace_tabs.contains(id);
},
count: function() {
return workspace_tabs.count();
return workspaceTabCount;
},
active: function() {
return activeWorkspace

View File

@@ -113,8 +113,8 @@
.debug-message-meta {
background: #fff;
font-size: 10px;
color: #777;
font-size: 11px;
color: #707070;
}
.debug-message-date {
padding: 1px 5px 1px 1px;
@@ -125,7 +125,7 @@
}
.debug-message-name {
padding: 1px 5px;
color: #777;
color: #707070;
}
.debug-message-tools {
position: absolute;
@@ -159,7 +159,7 @@
.debug-message-element {
color: #333;
font-family: Menlo, monospace;
font-size: 12px !important;
font-size: 13px !important;
line-height: 1.3em;
}
.debug-message-object-key {
@@ -188,11 +188,9 @@
.debug-message-element.collapsed>span>.debug-message-object-handle {
transform: rotate(0deg);
}
.debug-message-object-entry.collapsed > .debug-message-object-entry {
display:none;
}
.debug-message-element.collapsed .debug-message-object-entry {
display:none;
}
@@ -202,14 +200,13 @@
.debug-message-element.collapsed .debug-message-buffer-opts {
display: none;
}
.debug-message-element.collapsed .debug-message-object-type-header {
display:none;
}
.debug-message-object-entry pre {
font-family: Menlo, monospace;
font-size: 12px;
line-height: 1.4em;
font-size: 13px;
line-height: 1.2em;
margin: 0 0 0 -1em;
}

View File

@@ -16,17 +16,16 @@
.node-dialog-view-diff-panel {
padding: 5px;
padding-top: 30px;
position: relative;
.red-ui-editableList-container {
border-radius:1px;
padding:0;
background: #f9f9f9;
}
.node-dialog-view-diff-diff {
position: absolute;
top:30px;
bottom:10px;
left:10px;
right:10px;
li {
background: #f9f9f9;
padding: 0px;
@@ -38,21 +37,20 @@
padding: 5px;
// padding-bottom: 5px;
}
&.node-dialog-view-diff-panel-merge {
.node-dialog-view-diff-diff {
top: 80px
}
.node-dialog-view-diff-headers {
top: 55px;
}
}
}
.node-diff-container {
position: absolute;
top: 40px;
right:0;
bottom: 0;
left: 0;
overflow-y: scroll;
}
.node-dialog-view-diff-headers {
position: absolute;
left:237px;
right:18px;
left:232px;
right:12px;
top: 5px;
height: 25px;
div {
@@ -76,11 +74,6 @@
}
.node-diff-toolbar {
position:absolute;
top:0;
left:0;
right:0;
height: 43px;
box-sizing: border-box;
color: #666;
text-align: right;
@@ -555,129 +548,129 @@ ul.node-dialog-configm-deploy-list {
.node-text-diff {
height: 100%;
overflow-y:auto;
table {
table.node-text-diff-content {
margin: 10px;
border: 1px solid $secondary-border-color;
border-radius: 3px;
table-layout: fixed;
width: calc(100% - 20px);
}
td {
vertical-align: top;
word-wrap: break-word;
}
td.lineno {
font-family: monospace;
text-align: right;
color: #aaa;
background: #f6f6f6;
padding: 1px 5px;
}
td.lineno:nth-child(3) {
border-left: 1px solid $secondary-border-color;
}
td.linetext {
font-family: monospace;
white-space: pre-wrap;
padding: 1px 5px;
span.prefix {
width: 30px;
display: inline-block;
text-align: center;
color: #999;
td {
vertical-align: top;
word-wrap: break-word;
}
}
td.blank {
background: #f6f6f6;
}
td.added {
background: #eefaee;
}
td.removed {
background: #fadddd;
}
tr.mergeHeader td {
color: #800080;
background: #e5f9ff;
height: 26px;
vertical-align: middle;
}
tr.mergeHeader-separator td {
color: #800080;
background: darken(#e5f9ff, 10%);
height: 0px;
}
tr.mergeHeader-ours td {
border-top: 2px solid darken(#e5f9ff, 10%);
}
tr.mergeHeader-theirs td {
border-bottom: 2px solid darken(#e5f9ff, 10%);
}
td.unchanged {
color: #999;
}
tr.unchanged {
background: #fefefe;
}
tr.start-block {
border-top: 1px solid #f0f0f0;
}
tr.end-block {
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-file-header td {
.filename {
td.lineno {
font-family: monospace;
text-align: right;
color: #aaa;
background: #f6f6f6;
padding: 1px 5px;
}
background: #f3f3f3;
padding: 5px 10px 5px 0;
color: #333;
cursor: pointer;
i.node-diff-chevron {
width: 30px;
td.lineno:nth-child(3) {
border-left: 1px solid $secondary-border-color;
}
}
tr.node-text-diff-file-header.collapsed {
td i.node-diff-chevron {
transform: rotate(-90deg);
td.linetext {
font-family: monospace;
white-space: pre-wrap;
padding: 1px 5px;
span.prefix {
width: 30px;
display: inline-block;
text-align: center;
color: #999;
}
}
}
tr.node-text-diff-commit-header td {
background: #f3f3f3;
padding: 5px 10px;
color: #333;
h3 {
font-size: 1.4em;
margin: 0;
td.blank {
background: #f6f6f6;
}
.commit-summary {
border-top: 1px solid $secondary-border-color;
padding-top: 5px;
td.added {
background: #eefaee;
}
td.removed {
background: #fadddd;
}
tr.mergeHeader td {
color: #800080;
background: #e5f9ff;
height: 26px;
vertical-align: middle;
}
tr.mergeHeader-separator td {
color: #800080;
background: darken(#e5f9ff, 10%);
height: 0px;
}
tr.mergeHeader-ours td {
border-top: 2px solid darken(#e5f9ff, 10%);
}
tr.mergeHeader-theirs td {
border-bottom: 2px solid darken(#e5f9ff, 10%);
}
td.unchanged {
color: #999;
}
.commit-body {
margin-bottom:15px;
white-space: pre;
line-height: 1.2em;
tr.unchanged {
background: #fefefe;
}
tr.start-block {
border-top: 1px solid #f0f0f0;
}
tr.end-block {
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-file-header td {
.filename {
font-family: monospace;
}
background: #f3f3f3;
padding: 5px 10px 5px 0;
color: #333;
cursor: pointer;
i.node-diff-chevron {
width: 30px;
}
}
tr.node-text-diff-file-header.collapsed {
td i.node-diff-chevron {
transform: rotate(-90deg);
}
}
tr.node-text-diff-commit-header td {
background: #f3f3f3;
padding: 5px 10px;
color: #333;
h3 {
font-size: 1.4em;
margin: 0;
}
.commit-summary {
border-top: 1px solid $secondary-border-color;
padding-top: 5px;
color: #999;
}
.commit-body {
margin-bottom:15px;
white-space: pre;
line-height: 1.2em;
}
}
tr.node-text-diff-header > td:not(.flow-diff) {
font-family: monospace;
padding: 5px 10px;
text-align: left;
color: #666;
background: #ffd;
height: 30px;
vertical-align: middle;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-expand td {
cursor: pointer;
&:hover {
background: #ffc;
}
}
}
tr.node-text-diff-header td {
font-family: monospace;
padding: 5px 10px;
text-align: left;
color: #666;
background: #ffd;
height: 30px;
vertical-align: middle;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-expand td {
cursor: pointer;
&:hover {
background: #ffc;
}
}
}

View File

@@ -501,9 +501,9 @@
top: 4px;
right: 4px;
display: none;
}
button {
width: 24px;
button {
width: 24px;
}
}
&:hover {

View File

@@ -64,9 +64,10 @@
vertical-align: middle;
color: #555;
i {
position:relative;
top:-3px;
margin-right:4px;
position: relative;
top: -3px;
margin-left: 1px;
margin-right: 2px;
margin-top: 1px;
vertical-align: middle;
&.fa-ellipsis-h {

View File

@@ -138,7 +138,7 @@
icon: "arrow-in.png",
align: "right",
label: function() {
return this.name||this.command;
return this.name||this.command||(this.useSpawn=="true"?this._("exec.spawn"):this._("exec.exec"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -65,6 +65,8 @@ module.exports = function(RED) {
"log:__node__.log,"+
"error:__node__.error,"+
"warn:__node__.warn,"+
"debug:__node__.debug,"+
"trace:__node__.trace,"+
"on:__node__.on,"+
"status:__node__.status,"+
"send:function(msgs){ __node__.send(__msgid__,msgs);}"+
@@ -91,6 +93,12 @@ module.exports = function(RED) {
warn: function() {
node.warn.apply(node, arguments);
},
debug: function() {
node.debug.apply(node, arguments);
},
trace: function() {
node.trace.apply(node, arguments);
},
send: function(id, msgs) {
sendResults(node, id, msgs);
},

View File

@@ -99,7 +99,7 @@
outputs:1,
icon: "template.png",
label: function() {
return this.name;
return this.name||this._("template.template");;
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -50,6 +50,7 @@ module.exports = function(RED) {
// try node context:
var dot = name.indexOf(".");
/* istanbul ignore else */
if (dot > 0) {
var contextName = name.substr(0, dot);
var variableName = name.substr(dot + 1);
@@ -61,7 +62,8 @@ module.exports = function(RED) {
return this.nodeContext.global.get(variableName);
}
}
}catch(err) {
}
catch(err) {
throw err;
}
}
@@ -87,24 +89,27 @@ module.exports = function(RED) {
* Allow template contents to be defined externally
* through inbound msg.template IFF node.template empty
*/
var template = node.template;
if (msg.hasOwnProperty("template")) {
if (node.template == "" || node.template === null) {
node.template = msg.template;
if (template == "" || template === null) {
template = msg.template;
}
}
if (node.syntax === "mustache") {
if (node.outputFormat === "json") {
value = mustache.render(node.template,new NodeContext(msg, node.context(), null, true));
value = mustache.render(template,new NodeContext(msg, node.context(), null, true));
} else {
value = mustache.render(node.template,new NodeContext(msg, node.context(), null, false));
value = mustache.render(template,new NodeContext(msg, node.context(), null, false));
}
} else {
value = node.template;
value = template;
}
/* istanbul ignore else */
if (node.outputFormat === "json") {
value = JSON.parse(value);
}
/* istanbul ignore else */
if (node.outputFormat === "yaml") {
value = yaml.load(value);
}
@@ -117,7 +122,8 @@ module.exports = function(RED) {
node.context().global.set(node.field,value);
}
node.send(msg);
} catch(err) {
}
catch(err) {
node.error(err.message);
}
});

View File

@@ -108,7 +108,7 @@
outstanding messages held by the node are cleared without being sent.</dd>
</dl>
<h3>Details</h3>
<p>When configured to delay messages, the delay interval can be a fixed value
<p>When configured to delay messages, the delay interval can be a fixed value,
a random value within a range or dynamically set for each message.</p>
<p>When configured to rate limit messages, their delivery is spread across
the configured time period. The status shows the number of messages currently in the queue.

View File

@@ -100,8 +100,6 @@ module.exports = function(RED) {
msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg);
}
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
if (node.duration === 0) { node.topics[topic].tout = 0; }
else if (node.loop === true) {
/* istanbul ignore else */
@@ -113,21 +111,25 @@ module.exports = function(RED) {
}
}
else {
node.topics[topic].tout = setTimeout(function() {
var msg2 = null;
if (node.op2type !== "nul") {
msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") {
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
if (!node.topics[topic].tout) {
node.topics[topic].tout = setTimeout(function() {
var msg2 = null;
if (node.op2type !== "nul") {
msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") {
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
}
msg2.payload = node.topics[topic].m2;
delete node.topics[topic];
node.send(msg2);
}
msg2.payload = node.topics[topic].m2;
}
delete node.topics[topic];
node.status({});
node.send(msg2);
}, node.duration);
else { delete node.topics[topic]; }
node.status({});
}, node.duration);
}
}
node.status({fill:"blue",shape:"dot",text:" "});
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
}
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
/* istanbul ignore else */

View File

@@ -33,7 +33,7 @@
outputs:0,
icon: "comment.png",
label: function() {
return this.name||"";
return this.name||this._("comment.comment");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -222,7 +222,6 @@ RED.debug = (function() {
clearMessageList(false);
});
return {
content: content,
footer: footerToolbar
@@ -238,6 +237,9 @@ RED.debug = (function() {
workspaceOrder.forEach(function(ws,i) {
workspaceOrderMap[ws] = i;
});
candidateNodes = candidateNodes.filter(function(node) {
return workspaceOrderMap.hasOwnProperty(node.z);
})
candidateNodes.sort(function(A,B) {
var wsA = workspaceOrderMap[A.z];
var wsB = workspaceOrderMap[B.z];
@@ -339,7 +341,7 @@ RED.debug = (function() {
activeMenuMessage.clearPinned();
}},
null,
{id:"debug-message-menu-item-filter",label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
{id:"debug-message-menu-item-filter", label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
var candidateNodes = RED.nodes.filterNodes({type:'debug'});
candidateNodes.forEach(function(n) {
filteredNodes[n.id] = true;
@@ -361,6 +363,15 @@ RED.debug = (function() {
menuOptionMenu.on('mouseup', function() { $(this).hide() });
menuOptionMenu.appendTo("body");
}
var filterOptionDisabled = false;
var sourceNode = RED.nodes.node(sourceId);
if (sourceNode && sourceNode.type !== 'debug') {
filterOptionDisabled = true;
}
RED.menu.setDisabled('debug-message-menu-item-filter',filterOptionDisabled);
RED.menu.setDisabled('debug-message-menu-item-clear-filter',filterOptionDisabled);
var elementPos = button.offset();
menuOptionMenu.css({
top: elementPos.top+"px",

View File

@@ -179,7 +179,7 @@
<dt>payload <span class="property-type">number</span></dt>
<dd>the payload will be a 1 or a 0.</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd>the topic will be set to `pi/{the pin number}`.</dd>
<dd>the topic will be set to <code>pi/{the pin number}</code>.</dd>
</dl>
<h3>Details</h3>
<p>You may also enable the input pullup resistor or the pulldown resistor.</p>

View File

@@ -142,9 +142,9 @@ module.exports = function(RED) {
var limit = 1;
if (node.out === "pwm") { limit = 100; }
if ((out >= 0) && (out <= limit)) {
if (RED.settings.verbose) { node.log("out: "+msg.payload); }
if (RED.settings.verbose) { node.log("out: "+out); }
if (node.child !== null) {
node.child.stdin.write(msg.payload+"\n");
node.child.stdin.write(out+"\n");
node.status({fill:"green",shape:"dot",text:msg.payload.toString()});
}
else {

View File

@@ -75,7 +75,7 @@
<p>The node will listen on the configured path for requests of a particular type.
The path can be fully specified, such as <code>/user</code>, or include
named parameters that accept any value, such as <code>/user/:name</code>.
When named parameters are used, their actual value in a request can be accessed under `msg.req.params`.</p>
When named parameters are used, their actual value in a request can be accessed under <code>msg.req.params</code>.</p>
<p>For requests that include a body, such as a POST or PUT, the contents of
the request is made available as <code>msg.payload</code>.</p>
<p>If the content type of the request can be determined, the body will be parsed to

View File

@@ -88,6 +88,8 @@
<dt class="optional">rejectUnauthorized</dt>
<dd>If set to <code>true</code>, allows requests to be made to https sites that use
self signed certificates.</dd>
<dt class="optional">followRedirects</dt>
<dd>If set to <code>false</code> prevent following Redirect (HTTP 301).<code>true</code> by default</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
@@ -117,7 +119,7 @@
the response headers. The next node will then use those headers for its request - this
is not usually the right thing to do. If <code>msg.headers</code> property is left unchanged
between nodes, it will be ignored by the second node. To set custom headers, <code>msg.headers</code>
should first be deleted or reset to an empty object: `{}`.
should first be deleted or reset to an empty object: <code>{}</code>.
<h4>Cookie handling</h4>
<p>The <code>cookies</code> property passed to the node must be an object of name/value pairs.
The value can be either a string to set the value of the cookie or it can be an

View File

@@ -108,6 +108,9 @@ module.exports = function(RED) {
}
}
}
if (msg.hasOwnProperty('followRedirects')) {
opts.followRedirects = msg.followRedirects;
}
if (msg.cookies) {
var cookies = [];
if (opts.headers.hasOwnProperty('cookie')) {
@@ -263,9 +266,8 @@ module.exports = function(RED) {
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
}
node.send(msg);
node.status({});
node.send(msg);
}
});
});
@@ -280,8 +282,8 @@ module.exports = function(RED) {
node.error(err,msg);
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
node.send(msg);
node.status({fill:"red",shape:"ring",text:err.code});
node.send(msg);
});
if (payload) {
req.write(payload);

View File

@@ -59,7 +59,7 @@
outputs:1,
icon: "watch.png",
label: function() {
return this.name||this.files;
return this.name||this.files||this._("watch.watch");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -52,6 +52,7 @@ module.exports = function(RED) {
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
});
client.setKeepAlive(true,120000);
connectionPool[id] = client;
client.on('data', function (data) {
@@ -123,7 +124,8 @@ module.exports = function(RED) {
clearTimeout(reconnectTimeout);
if (!node.connected) { done(); }
});
} else {
}
else {
var server = net.createServer(function (socket) {
socket.setKeepAlive(true,120000);
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
@@ -184,6 +186,7 @@ module.exports = function(RED) {
node.log(err);
});
});
server.on('error', function(err) {
if (err) {
node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()}));
@@ -237,6 +240,7 @@ module.exports = function(RED) {
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
});
client.setKeepAlive(true,120000);
client.on('error', function (err) {
node.log(RED._("tcpin.errors.error",{error:err.toString()}));
});
@@ -288,7 +292,8 @@ module.exports = function(RED) {
if (!node.connected) { done(); }
});
} else if (node.beserver == "reply") {
}
else if (node.beserver == "reply") {
node.on("input",function(msg) {
if (msg._session && msg._session.type == "tcp") {
var client = connectionPool[msg._session.id];
@@ -314,7 +319,8 @@ module.exports = function(RED) {
}
}
});
} else {
}
else {
var connectedSockets = [];
node.status({text:RED._("tcpin.status.connections",{count:0})});
var server = net.createServer(function (socket) {

View File

@@ -70,8 +70,8 @@
}
},
"catch": {
"catch": "catch all",
"catchNodes": "catch (__number__)",
"catch": "catch: all",
"catchNodes": "catch: __number__",
"label": {
"source": "Catch errors from",
"node": "node",
@@ -86,8 +86,8 @@
}
},
"status": {
"status": "status (all)",
"statusNodes": "status (__number__)",
"status": "status: all",
"statusNodes": "status: __number__",
"label": {
"source": "Report status from",
"node": "node",
@@ -166,6 +166,8 @@
}
},
"exec": {
"exec": "exec",
"spawn": "spawn",
"label": {
"command": "Command",
"append": "Append",
@@ -195,6 +197,7 @@
"tip": "See the Info tab for help writing functions."
},
"template": {
"template": "template",
"label": {
"template": "Template",
"property": "Set property",
@@ -301,6 +304,7 @@
}
},
"comment": {
"comment": "comment",
"label": {
"title": "Title",
"body": "Body"
@@ -416,6 +420,7 @@
}
},
"watch": {
"watch": "watch",
"label": {
"files": "File(s)",
"recursive": "Watch sub-directories recursively"
@@ -542,6 +547,7 @@
}
},
"switch": {
"switch": "switch",
"label": {
"property": "Property",
"rule": "rule",
@@ -597,6 +603,7 @@
}
},
"range": {
"range": "range",
"label": {
"action": "Action",
"inputrange": "Map the input range",
@@ -763,7 +770,9 @@
"status": {
"stopped": "stopped",
"closed": "closed",
"not-running": "not running"
"not-running": "not running",
"not-available": "not available",
"na": "N/A : __value__"
},
"errors": {
"ignorenode": "Ignoring Raspberry Pi specific node",
@@ -782,6 +791,7 @@
}
},
"tail": {
"tail": "tail",
"label": {
"filename": "Filename",
"type": "File type",
@@ -835,6 +845,7 @@
"tip": "Tip: The filename should be an absolute path, otherwise it will be relative to the working directory of the Node-RED process."
},
"split": {
"split": "split",
"intro":"Split <code>msg.payload</code> based on type:",
"object":"<b>Object</b>",
"objectSend":"Send a message for each key/value pair",
@@ -846,6 +857,7 @@
"addname":" Copy key to "
},
"join":{
"join": "join",
"mode":{
"mode":"Mode",
"auto":"automatic",
@@ -892,6 +904,7 @@
}
},
"sort" : {
"sort": "sort",
"target" : "Sort",
"seq" : "message sequence",
"key" : "Key",
@@ -905,6 +918,7 @@
"clear" : "clear pending message in sort node"
},
"batch" : {
"batch": "batch",
"mode": {
"label" : "Mode",
"num-msgs" : "Group by number of messages",

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/x-red" data-help-name="sentiment">
<p>指定したプロパティ(デフォルトは<code>payload</code>)<code>sentiment</code></p>
<h3>出力</h3>
<dl class="message-properties">
<dt>sentiment <span class="property-type">オブジェクト</span></dt>
<dd>AFINN-111による感情分析の結果</dd>
<dt>sentiment.score <span class="property-type">数値</span></dt>
<dd>感情分析スコア</dd>
</dl>
<h3>入力</h3>
<dl class="message-properties">
<dt>overrides <span class="property-type">オブジェクト</span></dt>
<dd>単語スコアの上書きをするためのオブジェクト - <code>{ word:score,... }</code></dd>
</dl>
<h3>詳細</h3>
<p>ゼロ以上のスコアはポジティブゼロ以下はネガティブを意味します</p>
<p>スコアの範囲は通常-5から+5ですがより大きかったり小さかったりすることもあります</p>
<p>詳細は<a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a></p>
</script>

View File

@@ -0,0 +1,34 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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ードを用いることで指定したペイロード値を用いてフローを開始できますデフォルトのペイロード値は現在時刻のタイムスタンプを1970年1月1日からの経過ミリ秒で表現した値です</p>
<p>文字列数値論理値JavaScriptオブジェクトフロー/グローバルコンテキストの値などの送出も可能です</p>
<p> デフォルト設定ではエディタ内に表示されるボタンをクリックすることでノードを手動で起動できます指定間隔もしくはスケジュールに従ってメッセージを送出するように設定することも可能です</p>
<p>またフロー開始の際に一度だけメッセージを送出させることもできます</p>
<p><i>時間間隔</i>596(24)</p>
<p><b></b>:「<i>指定した時間間隔、日時</i><i>指定した日時</i>」オプションは標準的なcronシステムを内部で利用します。したがって「20分」という指定は、その時点から20分後ではなく、毎時きっかり、20分、40分を意味します。現時刻から20分毎を指定するには「<i>指定した時間間隔</i>オプションを用います</p>
<p><b></b>: function使</p>
</script>

View File

@@ -0,0 +1,36 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" 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>エラーを送出したードのID</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>デフォルトでは同じタブの全てのノードが送出したエラーをキャッチします特定のノードをキャッチ対象とすることも可能です</p>
<p>エラー発生時にはマッチするすべてのcatchードがメッセージを受け取ります</p>
<p>サブフロー内でエラーが送出された場合まずサブフロー内のcatchードで処理されます対応するノードが存在しない場合にはそのサブフローが配置されたタブにエラーを伝播して処理します</p>
<p>メッセージが<code>error</code><code>error</code><code>_error</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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>ステータスを表示したードのID</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,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/x-red" data-help-name="debug">
<p>サイドバーのデバッグタブに選択したメッセージプロパティの値を表示します設定によりランタイムログへの出力も可能ですデフォルトの表示対象は<code>msg.payload</code></p>
<h3>詳細</h3>
<p>デバッグサイドバーは受け取ったメッセージの階層構造を表示する機能を備えますこの機能によりメッセージの構造を容易に理解できます</p>
<p>JavaScriptオブジェクトと配列は必要に応じて折り畳んだり展開したりできますバッファオブジェクトを生データとして表示したり表現可能な場合に文字列として表示することも可能です</p>
<p>メッセージを受信した時刻送信ノードメッセージの型に関する情報をデバッグサイドバーに表示されたメッセージに付随して表示します送信元ードのIDを選択するとワークスペース内の対応ノードを確認できます</p>
<p>出力の有効/無効はノード上のボタンで切り替えられますフロー上で未使用のdebugードは無効化するか削除することを推奨します</p>
<p>全てのメッセージをランタイムログに送付もしくは(32文字の)短いデータをdebugードの下のステータステキストに表示することも可能です</p>
</script>

View File

@@ -0,0 +1,31 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="link in">
<p>フロー間に仮想的なリンクを作成します</p>
<h3>詳細</h3>
<p>任意のタブ上に存在する<code>link out</code></p>
<p>linkード間のリンクはlinkードを選択した場合にのみ表示されます他のタブへのリンクがある場合には仮想的なノードを表示しますこの仮想的ノードをクリックすると対応するタブに移動できます</p>
<p><b>: </b></p>
</script>
<script type="text/x-red" 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,75 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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ードのプロセスID</dd>
</dl>
<h3>出力</h3>
<ol class="node-ports">
<li>標準出力(stdout)
<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>返却コードオブジェクト(3番目の端子でも受取り可能)のコピー(execモードのみ)</dd>
</dl>
</li>
<li>標準エラー出力(stderr)
<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>返却コードオブジェクト(3番目の端子でも受取り可能)のコピー(execモードのみ)</dd>
</dl>
</li>
<li>返却コード(return code)
<dl class="message-properties">
<dt>payload <span class="property-type">オブジェクト</span></dt>
<dd>リターンコード<code>message</code><code>signal</code>(<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>使
標準出力および標準エラー出力へ出力を返すようにすることもできますこの場合通常1行毎に値を返しますコマンドの実行が完了すると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>"This is a single parameter"</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>ードが1つ以上のプロセスを実行している場合<code>msg.pid</code>PID</p>
<p><code>タイムアウト</code></p>
<p>ヒント: Pythonアプリケーションを実行する場合<code>-u</code></p>
</script>

View File

@@ -0,0 +1,43 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="function">
<p>受信メッセージに対して処理を行うJavaScriptコード(関数の本体)を定義します</p>
<p>入力メッセージは<code>msg</code>JavaScript</p>
<p><code>msg</code><code>msg.payload</code></p>
<p>通常コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します何も返却しない場合にはフロー実行を停止します</p>
<h3>詳細</h3>
<p>コードの書き方の詳細については<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a></p>
<h4>メッセージの送信</h4>
<p>フロー内の次ノードにメッセージを渡すためにはメッセージを返却するか<code>node.send(messages)</code></p>
<p>返却/sendの対象は次のとおりです:</p>
<ul>
<li>単一メッセージオブジェクト - 最初の出力に接続されたノードに渡されます</li>
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
</ul>
<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>
<p>catchードを用いてエラー処理が可能ですcatchードで処理させるためには<code>msg</code><code>node.error</code>:</p>
<pre>node.error("エラー",msg);</pre>
</script>

View File

@@ -0,0 +1,47 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="template">
<p>テンプレートに基づいてプロパティを設定します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">オブジェクト</span></dt>
<dd>テンプレートを生成するための情報を含むメッセージオブジェクト</dd>
<dt class="optional">template <span class="property-type">文字列</span></dt>
<dd><code>msg.payload</code></dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">オブジェクト</span></dt>
<dd>指定したテンプレートと入力メッセージのプロパティから生成した値を設定したメッセージ</dd>
</dl>
<h3>詳細</h3>
<p>このノードは<i><a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache</a></i>形式をデフォルトで利用しますが使用しないようにすることもできます</p>
<p>例えば
<pre>こんにちは{{payload.name}}さん今日は{{date}}です</pre>
<p>というテンプレートに対して
<pre>{
date: "月曜日"
payload: {
name: "山田",
}
}</pre>
<p>というメッセージを受信した場合</p>
<pre>こんにちは山田さん今日は月曜日です</pre>
<p>というプロパティが生成されます</p>
<p>フローコンテキストもしくはグローバルコンテキストのプロパティ値を使うこともできますそれぞれ<code>{{flow.名前}}</code><code>{{global.}}</code></p>
<p><b>: </b>デフォルトでは、<i>mustache</i>形式は置換対象のHTML要素をエスケープしますこれを抑止するには<code>{{{三重}}}</code>使</p>
</script>

View File

@@ -0,0 +1,30 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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>
</dl>
<h3>詳細</h3>
<p>メッセージを遅延させるように設定する場合遅延時間は固定値範囲内の乱数値メッセージ毎の動的な指定値のいずれかを指定できます</p>
<p>流量制御する場合メッセージは指定した時間間隔内に分散して送信しますキューに残っているメッセージ数はノードのステータスに表示されます受け取った中間メッセージを破棄することも可能です</p>
<p>流量制御は全てのメッセージに適用することも<code>msg.topic</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="trigger">
<p>メッセージの受信すると別のメッセージの送信を行います延長もしくは初期化が指定されていない場合には2つ目のメッセージを送信することもできます</p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">reset</dt>
<dd>このプロパティを持つメッセージを受け取ると仕掛かり中の待機や繰り返しをクリアしメッセージの送信は行いません</dd>
</dl>
<h3>詳細</h3>
<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>reset</code><code>payload</code></p>
<p>受信メッセージでリセットするまで一定間隔でメッセージを再送するように指定することもできます</p>
<p><code>msg.topic</code></p>
</script>

View File

@@ -0,0 +1,21 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="comment">
<p>フローにコメントを記述するために利用します</p>
<h3>詳細</h3>
<p>編集パネルはMarkdown形式を記入可能です入力したテキストは情報サイドパネルに表示されます</p>
</script>

View File

@@ -0,0 +1,24 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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,71 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="rpi-gpio in">
<p>Raspberry Piの入力ード入力ピンの状態に応じて0 または 1 の値を持つ<code>msg.payload</code></p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>ペイロードには0 または 1 が設定されます</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd>トピックには<code>pi/{ピン番号}</code></dd>
</dl>
<h3>詳細</h3>
<p>入力のプルアップ抵抗またはプルダウン抵抗を有効にすることもできます</p>
<p>動作にはRPi.GPIO pythonライブラリのバージョン 0.5.10 (またはそれ以上)が必要です</p>
</script>
<script type="text/x-red" data-help-name="rpi-gpio out">
<p>Raspberry Piの出力ードデジタルモードまたはPWMモードで利用できます
<h3>入力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値 | 文字列 | 真偽値</span></dt>
</dl>
<h3>詳細</h3>
<p>デジタルモード - <code>msg.payload</code> 0 1 ( true false ) </p>
<p>デプロイ時にピンの初期値として 0 または 1 を設定することもできます</p>
<p>PWMモード - 入力値に 0 から 100 の数値を指定でき小数値の指定も可能です</p>
<p>サーボの制御にPWMモードが利用でき入力に小数値も含む 10 から 20 の値が指定可能です
PWMを行うハードウェアを利用していることからPWMモードの指定にはGPIO2ピンが最も適しています
より良くサーボの制御を行いたい場合はnode-red-node-pi-gpiod ノードの利用も検討してください</p>
<p>動作にはRPi.GPIO pythonライブラリのバージョン 0.5.10 (またはそれ以上)が必要です</p>
</script>
<script type="text/x-red" data-help-name="rpi-mouse">
<p>Raspberry Pi のマウスボタンノードUSBマウスが必要です</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>選択されたマウスのボタンが押されたまたは離された場合に 1 または 0 が設定されます</dd>
<dt>button <span class="property-type">数値</span></dt>
<dd>真ん中のボタンに応じて 1, 2, 4 が設定されボタンあるいはボタンの組み合わせに応じた処理ができます</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd><code>pi/mouse</code></dd>
</dl>
</script>
<script type="text/x-red" data-help-name="rpi-keyboard">
<p>Raspberry Pi のキーボードを制御するノードUSBキーボードが必要です</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>キーコードを含みます</dd>
<dt>action <span class="property-type">文字列</span></dt>
<dd>"up", "down", または "repeat" が設定されます</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd><code>pi/key</code></dd>
</dl>
</script>

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/x-red" data-help-name="tls-config">
<p>TLS接続のためのオプション設定</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/x-red" 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度到着, 1: 一度以上到着, 2: 1度のみ到着</dd>
<dt>retain <span class="property-type">真偽値</span></dt>
<dd>真の場合メッセージを保持メッセージが古い値の場合があります</dd>
</dl>
<h3>詳細</h3>
<p>購読トピックにはMQTTのワイルドカード(+: 1レベル, #: 複数レベル)を含めることができます</p>
<p>このノードの利用のためにはMQTTブローカへの接続設定が必要ですこの設定は鉛筆アイコンをクリックすることで行えます</p>
<p>MQTT(inおよびout)ノードはブローカへの接続設定を必要に応じて共有できます</p>
</script>
<script type="text/x-red" 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">数値</span></dt>
<dd>0: 最大1度到着, 1: 一度以上到着, 2: 1度のみ到着デフォルトは0です</dd>
<dt class="optional">retain <span class="property-type">真偽値</span></dt>
<dd>真の場合メッセージをブローカに保持しますデフォルトは偽です</dd>
</dl>
<h3>詳細</h3>
<p><code>msg.payload</code>JSON</p>
<p>発行に利用するトピックはノードに設定するかもしくは<code>msg.topic</code></p>
<p>同様にQoSとretainもードの設定もしくはノードの設定が空の場合にはそれぞれ<code>msg.qos</code><code>msg.retain</code>retain</p>
<p>このノードの利用のためにはMQTTブローカへの接続設定が必要ですこの設定は鉛筆アイコンをクリックすることで行えます</p>
<p>MQTT(inおよびout)ノードはブローカへの接続設定を必要に応じて共有できます</p>
</script>
<script type="text/x-red" data-help-name="mqtt-broker">
<p>MQTTブローカへの接続設定</p>
<p>ブローカへの接続設定を作成します設定は<code>MQTT In</code><code>MQTT Out</code></p>
<p>ードにクライアントIDを設定しておらずセッションの初期化を設定している場合ランダムなクライアントIDを生成しますクライアントIDを設定する場合接続先のブローカで一意となるようにしてください</p>
<h4>Birthメッセージ</h4>
<p>接続を確立した際に設定したトピックに対して発行するメッセージ</p>
<h4>Willメッセージ</h4>
<p>予期せず接続が切断された場合にブローカが発行するメッセージ</p>
<h4>WebSocket</h4>
<p>WebSocketによる接続を行うように設定できますWebSocketを利用するにはサーバフィールドに接続先のURIを完全な形式で記述します以下に例を示します</p>
<pre>ws://example.com:4000/mqtt</pre>
</script>

View File

@@ -0,0 +1,81 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="http in">
<p>HTTPエンドポイントを作成しWebサービスを構成します</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レスポンスオブジェクトこのプロパティを直接利用することは推奨しませんリクエストの処理方法については<code>HTTP Response</code>response</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/x-red" data-help-name="http response">
<p>HTTP Inードで受け付けたリクエストに対するレスポンスを送り返します</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>以下の例では2つのクッキーを設定しています1つ目は<code>name</code><code>nick</code>2<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> - () GMT0</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,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/x-red" 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を設定します</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>true</code>使https</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>
</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>{{{...}}}使/&mustache</p>
<p><b></b>: proxy<code>http_proxy=...</code>Node-RED</p>
<h4>複数のHTTPリクエストードの利用</h4>
<p>同一フローで本ノードを複数利用するためには<code>msg.headers</code><code>msg.headers</code>2<code>msg.headers</code><code>{}</code>
<h4>クッキーの扱い</h4>
<p>ノードに<code>cookies</code>/<code>value</code><p>
<p>リクエストに対して返却されたクッキーは<code>responseCookies</code></p>
<h4>要素タイプの扱い</h4>
<p><code>msg.payload</code><code>msg.payload</code>JSON</p>
<p>リクエストをフォームデータにエンコードするには<code>msg.headers["content-type"]</code><code>application/x-www-form-urlencoded</code></p>
</script>

View File

@@ -0,0 +1,36 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="websocket in">
<p>WebSocket入力ード</p>
<p>デフォルトではWebSocketにより受信したデータは<code>msg.payload</code>JSONJSON</p>
</script>
<script type="text/x-red" data-help-name="websocket out">
<p>WebSocket出力ード</p>
<p>デフォルトでは<code>msg.payload</code>WebSocket<code>msg</code>JSONWebSocket</p>
<p>このードが受信したメッセージがWebSocket Inードが生成したものである場合メッセージはフローを起動したクライアントに送り返されますそれ以外の場合メッセージは接続している全てのクライアントにブロードキャストされます</p>
<p>WebSocket Inードが生成したメッセージをブロードキャストしたい場合にはフロー中で<code>msg._session</code></p>
</script>
<script type="text/x-red" data-help-name="websocket-listener">
<p>この設定ードはパスを指定してWebSocketサーバのエンドポイントを作成します</p>
</script>
<script type="text/x-red" data-help-name="websocket-client">
<p>この設定ードは指定したURLにWebSocketクライアントを接続します</p>
</script>

View File

@@ -0,0 +1,25 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="watch">
<p>ディレクトリもしくはファイルの変化を検知します</p>
<p>カンマ区切りでディレクトリおよびファイルのリストを指定します空白を含む場合は引用符で"..."のように囲んでください</p>
<p>Windowsでは2重バックスラッシュ\\をディレクトリ名に使用します</p>
<p>実際に変化したファイルのフルパス名を<code>msg.payload</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

@@ -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/x-red" data-help-name="tcp in">
<p>TCPからの入力を行いますリモートTCPポートに接続するか外部らからのコネクションを受け付けます</p>
<p><b>: </b>1024rootadministrator</p>
</script>
<script type="text/x-red" data-help-name="tcp out">
<p>TCPへの出力を行いますリモートTCPポートへ接続外部からのコネクションの受け付けもしくはTCP Inードで受け付けたメッセージへのリプライを行います</p>
<p><code>msg.payload</code></p>
<p><code>msg.payload</code>Base64Base64</p>
<p><code>msg._session</code><b></b></p>
<p><b>: </b>1024rootadministrator</p>
</script>
<script type="text/x-red" data-help-name="tcp request">
<p>シンプルなTCPリクエストード<code>msg.payload</code>TCP</p>
<p>サーバに接続"リクエスト"送信"レスポンス"受信を行います固定長の文字数指定文字へのマッチ最初のリプライの到着から指定した時間待つデータの到着待ちデータ送信を行いリプライを待たず接続を即時解除などから動作を選択できます</p>
<p>レスポンスはバッファ形式で<code>msg.payload</code>toString()使</p>
<p>TCPホストのポート番号設定を空にした場合<code>msg.host</code><code>msg.port</code></p>
</script>

View File

@@ -0,0 +1,28 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="udp in">
<p>UDP入力ード<code>msg.payload</code>Base64</p>
<p><code>msg.ip</code><code>msg.port</code>IP</p>
<p><b></b>: 1024rootadministrator</p>
</script>
<script type="text/x-red" 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>: 1024rootadministrator</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/x-red" data-help-name="switch">
<p>プロパティの値によってメッセージの振り分けを行います</p>
<h3>詳細</h3>
<p>受信したメッセージに対し指定されたルールを順に評価しマッチしたルールに対応する出力ポートにメッセージを送出します</p>
<p>最初にルールがマッチしたところで評価を止めることも可能です</p>
<p>評価ルールにはメッセージプロパティフローコンテキスト/グローバルコンテキストのプロパティJSONata式の評価結果が利用できます</p>
<h3>ルール</h3>
<p>振り分けルールは以下の4つに分類されます</p>
<ol>
<li><b>(value)</b> - </li>
<li><b>(sequence)</b> - (split)</li>
<li><b>JSONata式</b> - </li>
<li><b>その他</b> - </li>
</ol>
<h3>メッセージ列の扱い</h3>
<p>switchードは入力メッセージの列に関する情報を保持する<code>msg.parts</code></p>
<p><b>メッセージ列の補正</b>switch<code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="change">
<p>メッセージフローコンテキストグローバルコンテキストのプロパティを変更削除移動します</p>
<p>ルールを複数指定した場合定義した順に適用します</p>
<h3>詳細</h3>
<p>利用可能な処理</p>
<dl class="message-properties">
<dt>代入</dt>
<dd>プロパティをセットします設定値にはさまざまな型の値メッセージやコンテキストの既存プロパティを利用できます<dd>
<dt>置換</dt>
<dd>プロパティに対して検索と置換を行います正規表現を指定した場合置換後の文字列には<code>$1</code></dd>
<dt>削除</dt>
<dd>プロパティを削除します</dd>
<dt>移動</dt>
<dd>プロパティの移動または名前の変更を行います</dd>
</dl>
<p>expressionには<a href="http://jsonata.org/" target="_new">JSONata</a></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="range">
<p>数値を異なる範囲の値に変換します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<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>
</dl>
<h3>詳細</h3>
<p>このノードは受け取った数値を線形スケーリングしますデフォルトでは結果の値はノードに設定した範囲内に限定しません</p>
<p><i>入力値の範囲外の値を最小値/最大値として拡大/縮小</i></p>
<p><i>入力値の範囲外の値を範囲幅で割った余りとし拡大/縮小</i></p>
</script>

View File

@@ -0,0 +1,137 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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><code>parts</code>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
<li><code>type</code> - - ///</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>このノードはメッセージ列を再構成して送信する際にも有用です例えば改行終端のコマンドを送信するようなシリアルデバイスではメッセージの最後のコマンド部分が途切れたメッセージを送出する場合がありますストリームモードを用いることで完結した個別コマンドにメッセージを分割することができます入力メッセージの最後に未完部分がある場合<b>split</b></p>
<p>このモードで処理する際にはメッセージ数を予め知ることができないため<code>msg.parts.count</code><b>join</b></p>
</script>
<script type="text/x-red" data-help-name="join">
<p>メッセージ列を結合して一つのメッセージにします</p>
<p>メッセージの結合には次の3つのモードが利用できます</p>
<dl>
<dt>自動</dt>
<dd><b>split</b>split</dd>
<dt>手動</dt>
<dd>メッセージ列をさまざまな方法で結合します</dd>
<dt>列の集約</dt>
<dd>メッセージ列に対して指定した式を適用し1つのメッセージに集約します</dd>
</dl>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">parts<span class="property-type">オブジェクト</span></dt>
<dd>自動的にメッセージ列を結合するには全メッセージがこのプロパティを持っていなければなりません<b>split</b><code>parts</code>
<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>設定されている場合保持しているメッセージを結合して送信します</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>key/valueオブジェクト</b> - </li>
<li><b>統合オブジェクト</b> - </li>
</ul>
<p>出力メッセージのその他のプロパティはメッセージを送信する直前のメッセージをコピーします</p>
<p><i>合計値</i></p>
<p><i></i></p>
<p><code>msg.complete</code></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,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/x-red" data-help-name="sort">
<p>メッセージ列もしくは配列型のペイロードをソートします</p>
<p><b>split</b></p>
<p>ソート順序は以下が指定可能です</p>
<ul>
<li><b>昇順</b></li>
<li><b>降順</b></li>
</ul>
<p>数値による並べ替えを選択することもできます</p>
<p>メッセージの並べ替えを行うためのソートキーは<code>payload</code>JSONataJSONata</p>
<p>sortードの処理では受信したメッセージが<code>msg.parts</code>split<code>parts</code></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><b>settings.js</b><code>nodeMessageBufferMaxLength</code></li>
</ul>
</p>
</script>

View File

@@ -0,0 +1,34 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="batch">
<p>指定したルールによりメッセージ列を生成します</p>
<h3>詳細</h3>
<p>メッセージ列の生成には以下の3つのモードが利用できます</p>
<dl>
<dt>入力メッセージ数でグループ化</dt>
<dd>入力メッセージを指定した長さのメッセージ列にグループ化しますメッセージ列の最後の部分を次のメッセージ列の先頭で繰り返すメッセージ数を<b>オーバラップ</b></dd>
<dt>入力間隔()でグループ化</dt>
<dd>指定時間間隔内に受信した入力メッセージをメッセージ列にグループ化します指定した時間内にメッセージを受信しない場合に空のメッセージを送信するように設定することもできます</dd>
<dt>メッセージグループの結合</dt>
<dd>入力メッセージ列を結合し1つのメッセージ列にしますメッセージ列の識別のため各メッセージは<code>msg.topic</code><code>msg.parts</code><code>topic</code>batch
</dd>
</dl>
<h4>メッセージの蓄積</h4>
<p>このノードの処理ではメッセージ列の処理のためメッセージを内部に蓄積します<code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -234,7 +234,7 @@
"and": "回/",
"rate": "流量",
"msgper": "メッセージ/",
"dropmsg": "仲介メッセージを削除",
"dropmsg": "中間メッセージを削除",
"label": {
"delay": "delay",
"variable": "variable",

View File

@@ -0,0 +1,44 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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として解釈しCSVの各行をキー/バリューとしたJavaScriptオブジェクトを生成します
各行毎にメッセージを送信するかオブジェクトの配列からなる一つのメッセージを送信するかを選択できます</li>
<li>入力がJavaScriptオブジェクトの場合CSV文字列への変換を行います</li>
<li>入力が基本型の配列の場合1行のCSV文字列へ変換します</li>
<li>入力が配列の配列もしくはオブジェクトの配列の場合複数行のCSV文字列へ変換します</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>列名にカラム名のリストを指定することができますCSVからオブジェクトに変換を行う際カラム名をプロパティ名として使用します列名の代わりにCSVデータの1行目にカラム名を含めることもできます</p>
<p>CSVへの変換を行う際にはオブジェクトから取り出すべきプロパティとその順序を列名を参照して決めます</p>
<p>入力が配列の場合には列名はカラム名を表す行の出力指定がされた場合だけ用います</p>
<p><code>parts</code></p>
<p>CSVを複数のメッセージに変換して出力する場合出力がメッセージ列となるよう<code>parts</code></p>
<p><b>:</b> </p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="html">
<p><code>msg.payload</code>HTMLCSS使</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>編集パネルでセレクタを指定していない場合メッセージのプロパティとして設定できます</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">配列 | 文字列</span></dt>
<dd>結果はペイロードにマッチした要素の配列を含む単一メッセージもしくはマッチした要素毎のメッセージのいずれかを選択できます複数メッセージを送信する場合メッセージには<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 documentation</a></p>
</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/x-red" 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>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>
<ul>
<li>入力が文字列の場合JSONとして解釈しJavaScriptオブジェクトに変換します</li>
<li>入力がJavaScriptオブジェクトの場合JSON文字列に変換しますJSON文字列は整形することも可能です</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>デフォルトの変換対象は<code>msg.payload</code></p>
<p>双方向の変換を自動選択するのではなく特定の変換のみ行うように設定できますこの機能は例えば<code>HTTP In</code>content-typeJSONJavaScript</p>
<p>JSON文字列への変換が指定されている場合受信した文字列に対してさらなるチェックは行いませんすなわち文字列がJSONとして正しいかどうかの検査や整形オプションを指定していたとしても整形処理を実施しません</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/x-red" 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>
</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>
<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">the xml2js docs</a></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>
<pre>{
"p": {
"$": {
"class": "tag"
},
"_": "Hello World"
}
}</pre>
</script>

View File

@@ -0,0 +1,34 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="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,25 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="tail">
<p>設定したファイルの末尾を出力(追加されたデータを監視)します(Linux/Macのみ)</p>
<p>このノードは<b>tail -F</b>Windows</p>
<h3>出力</h3>
<ul>
<li>(UTF-8形式の)テキストファイルは文字列を返却</li>
<li>バイナルファイルはバッファオブジェクトを返却</li>
</ul>
</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/x-red" 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>入力メッセージのペイロードをファイルの最後に追記します改行(\n)を各データの最後に追加することもできます</p>
<p><code>msg.filename</code>使</p>
<p>追記を行う代わりにファイル全体を上書きするように設定することもできます例えば画像のようなバイナリデータをファイルに書き出す場合はこのオプションを指定し改行を追記するオプションを指定しないようにします</p>
<p>この他ファイルの削除を行うことも可能です</p>
</script>
<script type="text/x-red" 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>
<dt class="optional">error <span class="property-type">オブジェクト</span></dt>
<dd><i>非推奨</i>: <code>payload</code><code>error</code></dd>
</dl>
<h3>詳細</h3>
<p>ファイルネームは絶対パスでの指定を推奨します絶対パスを指定しない場合はNode-REDプロセスのワーキングディレクトリからの相対パスとして扱います</p>
<p>Windowsではパスの区切り文字を(例えば<code>\\ユーザー\\名前</code>)</p>
<p>テキストファイルの場合行毎に分割して各々メッセージを送信することができますまたバイナリファイルの場合小さな塊のバッファに分割して送信できますバッファの分割単位はオペレーティングシステム依存ですが一般に64k(Linux/Mac)もしくは41k(Windows)です</p>
<p>複数のメッセージに分割する場合各メッセージには<code>parts</code></p>
<h4>旧式のエラー処理</h4>
<p>Node-RED 0.17より前の版ではファイルの読み込み時にエラーが発生すると<code>payload</code><code>error</code></p>
<p>エラーはcatchードで補足して処理することを推奨します</p>
</script>

View File

@@ -5,7 +5,8 @@
"topic": "主题",
"name": "名称",
"username": "用户名",
"password": "密码"
"password": "密码",
"property": "属性"
},
"status": {
"connected": "已连接",
@@ -13,7 +14,7 @@
"disconnected": "已断开",
"connecting": "连接中",
"error": "错误",
"ok": "确"
"ok": "确"
},
"notification": {
"error": "<strong>错误</strong>: __message__",
@@ -37,17 +38,17 @@
"repeat": "重复"
},
"timestamp": "时间戳",
"none": "空白",
"interval": "间隔",
"interval-time": "定时间内间隔",
"time": "定时间",
"none": "",
"interval": "周期性执行",
"interval-time": "定时间段周期性执行",
"time": "定时间",
"seconds": "秒",
"minutes": "分钟",
"hours": "小时",
"between": "介于",
"previous": "之前数值",
"at": "在",
"and": "之间",
"and": "",
"every": "每隔",
"days": [
"星期一",
@@ -59,18 +60,20 @@
"星期天"
],
"on": "在",
"onstart": "运行时注入?",
"tip": "<b>注意:</b> \"特定时间内间隔\" 和 \"特定时间\" 会使用cron系统.<br/> 详情查看信息页.",
"onstart": "立刻执行于",
"onceDelay": "秒后, 此后",
"tip": "<b>注意:</b> \"指定时间段周期性执行\" 和 \"指定时间\" 会使用cron系统.<br/> 详情查看信息页.",
"success": "成功注入: __label__",
"errors": {
"failed": "注入失败, 请查看日志"
"failed": "注入失败, 请查看日志",
"toolong": "周期过长"
}
},
"catch": {
"catch": "检测异常",
"catchNodes": "检测到 (__number__)",
"catch": "监测所有节点",
"catchNodes": "监测__number__个节点",
"label": {
"source": "检测错误来自",
"source": "监测范围",
"node": "节点",
"type": "类型",
"selectAll": "全选",
@@ -79,14 +82,14 @@
},
"scope": {
"all": "所有节点",
"selected": "已选节点"
"selected": "指定节点"
}
},
"status": {
"status": "状态 (所有)",
"statusNodes": "状态显示 (__number__)",
"status": "报告所有节点状态",
"statusNodes": "报告__number__个节点状态",
"label": {
"source": "状态报告来自",
"source": "报告状态范围",
"node": "节点",
"type": "类型",
"selectAll": "全选",
@@ -95,7 +98,7 @@
},
"scope": {
"all": "所有节点",
"selected": "已选节点"
"selected": "指定节点"
}
},
"debug": {
@@ -104,7 +107,11 @@
"msgobj": "完整信息",
"to": "目标",
"debtab": "调试窗口",
"tabcon": "调试窗口及终端控制台",
"tabcon": "调试窗口及Console",
"toSidebar": "调试窗口",
"toConsole": "Console",
"toStatus": "节点状态 (32位字符)",
"severity": "级别",
"notification": {
"activated": "成功激活: __label__",
"deactivated": "成功取消: __label__"
@@ -114,21 +121,21 @@
"name": "名称",
"filterAll": "所有节点",
"filterSelected": "已选节点",
"filterCurrent": "前流程",
"filterCurrent": "前流程",
"debugNodes": "调试节点",
"clearLog": "清日志",
"clearLog": "清日志",
"openWindow": "在新窗口打开"
},
"messageMenu": {
"collapseAll": "折叠所有路径",
"clearPinned": "清已固定路径",
"clearPinned": "清已固定路径",
"filterNode": "过滤此节点",
"clearFilter": "清除已设过滤"
"clearFilter": "清空过滤条件"
}
},
"link": {
"linkIn": "连接入口",
"linkOut": "连接出口",
"linkIn": "输入",
"linkOut": "输出",
"label": {
"event": "事件名称",
"node": "节点名称",
@@ -144,16 +151,18 @@
"upload": "上传",
"cert": "证书",
"key": "私钥",
"passphrase": "密码",
"ca": "CA证书",
"verify-server-cert":"验证服务器证书"
},
"placeholder": {
"cert":"证书路径 (PEM 格式)",
"key":"私路径 (PEM 格式)",
"ca":"CA证书路径 (PEM 格式)"
"key":"私路径 (PEM 格式)",
"ca":"CA证书路径 (PEM 格式)",
"passphrase":"私钥密码 (可选)"
},
"error": {
"missing-file": "证书/密文件提供"
"missing-file": "未提供证书/密文件"
}
},
"exec": {
@@ -169,10 +178,10 @@
"extraparams": "额外的输入参数"
},
"opt": {
"exec": "当命令任务完成时 - exec 模式",
"spawn": "当命令任务进行时 - spawn 模式"
"exec": "当命令完成时 - exec模式",
"spawn": "当命令进行时 - spawn模式"
},
"oldrc": "使用旧式输出模式 (传统模式)"
"oldrc": "使用旧式输出 (兼容模式)"
},
"function": {
"label": {
@@ -180,7 +189,7 @@
"outputs": "输出"
},
"error": {
"inputListener":"无法在函数里面加入对‘注入事件的监视",
"inputListener":"无法在函数中监听对'注入'事件",
"non-message-returned":"函数节点尝试返回类型为 __type__ 的信息"
},
"tip": "可从信息页面查看更多关于如何编写函数的帮助"
@@ -194,7 +203,8 @@
"output": "输出为",
"mustache": "Mustache 模版",
"plain": "纯文本",
"json": "解析JSON",
"json": "JSON",
"yaml": "YAML",
"none": "无"
},
"templatevalue": "This is the payload: {{payload}} !"
@@ -204,13 +214,13 @@
"for": "时长",
"delaymsg": "延迟每一条信息",
"delayfixed": "固定延迟时间",
"delayvarmsg": "msg.delay写延迟时长",
"delayvarmsg": "允许msg.delay写延迟时长",
"randomdelay": "随机延迟",
"limitrate": "信息速度限制",
"limitrate": "限制信息速",
"limitall": "所有信息",
"limittopic": "每一个 msg.topic",
"fairqueue": "轮流发每一个主题",
"timedqueue": "发所有主题",
"limittopic": "每一个msg.topic",
"fairqueue": "依次发送每一个topic",
"timedqueue": "发所有topic",
"milisecs": "毫秒",
"secs": "秒",
"sec": "秒",
@@ -218,10 +228,10 @@
"min": "分",
"hours": "小时",
"hour": "小时",
"days": "",
"day": "",
"days": "",
"day": "",
"between": "介于",
"and": "",
"and": "",
"rate": "速度",
"msgper": "信息 每",
"dropmsg": "不传输中间信息",
@@ -245,14 +255,14 @@
"singular": "小时"
},
"day": {
"plural" : "",
"singular": ""
"plural" : "",
"singular": ""
}
}
},
"error": {
"buffer": "缓冲超过 1000 条信息",
"buffer1": "缓冲超过 10000 条信息"
"buffer": "缓冲超过 1000 条信息",
"buffer1": "缓冲超过 10000 条信息"
}
},
"trigger": {
@@ -267,9 +277,9 @@
"latest": "最新信息对象",
"nothing": "无"
},
"wait-reset": "等待重置",
"wait-reset": "等待重置",
"wait-for": "等待",
"wait-loop": "重发",
"wait-loop": "周期性重发",
"duration": {
"ms": "毫秒",
"s": "秒",
@@ -279,11 +289,11 @@
"extend": " 如有新信息,延长延迟",
"label": {
"trigger": "触发",
"trigger-block": "发并阻止",
"trigger-loop": "重发",
"trigger-block": "发并阻止",
"trigger-loop": "周期性重发",
"reset": "重置触发节点条件 如果:",
"resetMessage":"msg.reset 已设置",
"resetPayload":"msg.payload 等于",
"resetMessage":"msg.reset已设置",
"resetPayload":"msg.payload等于",
"resetprompt": "可选填"
}
},
@@ -292,7 +302,7 @@
"title": "标题",
"body": "主体"
},
"tip": "提示: 主题内容可以添加格式化为 <a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">Github 风格 Markdown</a>"
"tip": "提示: 主题内容可格式化为 <a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">Github风格Markdown</a>"
},
"unknown": {
"label": {
@@ -307,24 +317,24 @@
"qos": "QoS",
"clientid": "客户端ID",
"port": "端口",
"keepalive": "存货定时器(秒)",
"keepalive": "Keepalive计时(秒)",
"cleansession": "使用新的会话",
"use-tls": "使用安全连接 (SSL/TLS)",
"tls-config":"TLS 设置",
"verify-server-cert":"验证服务器证书",
"compatmode": "使用旧式 MQTT 3.1 支持"
"compatmode": "使用旧式MQTT 3.1支持"
},
"tabs-label": {
"connection": "连接",
"security": "安全",
"will": "终结信息",
"birth": "初始信息"
"will": "Will信息",
"birth": "Birth信息"
},
"placeholder": {
"clientid": "留空白将会自动生成",
"clientid": "留白则自动生成",
"clientid-nonclean":"如非新会话必须设置客户端ID",
"will-topic": "留白将禁止终止信息",
"birth-topic": "留白将禁止初始信息"
"will-topic": "留白将禁止Will信息",
"birth-topic": "留白将禁止Birth信息"
},
"state": {
"connected": "已连接到服务端: __broker__",
@@ -334,7 +344,7 @@
"retain": "保留",
"true": "是",
"false": "否",
"tip": "提示: 如果你想用msg属性来设置主题qos 或者是否保存,请将这几个区域留空",
"tip": "提示: 若希望通过msg属性对topic(信息), qos及retain(保留)进行设置, 则将上述项留白",
"errors": {
"not-defined": "主题未设置",
"missing-config": "未设置服务端",
@@ -344,13 +354,13 @@
},
"httpin": {
"label": {
"method": "方法",
"method": "请求方式",
"url": "URL",
"doc": "文档",
"return": "返回",
"upload": "接受文件上传?",
"status": "状态码",
"headers": "头子段",
"headers": "Header",
"other": "其他"
},
"setby": "- 用 msg.method 设定 -",
@@ -358,21 +368,21 @@
"use-tls": "使用安全连接 (SSL/TLS) ",
"tls-config":"TLS 设置",
"utf8": "UTF-8 字符串",
"binary": "二进制缓冲模块",
"json": "解析JSON对象",
"binary": "二进制数据",
"json": "JSON对象",
"tip": {
"in": "相对URL",
"res": "发送到此节点的消息<b>必须</b>来自 <i>http input</i> 节点",
"res": "发送到此节点的消息<b>必须</b>来自<i>http input</i>节点",
"req": "提示如果JSON解析失败则获取的字符串将按原样返回."
},
"httpreq": "http 请求",
"errors": {
"not-created": "当httpNodeRoot为否时无法创建 http-in 节点",
"not-created": "当httpNodeRoot为否时无法创建http-in节点",
"missing-path": "无路径",
"no-response": "无响应对象",
"json-error": "JSON 解析错误",
"no-url": "未设定 URL",
"deprecated-call":"__method__ 方法已弃用",
"deprecated-call":"__method__方法已弃用",
"invalid-transport":"非HTTP传输请求"
},
"status": {
@@ -387,13 +397,14 @@
},
"listenon": "监听",
"connectto": "连接",
"payload": "发送/接受 有效载荷",
"message": "发送/接受 完整信息",
"sendrec": "发送/接受",
"payload": "有效载荷",
"message": "完整信息",
"tip": {
"path1": "默认情况下,<code> payload </code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.",
"path1": "默认情况下,<code>payload</code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.",
"path2": "这条路径将相对于 ",
"url1": "URL 应该使用 ws:&#47;&#47; 或者 wss:&#47;&#47; 方案并指向现有的websocket侦听器.",
"url2": "默认情况下,<code> payload </code>将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象."
"url1": "URL 应该使用ws:&#47;&#47;或者wss:&#47;&#47;方案并指向现有的websocket侦听器.",
"url2": "默认情况下,<code>payload</code> 将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象."
},
"errors": {
"connect-error": "ws连接发生了错误: ",
@@ -403,8 +414,8 @@
},
"watch": {
"label": {
"files": "文件(s)",
"recursive": "递归查看文件夹"
"files": "文件",
"recursive": "递归所有子文件夹"
},
"placeholder": {
"files": "逗号分开文件或文件夹"
@@ -416,8 +427,8 @@
"type": "类型",
"output": "输出",
"port": "端口",
"host": "主服务器",
"payload": "有效载荷(s)",
"host": "主机地址",
"payload": "有效载荷",
"delimited": "分隔符号",
"close-connection": "是否在成功发送每条信息后断开连接?",
"decode-base64": "用 Base64 解码信息?",
@@ -429,19 +440,19 @@
"type": {
"listen": "监听",
"connect": "连接",
"reply": "回应到 TCP"
"reply": "响应 TCP"
},
"output": {
"stream": "字串流",
"single": "单一",
"buffer": "缓冲模块",
"buffer": "Buffer",
"string": "字符串",
"base64": "Base64 字符串"
},
"return": {
"timeout": "在固定时间超时后",
"character": "当收到某个字符",
"number": "固定数目的字符",
"timeout": "定时间后",
"character": "当收到某个字符",
"number": "指定字符",
"never": "永不 - 保持连接",
"immed": "马上 - 不需要等待回复"
},
@@ -452,8 +463,8 @@
"stopped-listening": "已停止监听端口",
"connection-from": "连接来自 __host__:__port__",
"connection-closed": "连接已关闭 __host__:__port__",
"connections": "__count__ 连接",
"connections_plural": "__count__ 连接"
"connections": "__count__ 连接",
"connections_plural": "__count__ 连接"
},
"errors": {
@@ -463,7 +474,7 @@
"error": "错误: __error__",
"socket-error": "套接字连接错误来自 __host__:__port__",
"no-host": "主服务器和/或者端口未设定",
"no-host": "主机地址或端口未设定",
"connect-timeout": "连接超时",
"connect-fail": "连接失败"
}
@@ -476,23 +487,23 @@
"output": "输出",
"group": "组",
"interface": "本地IP",
"interfaceprompt": "(可选)本地 IP 绑定到",
"interfaceprompt": "(可选)本地 IP 绑定到",
"send": "发送一个",
"toport": "到端口",
"address": "地址",
"decode-base64": "是否解码编码为Base64的信息?"
"decode-base64": "是否解码Base64编码的信息?"
},
"placeholder": {
"interface": "(可选eth0 的 ip 地址",
"address": "目的地 ip 地址"
"interface": "可选eth0的IP地址",
"address": "目标IP地址"
},
"udpmsgs": "udp 信息",
"udpmsgs": "udp信息",
"mcmsgs": "组播信息",
"udpmsg": "udp 信息",
"udpmsg": "udp信息",
"bcmsg": "广播信息",
"mcmsg": "组播信息",
"output": {
"buffer": "缓冲模块",
"buffer": "Buffer",
"string": "字符串",
"base64": "Base64编码字符串"
},
@@ -503,8 +514,8 @@
},
"tip": {
"in": "提示:确保您的防火墙将允许数据进入",
"out": "提示:如果要使用<code> msg.ip </code>和<code> msg.port </code>设置,请将地址和端口留空",
"port": "端口已在使用: "
"out": "提示:如果要使用<code>msg.ip</code>和<code>msg.port</code>设置,请将地址和端口留空",
"port": "在使用端口: "
},
"status": {
"listener-at": "udp 监听器正在监听 __host__:__port__",
@@ -520,66 +531,72 @@
"access-error": "UDP 访问错误, 你可能需要root权限才能接入1024以下的端口",
"error": "错误: __error__",
"bad-mcaddress": "无效的组播地址",
"interface": "必须是需要接口的 ip 地址",
"ip-notset": "udp: ip 地址未设定",
"interface": "必须是指定接口的IP地址",
"ip-notset": "udp: IP地址未设定",
"port-notset": "udp: 端口未设定",
"port-invalid": "udp: 无效端口号码",
"alreadyused": "udp: 端口已经在使用"
"alreadyused": "udp: 端口已被占用"
}
},
"switch": {
"label": {
"property": "属性",
"rule": "规"
"rule": "规",
"repair" : "重建信息队列"
},
"and": "",
"and": "",
"checkall": "全选所有规则",
"stopfirst": "接受第一条匹配信息后停止",
"ignorecase": "忽大小写",
"ignorecase": "忽大小写",
"rules": {
"btwn":"在之间",
"cont":"包含",
"regex":"匹配正则表达式",
"true":"为真",
"false":"为假",
"null":"为空",
"nnull":"非空",
"null":"为空",
"nnull":"非空",
"head":"head",
"tail":"tail",
"index":"index between",
"exp":"JSONata表达式",
"else":"除此以外"
},
"errors": {
"invalid-expr": "无效 JSONata 表达: __error__"
"invalid-expr": "无效JSONata表达: __error__",
"too-many" : "Switch节点中有太多待定信息"
}
},
"change": {
"label": {
"rules": "规",
"rule": "规",
"rules": "规",
"rule": "规",
"set": "设定 __property__",
"change": "改 __property__",
"change": "改 __property__",
"delete": "删除 __property__",
"move": "移动 __property__",
"changeCount": "改: __count__ 条规矩",
"regex": "用正则表达式"
"changeCount": "改: __count__条规矩",
"regex": "使用正则表达式"
},
"action": {
"set": "设定",
"change": "改",
"change": "改",
"delete": "删除",
"move": "转移",
"to": "到",
"search": "搜索",
"replace": "更改为"
"replace": "替代为"
},
"errors": {
"invalid-from": "无效来源 from 属性: __error__",
"invalid-json": "无效 to 属性",
"invalid-expr": "无效 JSONata 表示: __error__"
"invalid-from": "无效的'from'属性: __error__",
"invalid-json": "无效的'to'JSON 属性",
"invalid-expr": "无效JSONata表达式: __error__"
}
},
"range": {
"label": {
"action": "行为作用",
"inputrange": "映射输入数据范围",
"action": "操作",
"inputrange": "映射输入数据",
"resultrange": "至目标范围",
"from": "从",
"to": "到",
@@ -591,26 +608,28 @@
"maxout": "e.g. 255"
},
"scale": {
"payload": "按比例 msg.payload",
"payload": "按比例msg.payload",
"limit": "按比例并设定界限至目标范围",
"wrap": "按比例并包含在目标范围内"
},
"tip": "提示: 此节点仅对数字有效",
"errors": {
"notnumber": "不是一个数"
"notnumber": "不是一个数"
}
},
"csv": {
"label": {
"columns": "列",
"separator": "分隔符",
"c2o": "CSV 至对象选项",
"o2c": "对象至 to CSV 选项",
"separator": "分隔符",
"c2o": "CSV至对象",
"o2c": "对象至CSV",
"input": "输入",
"skip-s": "忽略前",
"skip-e": "行",
"firstrow": "第一行包含列名",
"output": "输出",
"includerow": "包含列名行",
"newline": "新的一行"
"newline": "换行符"
},
"placeholder": {
"columns": "用逗号分割列名"
@@ -625,8 +644,8 @@
"other": "其他..."
},
"output": {
"row": "每行包含一条信息",
"array": "一条单独信息 [数组]"
"row": "每行一条信息",
"array": "一条信息 [数组]"
},
"newline": {
"linux": "Linux (\\n)",
@@ -634,8 +653,8 @@
"windows": "Windows (\\r\\n)"
},
"errors": {
"csv_js": "此节点仅处理 CSV 字符串或 js 对象",
"obj_csv": "对象 -> CSV 转换未设定列模版"
"csv_js": "此节点仅处理CSV字符串或JS对象",
"obj_csv": "对象->CSV转换未设定列模版"
}
},
"html": {
@@ -644,13 +663,13 @@
"output": "输出"
},
"output": {
"html": "选定元素的 html 内容",
"html": "选定元素的html内容",
"text": "选定元素的纯文本内容",
"attr": "选定元素的所有属性对象"
"attr": "包含选定元素的所有属性对象"
},
"format": {
"single": "由一个单独信息包含一个数组",
"multi": "多条信息,每一条包含一个元素"
"single": "一条信息 [数组]",
"multi": "多条信息,每一个元素"
}
},
"json": {
@@ -660,8 +679,15 @@
"dropped-error": "转换有效负载失败"
},
"label": {
"o2j": "对象至 JSON 选项",
"pretty": "格式化 JSON 字符串"
"o2j": "对象至JSON",
"pretty": "格式化JSON字符串",
"action": "操作",
"property": "属性",
"actions": {
"toggle": "JSON字符串与对象互转",
"str":"总是转为JSON字符串",
"obj":"总是转为JS对象"
}
}
},
"yaml": {
@@ -687,14 +713,14 @@
"gpiopin": "GPIO",
"selectpin": "选择引脚",
"resistor": "电阻?",
"readinitial": "在部署/重新启动时读取引脚的初始状态?",
"readinitial": "在部署/重时读取引脚的初始状态?",
"type": "类型",
"initpin": "初始化引脚状态?",
"debounce": "去抖动",
"freq": "频率",
"button": "按钮",
"pimouse": "Pi 鼠标",
"pikeyboard": "Pi 键盘",
"pimouse": "Pi鼠标",
"pikeyboard": "Pi键盘",
"left": "左",
"right": "右",
"middle": "中"
@@ -705,21 +731,21 @@
"pulldown": "下拉电阻"
},
"digout": "数字输出",
"pwmout": "PWM 输出",
"pwmout": "PWM输出",
"servo": "伺服输出",
"initpin0": "初始引脚电平 - 低 (0)",
"initpin1": "初始引脚电平 - 高 (1)",
"initpin0": "初始引脚电平 - 低(0)",
"initpin1": "初始引脚电平 - 高(1)",
"left": "左",
"right": "右",
"middle": "中",
"any": "任何",
"pinname": "引脚",
"alreadyuse": "已经在用",
"alreadyset": "已经设定为",
"alreadyuse": "已被使用",
"alreadyset": "已被设为",
"tip": {
"pin": "<b>引脚在使用</b>: ",
"in": "提示: 仅接受数字输入 - 输出必须为 0 或 1.",
"dig": "提示: 如用数字输出 - 输入必须为 0 或 1.",
"pin": "<b>在使用引脚</b>: ",
"in": "提示: 仅接受数字输入 - 输出必须为0或1.",
"dig": "提示: 如用数字输出 - 输入必须为0或1.",
"pwm": "提示: 如用PWM输出 - 输入必须为0至100之间; 如用高频率可能会比预期占用更多CPU资源.",
"ser": "<b>提示</b>: 如用伺服输出 - 输入必须为0至100之间. 50为中间值."
},
@@ -728,7 +754,7 @@
"input": "输入",
"pullup": "含有上拉电阻的输入",
"pulldown": "含有下拉电阻的输入",
"pwmout": "PWM 输出",
"pwmout": "PWM输出",
"servo": "伺服输出"
},
"status": {
@@ -740,27 +766,27 @@
"ignorenode": "忽略树莓派的特定节点",
"version": "版本命令失败",
"sawpitype": "查看Pi类型",
"libnotfound": "找不到树莓派 RPi.GPIO python库",
"alreadyset": "GPIO 引脚 __pin__ 已经被设定为类型: __type__",
"invalidpin": "无效 GPIO 引脚",
"libnotfound": "找不到树莓派RPi.GPIOpython库",
"alreadyset": "GPIO引脚 __pin__ 已经被设定为类型: __type__",
"invalidpin": "无效GPIO引脚",
"invalidinput": "无效输入",
"needtobeexecutable": "__command__ 需要为可运行命令",
"mustbeexecutable": "nrgpio 需要为可运行",
"commandnotfound": "nrgpio 命令不存在",
"commandnotexecutable": "nrgpio 命令无法运行",
"needtobeexecutable": "__command__为可运行命令",
"mustbeexecutable": "nrgpio为可运行",
"commandnotfound": "nrgpio命令不存在",
"commandnotexecutable": "nrgpio命令不可运行",
"error": "错误: __error__",
"pythoncommandnotfound": "nrpgio python 命令不运行"
"pythoncommandnotfound": "nrpgio python命令未处于运行状态"
}
},
"tail": {
"label": {
"filename": "文件名",
"type": "文件类型",
"splitlines": "拆分线 \\n?"
"splitlines": "以\\n来拆分行?"
},
"action": {
"text": "文本 - 返回字符串",
"binary": "二进制 - 返回缓冲区"
"binary": "二进制 - 返回Buffer"
},
"errors": {
"windowsnotsupport": "Windows目前不支持."
@@ -770,7 +796,7 @@
"label": {
"filename": "文件名",
"action": "行为",
"addnewline": "向每个有效载荷添加换行符(\\ n?",
"addnewline": "向每个有效载荷添加换行符(\\n?",
"createdir": "创建目录(如果不存在)?",
"outputas": "输出",
"breakchunks": "分拆成块",
@@ -781,14 +807,14 @@
},
"action": {
"append": "追加至文件",
"overwrite": "写文件",
"overwrite": "写文件",
"delete": "删除文件"
},
"output": {
"utf8": "一条单独 utf8 字符串",
"buffer": "一条单独缓冲区对象",
"utf8": "一utf8字符串",
"buffer": "一个Buffer对象",
"lines": "每行一条信息",
"stream": "缓冲区流"
"stream": "一个Buffer流"
},
"status": {
"wrotefile": "写入至文件: __file__",
@@ -806,41 +832,99 @@
"tip": "提示: 文件名应该是绝对路径否则它将相对于Node-RED进程的工作目录。"
},
"split": {
"intro":"分<code>msg.payload</code> 基于类型:",
"intro":"基于以下类型拆分<code>msg.payload</code>:",
"object":"<b>对象</b>",
"objectSend":"发送每个键/值对的消息",
"strBuff":"<b>字符串</b> / <b>缓冲区</b>",
"objectSend":"每个键值对作为单个消息发送",
"strBuff":"<b>字符串</b> / <b>Buffer</b>",
"array":"<b>数组</b>",
"splitUsing":"拆分使用",
"splitLength":"固定长度",
"stream":"处理为消息流",
"stream":"为消息流处理",
"addname":" 复制键到 "
},
"join":{
"mode":{
"mode":"模式",
"auto":"自动",
"merge":"合并序列",
"reduce":"缩减序列",
"custom":"手动"
},
"combine":"结合每一个",
"create":"创建输出",
"combine":"合并每个",
"create":"输出",
"type":{
"string":"字符串",
"array":"数组",
"buffer":"缓冲区",
"object":"键/值对象",
"buffer":"Buffer",
"object":"键值对象",
"merged":"合并对象"
},
"using":"使用值",
"key":"作键",
"using":"使用值",
"key":"作键",
"joinedUsing":"合并符号",
"send":"发送信息:",
"afterCount":"达到一定数的信息部件时",
"count":"数",
"afterCount":"达到一定数的信息时",
"count":"数",
"subsequent":"和每个后续的消息",
"afterTimeout":"第一条消息的超时后",
"afterTimeout":"第一条消息的若干时间后",
"seconds":"秒",
"complete":"在使用<code> msg.complete </ code>属性设置的消息后",
"tip":"此模式假定此节点与 <i>split</i> 或者接收到的消息将具有正确配置的 <code>msg.parts</code> 属性."
"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": "Reduce表达式",
"exp-value": "exp",
"init": "初始值",
"right": "反向求值(从后往前)",
"fixup": "Fix-up exp"
},
"errors": {
"invalid-expr": "无效的JSONata表达式: __error__"
}
},
"sort" : {
"target" : "排序属性",
"seq" : "信息队列",
"key" : "键值",
"elem" : "元素值",
"order" : "顺序",
"ascending" : "升序",
"descending" : "降序",
"as-number" : "作为数值",
"invalid-exp" : "sort节点中存在无效的JSONata表达式",
"too-many" : "sort节点中有太多待定信息",
"clear" : "清空sort节点中的待定信息"
},
"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

@@ -65,7 +65,7 @@
that are part of a sequence.</p>
<p>The <b>recreate message sequences</b> option can be enabled to generate new message sequences
for each rule that matches. In this mode, the node will buffer the entire incoming
sequence before sending the new sequences on. The runtime setting `nodeMessageBufferMaxLength`
sequence before sending the new sequences on. The runtime setting <code>nodeMessageBufferMaxLength</code>
can be used to limit how many messages nodes will buffer.</p>
</script>
@@ -140,7 +140,7 @@
},
icon: "switch.png",
label: function() {
return this.name||"switch";
return this.name||this._("swicth.switch");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
@@ -199,7 +199,7 @@
rule.t = 'eq';
}
if (!opt.hasOwnProperty('i')) {
opt._i = Math.floor((0x99999-0x10000)*Math.random()).toString(16);
opt._i = Math.floor((0x99999-0x10000)*Math.random()).toString();
}
container.css({
overflow: 'hidden',

View File

@@ -76,7 +76,8 @@
outputs: 1,
icon: "range.png",
label: function() {
return this.name || "range";
if (this.minout !== "" && this.maxout !== "") { return this.name||this.minout + " - " + this.maxout; }
else { return this.name||this._("range.range"); }
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";

View File

@@ -112,7 +112,7 @@
outputs:1,
icon: "split.png",
label: function() {
return this.name||"split";
return this.name||this._("split.split");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
@@ -337,7 +337,7 @@
</p>
<h4>Storing messages</h4>
<p>This node will buffer messages internally in order to work across sequences. The
runtime setting `nodeMessageBufferMaxLength` can be used to limit how many messages nodes
runtime setting <code>nodeMessageBufferMaxLength</code> can be used to limit how many messages nodes
will buffer.</p>
</script>
@@ -367,7 +367,7 @@
outputs:1,
icon: "join.png",
label: function() {
return this.name||"join";
return this.name||this._("join.join");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -103,7 +103,7 @@
outputs:1,
icon: "sort.png",
label: function() {
return this.name || "sort";
return this.name||this._("sort.sort");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";

View File

@@ -85,12 +85,11 @@
must have a <code>msg.topic</code> property and a <code>msg.parts</code> property
identifying its sequence. The node is configured with a list of <code>topic</code>
values to identify the order sequences are concatenated.
</dd>
</dd>
</dl>
<h4>Storing messages</h4>
<p>This node will buffer messages internally in order to work across sequences. The
runtime setting `nodeMessageBufferMaxLength` can be used to limit how many messages nodes
runtime setting <code>nodeMessageBufferMaxLength</code> can be used to limit how many messages nodes
will buffer.</p>
</script>
@@ -111,7 +110,7 @@
outputs:1,
icon: "batch.png",
label: function() {
return this.name || "batch";
return this.name||this._("batch.batch");;
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";

View File

@@ -116,7 +116,7 @@ module.exports = function(RED) {
for (var topic of topics) {
remove_topic(pending, topic);
}
send_msgs(node, msgs, false);
send_msgs(node, msgs, true);
node.pending_count -= msgs.length;
}

View File

@@ -58,6 +58,7 @@
color:"#DEBD5C",
defaults: {
name: {value:""},
property: {value:"payload"},
tag: {value:""},
ret: {value:"html"},
as: {value:"single"}
@@ -70,6 +71,9 @@
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-property").typedInput({default:'msg',types:['msg']});
}
});
</script>

View File

@@ -46,7 +46,7 @@
outputs:1,
icon: "file.png",
label: function() {
return this.name||this.filename||"tail";
return this.name||this.filename||this._("tail.tail");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "0.18.1",
"version": "0.18.4",
"description": "A visual tool for wiring the Internet of Things",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -60,7 +60,7 @@
"mustache": "2.3.0",
"node-red-node-email": "0.1.*",
"node-red-node-feedparser": "0.1.*",
"node-red-node-rbe": "0.1.*",
"node-red-node-rbe": "0.2.*",
"node-red-node-twitter": "0.1.*",
"nopt": "4.0.1",
"oauth2orize": "1.11.0",

26
red.js
View File

@@ -31,8 +31,10 @@ var app = express();
var settingsFile;
var flowFile;
var readonly;
var knownOpts = {
"credentialSecret": String,
"help": Boolean,
"port": Number,
"settings": [path],
@@ -41,6 +43,7 @@ var knownOpts = {
"verbose": Boolean
};
var shortHands = {
"k":["--credentialSecret"],
"?":["--help"],
"p":["--port"],
"s":["--settings"],
@@ -59,9 +62,11 @@ var parsedArgs = nopt(knownOpts,shortHands,process.argv,2)
if (parsedArgs.help) {
console.log("Node-RED v"+RED.version());
console.log("Usage: node-red [-v] [-?] [--settings settings.js] [--userDir DIR]");
console.log(" [--port PORT] [--title TITLE] [flows.json]");
console.log(" [--port PORT] [--credentialSecret SECRET_KEY]");
console.log(" [--title TITLE] [flows.json]");
console.log("");
console.log("Options:");
console.log(" -k, --credentialSecret SECRET_KEY key to unlock credentials file");
console.log(" -p, --port PORT port to listen on");
console.log(" -s, --settings FILE use specified settings file");
console.log(" --title TITLE process window title");
@@ -101,8 +106,15 @@ if (parsedArgs.settings) {
var settingsStat = fs.statSync(defaultSettings);
if (settingsStat.mtime.getTime() <= settingsStat.ctime.getTime()) {
// Default settings file has not been modified - safe to copy
fs.copySync(defaultSettings,userSettingsFile);
settingsFile = userSettingsFile;
try {
fs.copySync(defaultSettings,userSettingsFile);
settingsFile = userSettingsFile;
}
catch (err) {
console.log("Can't copy settings file.");
settingsFile = defaultSettings;
readonly = true;
}
} else {
// Use default settings.js as it has been modified
settingsFile = defaultSettings;
@@ -114,6 +126,10 @@ if (parsedArgs.settings) {
try {
var settings = require(settingsFile);
settings.settingsFile = settingsFile;
if (readonly === true) {
console.log("Setting to read Only mode.");
settings.readOnly = true;
}
} catch(err) {
console.log("Error loading settings file: "+settingsFile)
if (err.code == 'MODULE_NOT_FOUND') {
@@ -126,6 +142,10 @@ try {
process.exit();
}
if (parsedArgs.credentialSecret) {
settings.credentialSecret = parsedArgs.credentialSecret;
}
if (parsedArgs.verbose) {
settings.verbose = true;
}

View File

@@ -16,11 +16,9 @@
var log;
var redNodes;
var settings;
module.exports = {
init: function(runtime) {
settings = runtime.settings;
redNodes = runtime.nodes;
log = runtime.log;
},

View File

@@ -16,11 +16,9 @@
var log;
var redNodes;
var settings;
module.exports = {
init: function(runtime) {
settings = runtime.settings;
redNodes = runtime.nodes;
log = runtime.log;
},
@@ -80,7 +78,7 @@ module.exports = {
}).catch(function(err) {
log.warn(log._("api.flows.error-save",{message:err.message}));
log.warn(err.stack);
res.status(500).json({error:"unexpected_error", message:err.message});
res.status(500).json({error:err.code || "unexpected_error", message:err.message});
});
}
}

View File

@@ -18,17 +18,13 @@ var when = require("when");
var apiUtils = require("../util");
var redNodes;
var log;
var i18n;
var settings;
var events;
module.exports = {
init: function(runtime) {
redNodes = runtime.nodes;
log = runtime.log;
i18n = runtime.i18n;
settings = runtime.settings;
events = runtime.events;
},
getAll: function(req,res) {
if (req.get("accept") == "application/json") {
@@ -72,11 +68,6 @@ module.exports = {
return;
}
promise.then(function(info) {
if (isUpgrade) {
events.emit("runtime-event",{id:"node/upgraded",retain:false,payload:{module:node.module,version:node.version}});
} else {
events.emit("runtime-event",{id:"node/added",retain:false,payload:info.nodes});
}
if (node.module) {
log.audit({event: "nodes.install",module:node.module,version:node.version},req);
res.json(info);
@@ -114,7 +105,6 @@ module.exports = {
}
promise.then(function(list) {
events.emit("runtime-event",{id:"node/removed",retain:false,payload:list});
log.audit({event: "nodes.remove",module:mod},req);
res.status(204).end();
}).catch(function(err) {
@@ -248,21 +238,6 @@ function putNode(node, enabled) {
} else {
promise = redNodes.disableNode(node.id);
}
return promise.then(function(info) {
if (info.enabled === enabled && !info.err) {
events.emit("runtime-event",{id:"node/"+(enabled?"enabled":"disabled"),retain:false,payload:info});
log.info(" "+log._("api.nodes."+(enabled?"enabled":"disabled")));
for (var i=0;i<info.types.length;i++) {
log.info(" - "+info.types[i]);
}
} else if (enabled && info.err) {
log.warn(log._("api.nodes.error-enable"));
log.warn(" - "+info.name+" : "+info.err);
}
return info;
});
}
return promise;
}

View File

@@ -93,7 +93,8 @@
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
"missing_flow_file": "<p>Project flow file not found.</p><p>The project is not configured with a flow file.</p>",
"project_empty": "<p>The project is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>",
"project_not_found": "<p>Project '__project__' not found.</p>"
"project_not_found": "<p>Project '__project__' not found.</p>",
"git_merge_conflict": "<p>Automatic merging of changes failed.</p><p>Fix the unmerged conflicts then commit the results.</p>"
},
"error": "<strong>Error</strong>: __message__",

View File

@@ -239,7 +239,7 @@
"managePalette": "管理面板"
},
"library": {
"openLibrary": "打开库...",
"openLibrary": "打开库...",
"saveToLibrary": "保存到库...",
"typeLibrary": "__type__类型库",
"unnamedType": "无名__type__",

View File

@@ -194,5 +194,25 @@
"$globalContext": {
"args": "string",
"desc": "获取全局上下文的属性。"
},
"$pad": {
"args": "string, width [, char]",
"desc": "根据需要,向字符串`string`的副本中填充文字使该字符串的字数达到`width`的绝对值并返回填充文字后的字符串。\n\n如果`width`的值为正,则向字符串`string`的右侧填充文字,如果`width`为负,则向字符串`string`的左侧填充文字。\n\n可选参数`char`用来指定填充的文字。如果未指定该参数,则填充空白文字。"
},
"$fromMillis": {
"args": "number",
"desc": "将表示从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数的数值转换成ISO 8601形式时间戳的字符串。"
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "将`number`转换成具有`picture`所指定的数值格式的字符串。\n\n此函数的功能与XPath F&O 3.1规格中定义的XPath/XQuery函数的fn:format-number功能相一致。参数`picture`用于指定数值的转换格式其语法与fn:format-number中的定义一致。\n\n可选的第三参数`options`用来覆盖默认的局部环境格式如小数点分隔符。如果指定该参数那么该参数必须是包含name/value对的对象并且name/value对必须符合XPath F&O 3.1规格中记述的数值格式。"
},
"$formatBase": {
"args": "number [, radix]",
"desc": "将`number`变换为以参数`radix`的值为基数形式的字符串。如果不指定`radix`的值则默认基数为10。指定的`radix`值必须在236之间否则抛出错误。"
},
"$toMillis": {
"args": "timestamp",
"desc": "将ISO 8601格式的字符串`timestamp`转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
}
}

View File

@@ -16,13 +16,11 @@
var express = require("express");
var runtime;
var settings;
var needsPermission = require("../../auth").needsPermission;
module.exports = {
init: function(_runtime) {
runtime = _runtime;
settings = runtime.settings;
},
app: function() {
var app = express();
@@ -149,7 +147,9 @@ module.exports = {
// Get project status - files, commit counts, branch info
app.get("/:id/status", needsPermission("projects.read"), function(req,res) {
runtime.storage.projects.getStatus(req.user, req.params.id).then(function(data) {
var includeRemote = req.query.remote;
runtime.storage.projects.getStatus(req.user, req.params.id, includeRemote).then(function(data) {
if (data) {
res.json(data);
} else {
@@ -248,8 +248,11 @@ module.exports = {
res.redirect(303,req.baseUrl+"/"+projectName+"/status");
})
.catch(function(err) {
console.log(err.stack);
res.status(400).json({error:"unexpected_error", message:err.toString()});
if (err.code) {
res.status(400).json({error:err.code, message: err.message});
} else {
res.status(400).json({error:"unexpected_error", message:err.toString()});
}
})
});
@@ -350,8 +353,9 @@ module.exports = {
app.post("/:id/pull/?*", needsPermission("projects.write"), function(req,res) {
var projectName = req.params.id;
var remoteBranchName = req.params[0];
var setRemote = req.query.u;
runtime.storage.projects.pull(req.user, projectName,remoteBranchName,setRemote).then(function(data) {
var setUpstream = req.query.setUpstream;
var allowUnrelatedHistories = req.query.allowUnrelatedHistories;
runtime.storage.projects.pull(req.user, projectName,remoteBranchName,setUpstream,allowUnrelatedHistories).then(function(data) {
res.status(204).end();
})
.catch(function(err) {
@@ -501,6 +505,10 @@ module.exports = {
// Add a remote
app.post("/:id/remotes", needsPermission("projects.write"), function(req,res) {
var projectName = req.params.id;
if (/^https?:\/\/[^/]+@/i.test(req.body.url)) {
res.status(400).json({error:"unexpected_error", message:"Git http url must not include username/password"});
return;
}
runtime.storage.projects.addRemote(req.user, projectName, req.body).then(function() {
res.redirect(303,req.baseUrl+"/"+projectName+"/remotes");
}).catch(function(err) {

View File

@@ -54,10 +54,11 @@ module.exports = {
var activeProject = runtime.storage.projects.getActiveProject();
if (activeProject) {
safeSettings.project = activeProject;
}
safeSettings.files = {
flow: runtime.storage.projects.getFlowFilename(),
credentials: runtime.storage.projects.getCredentialsFilename()
} else if (runtime.storage.projects.flowFileExists()) {
safeSettings.files = {
flow: runtime.storage.projects.getFlowFilename(),
credentials: runtime.storage.projects.getCredentialsFilename()
}
}
safeSettings.git = {
globalUser: runtime.storage.projects.getGlobalGitUser()

View File

@@ -17,7 +17,6 @@
var express = require("express");
var os = require("os");
var runtime;
var settings;
var needsPermission = require("../auth").needsPermission;
function getUsername(userObj) {
@@ -31,7 +30,6 @@ function getUsername(userObj) {
module.exports = {
init: function(_runtime) {
runtime = _runtime;
settings = runtime.settings;
},
app: function() {
var app = express();

View File

@@ -24,8 +24,6 @@ var cors = require('cors');
var auth = require("./auth");
var apiUtil = require("./util");
var i18n;
var log;
var adminApp;
var server;
var runtime;
@@ -35,8 +33,6 @@ function init(_server,_runtime) {
server = _server;
runtime = _runtime;
var settings = runtime.settings;
i18n = runtime.i18n;
log = runtime.log;
if (settings.httpAdminRoot !== false) {
apiUtil.init(runtime);
adminApp = express();

View File

@@ -83,7 +83,8 @@
"credentials": {
"error":"Error loading credentials: __message__",
"error-saving":"Error saving credentials: __message__",
"not-registered": "Credential type '__type__' is not registered"
"not-registered": "Credential type '__type__' is not registered",
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n"
},
"flows": {
"registered-missing": "Missing type registered: __type__",

View File

@@ -201,6 +201,9 @@ var api = module.exports = {
encryptedCredentials = credentials;
}
log.debug("red/runtime/nodes/credentials.load : keyType="+encryptionKeyType);
if (encryptionKeyType === 'system') {
log.warn(log._("nodes.credentials.system-key-warning"));
}
return setupEncryptionPromise.then(function() {
var clearInvalidFlag = false;
if (credentials.hasOwnProperty("$")) {

View File

@@ -104,7 +104,43 @@ function init(runtime) {
function disableNode(id) {
flows.checkTypeInUse(id);
return registry.disableNode(id);
return registry.disableNode(id).then(function(info) {
reportNodeStateChange(info,false);
return info;
});
}
function enableNode(id) {
return registry.enableNode(id).then(function(info) {
reportNodeStateChange(info,true);
return info;
});
}
function reportNodeStateChange(info,enabled) {
if (info.enabled === enabled && !info.err) {
events.emit("runtime-event",{id:"node/"+(enabled?"enabled":"disabled"),retain:false,payload:info});
log.info(" "+log._("api.nodes."+(enabled?"enabled":"disabled")));
for (var i=0;i<info.types.length;i++) {
log.info(" - "+info.types[i]);
}
} else if (enabled && info.err) {
log.warn(log._("api.nodes.error-enable"));
log.warn(" - "+info.name+" : "+info.err);
}
}
function installModule(module,version) {
var ex_module = registry.getModuleInfo(module);
var isUpgrade = !!ex_module;
return registry.installModule(module,version).then(function(info) {
if (isUpgrade) {
events.emit("runtime-event",{id:"node/upgraded",retain:false,payload:{module:module,version:version}});
} else {
events.emit("runtime-event",{id:"node/added",retain:false,payload:info.nodes});
}
return info;
});
}
function uninstallModule(module) {
@@ -115,7 +151,10 @@ function uninstallModule(module) {
for (var i=0;i<info.nodes.length;i++) {
flows.checkTypeInUse(module+"/"+info.nodes[i].name);
}
return registry.uninstallModule(module);
return registry.uninstallModule(module).then(function(list) {
events.emit("runtime-event",{id:"node/removed",retain:false,payload:list});
return list;
});
}
}
@@ -130,10 +169,10 @@ module.exports = {
eachNode: flows.eachNode,
paletteEditorEnabled: registry.paletteEditorEnabled,
installModule: registry.installModule,
installModule: installModule,
uninstallModule: uninstallModule,
enableNode: registry.enableNode,
enableNode: enableNode,
disableNode: disableNode,
// Node type registry

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