Compare commits

..

2 Commits

Author SHA1 Message Date
Dave Conway-Jones
7518987083 Add subflows to context sidebar 2019-06-19 09:51:48 +01:00
Dave Conway-Jones
5a7592a953 Add name to node and flow context view labels
slight adjust spacing for context view
2019-06-18 21:14:14 +01:00
856 changed files with 12535 additions and 39393 deletions

View File

@@ -28,8 +28,7 @@ To help us understand the issue, please fill-in as much of the following informa
### Please tell us about your environment:
- [ ] Node-RED version:
- [ ] Node.js version:
- [ ] node.js version:
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:
- [ ] running in Docker:

View File

@@ -1,6 +1,6 @@
---
name: Bug report
about: Reproducible software issues in the core of Node-RED
about: Reproducable software issues in the core of Node-RED
title: ''
labels: ''
assignees: ''
@@ -33,7 +33,7 @@ To help us understand the issue, please fill-in as much of the following informa
### Please tell us about your environment:
- [ ] Node-RED version:
- [ ] Node.js version:
- [ ] node.js version:
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:

View File

@@ -29,6 +29,6 @@ the [forum](https://discourse.nodered.org) or
<!-- 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 forum/slack team.
- [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team.
- [ ] I have run `grunt` to verify the unit tests pass
- [ ] I have added suitable unit tests to cover the new/changed functionality

View File

@@ -1,29 +0,0 @@
const fs = require("fs");
const newVersion = require("../../package.json").version;
if (process.env.GITHUB_REF !== "refs/tags/"+newVersion) {
console.log(`GITHUB_REF doesn't match the package.json version: ${process.env.GITHUB_REF} !== ${newVersion}`);
process.exit(0);
}
if (!/^\d+\.\d+\.\d+$/.test(newVersion)) {
console.log(`Not updating for a non-stable release - ${newVersion}`);
process.exit(0);
}
const currentVersion = require("../../../node-red-docker/package.json").version;
console.log(`Update from ${currentVersion} to ${newVersion}`)
updateFile(__dirname+"/../../../node-red-docker/package.json", currentVersion, newVersion);
updateFile(__dirname+"/../../../node-red-docker/docker-custom/package.json", currentVersion, newVersion);
updateFile(__dirname+"/../../../node-red-docker/README.md", currentVersion, newVersion);
console.log(`::set-env name=newVersion::${newVersion}`);
function updateFile(path,from,to) {
let contents = fs.readFileSync(path,"utf8");
contents = contents.replace(new RegExp(from.replace(/\./g,"\\."),"g"), to);
fs.writeFileSync(path, contents);
}

View File

@@ -1,18 +0,0 @@
const fs = require("fs");
const newVersion = require("../../package.json").version;
if (process.env.GITHUB_REF !== "refs/tags/"+newVersion) {
console.log(`GITHUB_REF doesn't match the package.json version: ${process.env.GITHUB_REF} !== ${newVersion}`);
process.exit(0);
}
if (!/^\d+\.\d+\.\d+$/.test(newVersion)) {
console.log(`Not updating for a non-stable release - ${newVersion}`);
process.exit(0);
}
const path = __dirname+"/../../../node-red.github.io/index.html";
let contents = fs.readFileSync(path, "utf8");
contents = contents.replace(/<span class="node-red-latest-version">v\d+\.\d+\.\d+<\/span>/, `<span class="node-red-latest-version">v${newVersion}<\/span>` );
fs.writeFileSync(path, contents);

View File

@@ -1,59 +0,0 @@
name: PublishDockerImage
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
on:
release:
types: [published]
jobs:
generate:
name: 'Update node-red-docker image'
runs-on: ubuntu-latest
steps:
- name: Check out node-red repository
uses: actions/checkout@v2
with:
path: 'node-red'
- name: Check out node-red-docker repository
uses: actions/checkout@v2
with:
repository: 'node-red/node-red-docker'
path: 'node-red-docker'
- name: Check out node-red.github.io repository
uses: actions/checkout@v2
with:
repository: 'node-red/node-red.github.io'
path: 'node-red.github.io'
- uses: actions/setup-node@v1
with:
node-version: '12'
- run: node ./node-red/.github/scripts/update-node-red-docker.js
- name: Create Docker Pull Request
uses: peter-evans/create-pull-request@v2
with:
token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
path: 'node-red-docker'
commit-message: 'Bump to ${{ env.newVersion }}'
title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
body: |
Updates the Node-RED Docker repo for the ${{ env.newVersion }} release.
Once this is merged, you will need to create a new release with the tag `v${{ env.newVersion }}`.
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary
- run: node ./node-red/.github/scripts/update-node-red-website.js
- name: Create Website Pull Request
uses: peter-evans/create-pull-request@v2
with:
token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
path: 'node-red.github.io'
commit-message: 'Bump to ${{ env.newVersion }}'
title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
body: |
Updates the Node-RED Website repo for the ${{ env.newVersion }} release.
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary

2
.gitignore vendored
View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
At a minimum, please include:
- Version of Node-RED - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly.
- Version of Node.js - what does `node -v` say?
- Version of node.js - what does `node -v` say?
## Feature requests

View File

@@ -16,29 +16,18 @@
var path = require("path");
var fs = require("fs-extra");
var sass = require("node-sass");
module.exports = function(grunt) {
var nodemonArgs = ["-V"];
var nodemonArgs = ["-v"];
var flowFile = grunt.option('flowFile');
if (flowFile) {
nodemonArgs.push(flowFile);
process.env.NODE_RED_ENABLE_PROJECTS=false;
}
var userDir = grunt.option('userDir');
if (userDir) {
nodemonArgs.push("-u");
nodemonArgs.push(userDir);
}
var browserstack = grunt.option('browserstack');
if (browserstack) {
process.env.BROWSERSTACK = true;
}
var nonHeadless = grunt.option('non-headless');
if (nonHeadless) {
process.env.NODE_RED_NON_HEADLESS = true;
process.env.NODE_RED_NON_HEADLESS = 'true';
}
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
@@ -53,8 +42,8 @@ module.exports = function(grunt) {
ui: 'bdd',
reporter: 'spec'
},
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
all: { src: ['test/**/*_spec.js'] },
core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
webdriver: {
@@ -62,19 +51,19 @@ module.exports = function(grunt) {
configFile: 'test/editor/wdio.conf.js'
}
},
nyc: {
mocha_istanbul: {
options: {
cwd: '.',
include: ['packages/node_modules/**'],
excludeNodeModules: false,
exclude: ['packages/node_modules/@node-red/editor-client/**'],
reporter: ['lcov', 'html','text-summary'],
reportDir: 'coverage',
all: true
globals: ['expect'],
timeout: 3000,
ignoreLeaks: false,
ui: 'bdd',
reportFormats: ['lcov','html'],
print: 'both',
istanbulOptions: ['--no-default-excludes', '-i','**/packages/node_modules/**']
},
all: { cmd: false, args: ['grunt', 'simplemocha:all'] },
core: { options: { exclude:['packages/node_modules/@node-red/editor-client/**', 'packages/node_modules/@node-red/nodes/**']},cmd: false, args: ['grunt', 'simplemocha:core'] },
nodes: { cmd: false, args: ['grunt', 'simplemocha:nodes'] }
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
jshint: {
options: {
@@ -90,20 +79,20 @@ module.exports = function(grunt) {
//"loopfunc": true, // allow functions to be defined in loops
//"sub": true // don't warn that foo['bar'] should be written as foo.bar
},
// all: [
// 'Gruntfile.js',
// 'red.js',
// 'packages/**/*.js'
// ],
// core: {
// files: {
// src: [
// 'Gruntfile.js',
// 'red.js',
// 'packages/**/*.js',
// ]
// }
// },
all: [
'Gruntfile.js',
'red.js',
'packages/**/*.js'
],
core: {
files: {
src: [
'Gruntfile.js',
'red.js',
'packages/**/*.js',
]
}
},
nodes: {
files: {
src: [ 'nodes/core/*/*.js' ]
@@ -111,7 +100,7 @@ module.exports = function(grunt) {
},
editor: {
files: {
src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ]
src: [ 'editor/js/**/*.js' ]
}
},
tests: {
@@ -131,7 +120,6 @@ module.exports = function(grunt) {
src: [
// Ensure editor source files are concatenated in
// the right order
"packages/node_modules/@node-red/editor-client/src/js/polyfills.js",
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js",
@@ -158,7 +146,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
@@ -171,8 +158,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
@@ -187,7 +172,6 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/group.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
@@ -200,12 +184,11 @@ module.exports = function(grunt) {
vendor: {
files: {
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.4.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.0.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js",
"node_modules/jsonata/jsonata-es5.min.js",
@@ -237,7 +220,6 @@ module.exports = function(grunt) {
sass: {
build: {
options: {
implementation: sass,
outputStyle: 'compressed'
},
files: [{
@@ -294,7 +276,7 @@ module.exports = function(grunt) {
files: [
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
],
tasks: ['copy:build','concat',/*'uglify',*/ 'attachCopyright:js']
tasks: ['copy:build','concat','uglify','attachCopyright:js']
},
sass: {
files: [
@@ -458,7 +440,6 @@ module.exports = function(grunt) {
'packages/node_modules/@node-red/runtime/lib/index.js',
'packages/node_modules/@node-red/runtime/lib/api/*.js',
'packages/node_modules/@node-red/runtime/lib/events.js',
'packages/node_modules/@node-red/runtime/lib/hooks.js',
'packages/node_modules/@node-red/util/**/*.js',
'packages/node_modules/@node-red/editor-api/lib/index.js',
'packages/node_modules/@node-red/editor-api/lib/auth/index.js'
@@ -509,37 +490,17 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-chmod');
grunt.loadNpmTasks('grunt-jsonlint');
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.loadNpmTasks('grunt-webdriver');
}
grunt.loadNpmTasks('grunt-mocha-istanbul');
grunt.loadNpmTasks('grunt-webdriver');
grunt.loadNpmTasks('grunt-jsdoc');
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
grunt.loadNpmTasks('grunt-npm-command');
grunt.loadNpmTasks('grunt-mkdir');
grunt.loadNpmTasks('grunt-simple-nyc');
grunt.registerMultiTask('nodemon', 'Runs a nodemon monitor of your node.js server.', function () {
const nodemon = require('nodemon');
this.async();
const options = this.options();
options.script = this.data.script;
let callback;
if (options.callback) {
callback = options.callback;
delete options.callback;
} else {
callback = function(nodemonApp) {
nodemonApp.on('log', function (event) {
console.log(event.colour);
});
};
}
callback(nodemon(options));
});
grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src;
@@ -594,25 +555,12 @@ module.exports = function(grunt) {
});
grunt.registerTask('verifyUiTestDependencies', function() {
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.fail.fatal('You need to install the UI test dependencies first.\nUse the script in "scripts/install-ui-test-dependencies.sh"');
if (!fs.existsSync(path.join("node_modules", "chromedriver"))) {
grunt.fail.fatal('You need to run "npm install chromedriver@2" before running UI test.');
return false;
}
});
grunt.registerTask('generatePublishScript',
'Generates a script to publish build output to npm',
function () {
const done = this.async();
const generatePublishScript = require("./scripts/generate-publish-script.js");
generatePublishScript().then(function(output) {
grunt.log.writeln(output);
const filePath = path.join(grunt.config.get('paths.dist'),"modules","publish.sh");
grunt.file.write(filePath,output);
done();
});
});
grunt.registerTask('setDevEnv',
'Sets NODE_ENV=development so non-minified assets are used',
function () {
@@ -621,50 +569,35 @@ module.exports = function(grunt) {
grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components',
['build','verifyPackageDependencies','jshint:editor','nyc:all']);
grunt.registerTask('no-coverage',
'Builds editor content then runs code style checks and unit tests on all components without code coverage',
['build','verifyPackageDependencies','jshint:editor','simplemocha:all']);
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',
['build','nyc:core']);
['build','mocha_istanbul:core']);
grunt.registerTask('test-editor',
'Runs code style check on editor code',
['jshint:editor']);
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies']);
} else {
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies','build','jshint:editor','webdriver:all']);
}
grunt.registerTask('test-ui',
'Builds editor content then runs unit tests on editor ui',
['verifyUiTestDependencies','build','jshint:editor','webdriver:all']);
grunt.registerTask('test-nodes',
'Runs unit tests on core nodes',
['build','nyc:nodes']);
['build','mocha_istanbul:nodes']);
grunt.registerTask('build',
'Builds editor content',
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
grunt.registerTask('build-dev',
'Developer mode: build dev version',
['clean:build','concat:build','concat:vendor','copy:build','sass:build','setDevEnv']);
grunt.registerTask('dev',
'Developer mode: run node-red, watch for source changes and build/restart',
['build','setDevEnv','concurrent:dev']);
grunt.registerTask('release',
'Create distribution zip file',
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules','generatePublishScript']);
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules']);
grunt.registerTask('pack-modules',
'Create module pack files for release',
@@ -673,7 +606,7 @@ module.exports = function(grunt) {
grunt.registerTask('coverage',
'Run Istanbul code test coverage task',
['build','nyc:all']);
['build','mocha_istanbul:all']);
grunt.registerTask('docs',
'Generates API documentation',

View File

@@ -1,4 +1,4 @@
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Copyright JS Foundation and other contributors, http://js.foundation
Apache License
Version 2.0, January 2004

View File

@@ -5,9 +5,9 @@ http://nodered.org
[![Build Status](https://travis-ci.org/node-red/node-red.svg?branch=master)](https://travis-ci.org/node-red/node-red)
[![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.svg?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master)
Low-code programming for event-driven applications.
A visual tool for wiring the Internet of Things.
![Node-RED: Low-code programming for event-driven applications](http://nodered.org/images/node-red-screenshot.png)
![Node-RED: A visual tool for wiring the Internet of Things](http://nodered.org/images/node-red-screenshot.png)
## Quick Start
@@ -56,7 +56,7 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena
## Authors
Node-RED is a project of the [OpenJS Foundation](https://openjsf.org).
Node-RED is a project of the [JS Foundation](http://js.foundation).
It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
@@ -67,4 +67,4 @@ It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-t
## Copyright and license
Copyright OpenJS Foundation and other contributors, https://openjsf.org under [the Apache 2.0 license](LICENSE).
Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE).

View File

@@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report any potential security issues to `team@nodered.org`. This will notify the core project team who will respond accordingly.

View File

@@ -1,7 +1,7 @@
{
"name": "node-red",
"version": "1.2.8",
"description": "Low-code programming for event-driven applications",
"version": "1.0.0-beta.2",
"description": "A visual tool for wiring the Internet of Things",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
"repository": {
@@ -13,8 +13,6 @@
"start": "node packages/node_modules/node-red/red.js",
"test": "grunt",
"build": "grunt build",
"dev": "grunt dev",
"build-dev": "grunt build-dev",
"docs": "grunt docs"
},
"contributors": [
@@ -26,94 +24,95 @@
}
],
"dependencies": {
"ajv": "6.12.6",
"async-mutex": "0.2.6",
"ajv": "6.10.0",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"cheerio": "0.22.0",
"clone": "2.1.2",
"content-type": "1.0.4",
"cookie": "0.4.1",
"cookie-parser": "1.4.5",
"cookie": "0.4.0",
"cookie-parser": "1.4.4",
"cors": "2.8.5",
"cron": "1.7.2",
"denque": "1.5.0",
"express": "4.17.1",
"express-session": "1.17.1",
"fs-extra": "8.1.0",
"cron": "1.7.1",
"denque": "1.4.1",
"express": "4.17.0",
"express-session": "1.16.1",
"fs-extra": "8.0.1",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
"https-proxy-agent": "5.0.0",
"hash-sum": "1.0.2",
"https-proxy-agent": "2.2.1",
"i18next": "15.1.2",
"iconv-lite": "0.6.2",
"iconv-lite": "0.4.24",
"is-utf8": "0.2.1",
"js-yaml": "3.14.0",
"js-yaml": "3.13.1",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.4",
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0",
"memorystore": "1.6.4",
"mime": "2.4.7",
"moment-timezone": "0.5.32",
"mqtt": "4.2.6",
"multer": "1.4.2",
"mustache": "4.1.0",
"node-red-admin": "^0.2.6",
"node-red-node-rbe": "^0.2.9",
"node-red-node-sentiment": "^0.1.6",
"node-red-node-tail": "^0.1.0",
"nopt": "5.0.0",
"jsonata": "1.6.4",
"memorystore": "1.6.1",
"mime": "2.4.3",
"mqtt": "2.18.8",
"multer": "1.4.1",
"mustache": "3.0.1",
"node-red-node-email": "^1.4.0",
"node-red-node-feedparser": "^0.1.14",
"node-red-node-rbe": "^0.2.4",
"node-red-node-sentiment": "^0.1.3",
"node-red-node-tail": "^0.0.2",
"node-red-node-twitter": "^1.1.4",
"nopt": "4.0.1",
"oauth2orize": "1.11.0",
"on-headers": "1.0.2",
"passport": "0.4.1",
"passport": "0.4.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.1",
"raw-body": "2.4.0",
"request": "2.88.0",
"semver": "6.3.0",
"tar": "6.0.5",
"uglify-js": "3.12.4",
"semver": "6.0.0",
"uglify-js": "3.5.15",
"when": "3.7.8",
"ws": "6.2.1",
"xml2js": "0.4.23"
"xml2js": "0.4.19"
},
"optionalDependencies": {
"bcrypt": "3.0.8"
"bcrypt": "3.0.6"
},
"devDependencies": {
"dompurify": "2.2.6",
"grunt": "1.3.0",
"grunt": "~1.0.3",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.3.2",
"grunt-concurrent": "3.0.0",
"grunt-contrib-clean": "~2.0.0",
"grunt-contrib-compress": "1.6.0",
"grunt-concurrent": "~2.3.1",
"grunt-contrib-clean": "~1.1.0",
"grunt-contrib-compress": "~1.4.0",
"grunt-contrib-concat": "~1.0.1",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-jshint": "~2.1.0",
"grunt-contrib-uglify": "~4.0.1",
"grunt-contrib-jshint": "~1.1.0",
"grunt-contrib-uglify": "~3.4.0",
"grunt-contrib-watch": "~1.1.0",
"grunt-jsdoc": "2.4.1",
"grunt-jsdoc-to-markdown": "5.0.0",
"grunt-jsonlint": "2.1.3",
"grunt-mkdir": "~1.1.0",
"grunt-jsdoc": "^2.2.1",
"grunt-jsdoc-to-markdown": "^4.0.0",
"grunt-jsonlint": "~1.1.0",
"grunt-mkdir": "~1.0.0",
"grunt-mocha-istanbul": "5.0.2",
"grunt-nodemon": "~0.4.2",
"grunt-npm-command": "~0.1.2",
"grunt-sass": "~3.1.0",
"grunt-sass": "~2.0.0",
"grunt-simple-mocha": "~0.4.1",
"grunt-simple-nyc": "^3.0.1",
"http-proxy": "1.18.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "1.2.7",
"grunt-webdriver": "^2.0.3",
"http-proxy": "^1.16.2",
"istanbul": "0.4.5",
"minami": "1.2.3",
"mocha": "^5.2.0",
"node-red-node-test-helper": "^0.2.6",
"node-sass": "^4.14.1",
"nodemon": "2.0.6",
"should": "13.2.3",
"mosca": "^2.8.3",
"should": "^8.4.0",
"sinon": "1.17.7",
"stoppable": "^1.1.0",
"supertest": "5.0.0"
"supertest": "3.4.2",
"wdio-chromedriver-service": "^0.1.5",
"wdio-mocha-framework": "^0.6.4",
"wdio-spec-reporter": "^0.1.5",
"webdriverio": "^4.14.1",
"node-red-node-test-helper": "^0.2.2",
"jsdoc-nr-template": "node-red/jsdoc-nr-template"
},
"engines": {
"node": ">=8"

View File

@@ -30,8 +30,7 @@ module.exports = {
scope: req.params.scope,
id: req.params.id,
key: req.params[0],
store: req.query['store'],
req: apiUtils.getRequestLogObject(req)
store: req.query['store']
}
runtimeAPI.context.getValue(opts).then(function(result) {
res.json(result);
@@ -46,8 +45,7 @@ module.exports = {
scope: req.params.scope,
id: req.params.id,
key: req.params[0],
store: req.query['store'],
req: apiUtils.getRequestLogObject(req)
store: req.query['store']
}
runtimeAPI.context.delete(opts).then(function(result) {
res.status(204).end();

View File

@@ -24,8 +24,7 @@ module.exports = {
get: function(req,res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.flows.getFlow(opts).then(function(result) {
return res.json(result);
@@ -36,8 +35,7 @@ module.exports = {
post: function(req,res) {
var opts = {
user: req.user,
flow: req.body,
req: apiUtils.getRequestLogObject(req)
flow: req.body
}
runtimeAPI.flows.addFlow(opts).then(function(id) {
return res.json({id:id});
@@ -49,8 +47,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
flow: req.body,
req: apiUtils.getRequestLogObject(req)
flow: req.body
}
runtimeAPI.flows.updateFlow(opts).then(function(id) {
return res.json({id:id});
@@ -61,8 +58,7 @@ module.exports = {
delete: function(req,res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.flows.deleteFlow(opts).then(function() {
res.status(204).end();

View File

@@ -27,8 +27,7 @@ module.exports = {
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
}
var opts = {
user: req.user,
req: apiUtils.getRequestLogObject(req)
user: req.user
}
runtimeAPI.flows.getFlows(opts).then(function(result) {
if (version === "v1") {
@@ -47,8 +46,7 @@ module.exports = {
}
var opts = {
user: req.user,
deploymentType: req.get("Node-RED-Deployment-Type")||"full",
req: apiUtils.getRequestLogObject(req)
deploymentType: req.get("Node-RED-Deployment-Type")||"full"
}
if (opts.deploymentType !== 'reload') {

View File

@@ -21,17 +21,15 @@ var flows = require("./flows");
var flow = require("./flow");
var context = require("./context");
var auth = require("../auth");
var info = require("./settings");
var apiUtil = require("../util");
module.exports = {
init: function(settings,runtimeAPI) {
init: function(runtimeAPI) {
flows.init(runtimeAPI);
flow.init(runtimeAPI);
nodes.init(runtimeAPI);
context.init(runtimeAPI);
info.init(settings,runtimeAPI);
var needsPermission = auth.needsPermission;
@@ -49,21 +47,14 @@ module.exports = {
// Nodes
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler);
if (!settings.editorTheme || !settings.editorTheme.palette || settings.editorTheme.palette.upload !== false) {
const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage() });
adminApp.post("/nodes",needsPermission("nodes.write"),upload.single("tarball"),nodes.post,apiUtil.errorHandler);
} else {
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
}
adminApp.get(/^\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
adminApp.put(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler);
adminApp.delete(/^\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler);
adminApp.get(/^\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler);
adminApp.put(/^\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler);
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
adminApp.get(/\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler);
adminApp.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler);
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler);
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler);
// Context
adminApp.get("/context/:scope(global)",needsPermission("context.read"),context.get,apiUtil.errorHandler);
@@ -76,8 +67,6 @@ module.exports = {
// adminApp.delete("/context/:scope(node|flow)/:id",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
adminApp.delete("/context/:scope(node|flow)/:id/*",needsPermission("context.write"),context.delete,apiUtil.errorHandler);
adminApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler);
return adminApp;
}
}

View File

@@ -24,8 +24,7 @@ module.exports = {
},
getAll: function(req,res) {
var opts = {
user: req.user,
req: apiUtils.getRequestLogObject(req)
user: req.user
}
if (req.get("accept") == "application/json") {
runtimeAPI.nodes.getNodeList(opts).then(function(list) {
@@ -43,19 +42,7 @@ module.exports = {
var opts = {
user: req.user,
module: req.body.module,
version: req.body.version,
url: req.body.url,
tarball: undefined,
req: apiUtils.getRequestLogObject(req)
}
if (!runtimeAPI.settings.editorTheme || !runtimeAPI.settings.editorTheme.palette || runtimeAPI.settings.editorTheme.palette.upload !== false) {
if (req.file) {
opts.tarball = {
name: req.file.originalname,
size: req.file.size,
buffer: req.file.buffer
}
}
version: req.body.version
}
runtimeAPI.nodes.addModule(opts).then(function(info) {
res.json(info);
@@ -67,8 +54,7 @@ module.exports = {
delete: function(req,res) {
var opts = {
user: req.user,
module: req.params[0],
req: apiUtils.getRequestLogObject(req)
module: req.params[0]
}
runtimeAPI.nodes.removeModule(opts).then(function() {
res.status(204).end();
@@ -80,8 +66,7 @@ module.exports = {
getSet: function(req,res) {
var opts = {
user: req.user,
id: req.params[0] + "/" + req.params[2],
req: apiUtils.getRequestLogObject(req)
id: req.params[0] + "/" + req.params[2]
}
if (req.get("accept") === "application/json") {
runtimeAPI.nodes.getNodeInfo(opts).then(function(result) {
@@ -102,8 +87,7 @@ module.exports = {
getModule: function(req,res) {
var opts = {
user: req.user,
module: req.params[0],
req: apiUtils.getRequestLogObject(req)
module: req.params[0]
}
runtimeAPI.nodes.getModuleInfo(opts).then(function(result) {
res.send(result);
@@ -122,8 +106,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params[0] + "/" + req.params[2],
enabled: body.enabled,
req: apiUtils.getRequestLogObject(req)
enabled: body.enabled
}
runtimeAPI.nodes.setNodeSetState(opts).then(function(result) {
res.send(result);
@@ -142,8 +125,7 @@ module.exports = {
var opts = {
user: req.user,
module: req.params[0],
enabled: body.enabled,
req: apiUtils.getRequestLogObject(req)
enabled: body.enabled
}
runtimeAPI.nodes.setModuleState(opts).then(function(result) {
res.send(result);
@@ -157,8 +139,7 @@ module.exports = {
var opts = {
user: req.user,
module: req.params[0],
lang: req.query.lng,
req: apiUtils.getRequestLogObject(req)
lang: req.query.lng
}
runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) {
res.json(result);
@@ -171,8 +152,7 @@ module.exports = {
getModuleCatalogs: function(req,res) {
var opts = {
user: req.user,
lang: req.query.lng,
req: apiUtils.getRequestLogObject(req)
lang: req.query.lng
}
runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) {
res.json(result);
@@ -184,8 +164,7 @@ module.exports = {
getIcons: function(req,res) {
var opts = {
user: req.user,
req: apiUtils.getRequestLogObject(req)
user: req.user
}
runtimeAPI.nodes.getIconList(opts).then(function(list) {
res.json(list);

View File

@@ -1,72 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var apiUtils = require("../util");
var runtimeAPI;
var settings;
var theme = require("../editor/theme");
var clone = require("clone");
var i18n = require("@node-red/util").i18n
function extend(target, source) {
var keys = Object.keys(source);
var i = keys.length;
while(i--) {
var value = source[keys[i]]
var type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
target[keys[i]] = value;
} else if (value === null) {
if (target.hasOwnProperty(keys[i])) {
delete target[keys[i]];
}
} else {
// Object
if (target.hasOwnProperty(keys[i])) {
target[keys[i]] = extend(target[keys[i]],value);
} else {
target[keys[i]] = value;
}
}
}
return target;
}
module.exports = {
init: function(_settings,_runtimeAPI) {
runtimeAPI = _runtimeAPI;
settings = _settings;
},
runtimeSettings: function(req,res) {
var opts = {
user: req.user
}
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
if (!settings.disableEditor) {
result.editorTheme = result.editorTheme||{};
var themeSettings = theme.settings();
if (themeSettings) {
// result.editorTheme may already exist with the palette
// disabled. Need to merge that into the receive settings
result.editorTheme = extend(clone(themeSettings),result.editorTheme);
}
result.editorTheme.languages = i18n.availableLanguages("editor");
}
res.json(result);
});
},
}

View File

@@ -36,7 +36,6 @@ var log = require("@node-red/util").log; // TODO: separate module
passport.use(strategies.bearerStrategy.BearerStrategy);
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
passport.use(strategies.anonymousStrategy);
passport.use(strategies.tokensStrategy);
var server = oauth2orize.createServer();
@@ -61,7 +60,7 @@ function init(_settings,storage) {
function needsPermission(permission) {
return function(req,res,next) {
if (settings && settings.adminAuth) {
return passport.authenticate(['bearer','tokens','anon'],{ session: false })(req,res,function() {
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
if (!req.user) {
return next();
}
@@ -101,10 +100,7 @@ function login(req,res) {
}
} else if (mergedAdminAuth.type === "strategy") {
var urlPrefix = (settings.httpAdminRoot||"").replace(/\/$/,"");
if (urlPrefix.length > 0) {
urlPrefix += "/";
}
var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot;
response = {
"type":"strategy",
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]

View File

@@ -123,57 +123,9 @@ AnonymousStrategy.prototype.authenticate = function(req) {
});
}
function authenticateUserToken(req) {
return new Promise( (resolve,reject) => {
var token = null;
var tokenHeader = Users.tokenHeader();
if (Users.tokenHeader() === null) {
// No custom user token provided. Fail the request
reject();
return;
} else if (Users.tokenHeader() === 'authorization') {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
}
} else {
token = req.headers[Users.tokenHeader()];
}
if (token) {
Users.tokens(token).then(function(user) {
if (user) {
resolve(user);
} else {
reject();
}
});
} else {
reject();
}
});
}
function TokensStrategy() {
passport.Strategy.call(this);
this.name = 'tokens';
}
util.inherits(TokensStrategy, passport.Strategy);
TokensStrategy.prototype.authenticate = function(req) {
authenticateUserToken(req).then(user => {
this.success(user,{scope:user.permissions});
}).catch(err => {
this.fail(401);
});
}
module.exports = {
bearerStrategy: bearerStrategy,
clientPasswordStrategy: clientPasswordStrategy,
passwordTokenExchange: passwordTokenExchange,
anonymousStrategy: new AnonymousStrategy(),
tokensStrategy: new TokensStrategy(),
authenticateUserToken: authenticateUserToken
anonymousStrategy: new AnonymousStrategy()
}

View File

@@ -14,7 +14,15 @@
* limitations under the License.
**/
const crypto = require("crypto");
function generateToken(length) {
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var token = [];
for (var i=0;i<length;i++) {
token.push(c[Math.floor(Math.random()*c.length)]);
}
return token.join("");
}
var storage;
var sessionExpiryTime
@@ -48,7 +56,7 @@ function expireSessions() {
}
if (nextExpiry < Number.MAX_SAFE_INTEGER) {
// Allow 5 seconds grace
expiryTimeout = setTimeout(expireSessions,Math.min(2147483647,(nextExpiry - Date.now()) + 5000))
expiryTimeout = setTimeout(expireSessions,(nextExpiry - Date.now()) + 5000)
}
if (modified) {
return storage.saveSessions(sessions);
@@ -107,7 +115,7 @@ module.exports = {
},
create: function(user,client,scope) {
return loadSessions().then(function() {
var accessToken = crypto.randomBytes(128).toString('base64');
var accessToken = generateToken(128);
var accessTokenExpiresAt = Date.now() + (sessionExpiryTime*1000);
@@ -121,7 +129,7 @@ module.exports = {
sessions[accessToken] = session;
if (!expiryTimeout) {
expiryTimeout = setTimeout(expireSessions,Math.min(2147483647,(accessTokenExpiresAt - Date.now()) + 5000))
expiryTimeout = setTimeout(expireSessions,(accessTokenExpiresAt - Date.now()) + 5000)
}
return storage.saveSessions(sessions).then(function() {

View File

@@ -59,9 +59,7 @@ function getDefaultUser() {
var api = {
get: get,
authenticate: authenticate,
default: getDefaultUser,
tokens: getDefaultUser,
tokenHeader: null
default: getDefaultUser
}
function init(config) {
@@ -107,14 +105,6 @@ function init(config) {
} else {
api.default = getDefaultUser;
}
if (config.tokens && typeof config.tokens === "function") {
api.tokens = config.tokens;
if (config.tokenHeader && typeof config.tokenHeader === "string") {
api.tokenHeader = config.tokenHeader.toLowerCase();
} else {
api.tokenHeader = "authorization";
}
}
}
function cleanUser(user) {
if (user && user.hasOwnProperty('password')) {
@@ -128,7 +118,5 @@ module.exports = {
init: init,
get: function(username) { return api.get(username).then(cleanUser)},
authenticate: function() { return api.authenticate.apply(null, arguments) },
default: function() { return api.default(); },
tokens: function(token) { return api.tokens(token); },
tokenHeader: function() { return api.tokenHeader }
default: function() { return api.default(); }
};

View File

@@ -16,13 +16,11 @@
var ws = require("ws");
var url = require("url");
const crypto = require("crypto");
var log = require("@node-red/util").log; // TODO: separate module
var Tokens;
var Users;
var Permissions;
var Strategies;
var server;
var settings;
@@ -33,6 +31,8 @@ var activeConnections = [];
var anonymousUser;
var retained = {};
var heartbeatTimer;
var lastSentTime;
@@ -44,7 +44,6 @@ function init(_server,_settings,_runtimeAPI) {
Tokens.onSessionExpiry(handleSessionExpiry);
Users = require("../auth/users");
Permissions = require("../auth/permissions");
Strategies = require("../auth/strategies");
}
function handleSessionExpiry(session) {
@@ -55,19 +54,26 @@ function handleSessionExpiry(session) {
}
})
}
function generateSession(length) {
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
var token = [];
for (var i=0;i<length;i++) {
token.push(c[Math.floor(Math.random()*c.length)]);
}
return token.join("");
}
function CommsConnection(ws, user) {
this.session = crypto.randomBytes(32).toString('base64');
function CommsConnection(ws) {
this.session = generateSession(32);
this.ws = ws;
this.stack = [];
this.user = user;
this.user = null;
this.lastSentTime = 0;
var self = this;
log.audit({event: "comms.open"});
log.trace("comms.open "+self.session);
var preAuthed = !!user;
var pendingAuth = !this.user && (settings.adminAuth != null);
var pendingAuth = (settings.adminAuth != null);
if (!pendingAuth) {
addActiveConnection(self);
@@ -124,16 +130,8 @@ function CommsConnection(ws, user) {
}
});
} else {
Users.tokens(msg.auth).then(function(user) {
if (user) {
self.user = user;
log.audit({event: "comms.auth",user:self.user});
completeConnection(user.permissions,msg.auth,true);
} else {
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
}
});
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
}
});
} else {
@@ -193,8 +191,8 @@ function start() {
var commsPath = settings.httpAdminRoot || "/";
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
wsServer = new ws.Server({ noServer: true });
wsServer.on('connection',function(ws, request, user) {
var commsConnection = new CommsConnection(ws, user);
wsServer.on('connection',function(ws) {
var commsConnection = new CommsConnection(ws);
});
wsServer.on('error', function(err) {
log.warn(log._("comms.error-server",{message:err.toString()}));
@@ -203,26 +201,8 @@ function start() {
server.on('upgrade', function upgrade(request, socket, head) {
const pathname = url.parse(request.url).pathname;
if (pathname === commsPath) {
if (Users.tokenHeader() !== null && request.headers[Users.tokenHeader()]) {
// The user has provided custom token handling. For the websocket,
// the token could be provided in two ways:
// - as an http header (only possible with a reverse proxy setup)
// - passed over the connected websock in an auth packet
// If the header is present, verify the token. If not, use the auth
// packet over the connected socket
//
Strategies.authenticateUserToken(request).then(user => {
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit('connection', ws, request, user);
});
}).catch(err => {
log.audit({event: "comms.auth.fail"});
socket.destroy();
})
return
}
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit('connection', ws, request, null);
wsServer.emit('connection', ws, request);
});
}
// Don't destroy the socket as other listeners may want to handle the

View File

@@ -88,13 +88,13 @@ module.exports = {
// Locales
var locales = require("./locales");
locales.init(runtimeAPI);
editorApp.get(/^\/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler);
editorApp.get(/locales\/(.+)\/?$/,locales.get,apiUtil.errorHandler);
// Library
var library = require("./library");
library.init(runtimeAPI);
editorApp.get(/^\/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
editorApp.post(/^\/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);
editorApp.get(/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry);
editorApp.post(/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry);
// Credentials
@@ -103,7 +103,7 @@ module.exports = {
editorApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,apiUtil.errorHandler);
// Settings
// Main /settings route is an admin route - see lib/admin/settings.js
editorApp.get("/settings",needsPermission("settings.read"),info.runtimeSettings,apiUtil.errorHandler);
// User Settings
editorApp.get("/settings/user",needsPermission("settings.read"),info.userSettings,apiUtil.errorHandler);
// User Settings

View File

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

View File

@@ -22,8 +22,7 @@ var needsPermission = require("../auth").needsPermission;
function listProjects(req,res) {
var opts = {
user: req.user,
req: apiUtils.getRequestLogObject(req)
user: req.user
}
runtimeAPI.projects.listProjects(opts).then(function(result) {
res.json(result);
@@ -34,8 +33,7 @@ function listProjects(req,res) {
function getProject(req,res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.projects.getProject(opts).then(function(data) {
if (data) {
@@ -51,8 +49,7 @@ function getProjectStatus(req,res) {
var opts = {
user: req.user,
id: req.params.id,
remote: req.query.remote,
req: apiUtils.getRequestLogObject(req)
remote: req.query.remote
}
runtimeAPI.projects.getStatus(opts).then(function(data){
if (data) {
@@ -67,8 +64,7 @@ function getProjectStatus(req,res) {
function getProjectRemotes(req,res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.projects.getRemotes(opts).then(function(data) {
res.json(data);
@@ -102,8 +98,7 @@ module.exports = {
app.post("/", needsPermission("projects.write"), function(req,res) {
var opts = {
user: req.user,
project: req.body,
req: apiUtils.getRequestLogObject(req)
project: req.body
}
runtimeAPI.projects.createProject(opts).then(function(result) {
res.json(result);
@@ -117,8 +112,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
project: req.body,
req: apiUtils.getRequestLogObject(req)
project: req.body
}
if (req.body.active) {
@@ -137,7 +131,6 @@ module.exports = {
req.body.hasOwnProperty('description') ||
req.body.hasOwnProperty('dependencies')||
req.body.hasOwnProperty('summary') ||
req.body.hasOwnProperty('version') ||
req.body.hasOwnProperty('files') ||
req.body.hasOwnProperty('git')) {
runtimeAPI.projects.updateProject(opts).then(function() {
@@ -157,8 +150,7 @@ module.exports = {
app.delete("/:id", needsPermission("projects.write"), function(req,res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.projects.deleteProject(opts).then(function() {
res.status(204).end();
@@ -176,8 +168,7 @@ module.exports = {
app.get("/:id/files", needsPermission("projects.read"), function(req,res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.projects.getFiles(opts).then(function(data) {
res.json(data);
@@ -194,8 +185,7 @@ module.exports = {
user: req.user,
id: req.params.id,
path: req.params[0],
tree: req.params.treeish,
req: apiUtils.getRequestLogObject(req)
tree: req.params.treeish
}
runtimeAPI.projects.getFile(opts).then(function(data) {
res.json({content:data});
@@ -209,8 +199,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
path: req.params[0],
req: apiUtils.getRequestLogObject(req)
path: req.params[0]
}
runtimeAPI.projects.revertFile(opts).then(function() {
@@ -225,8 +214,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
path: req.params[0],
req: apiUtils.getRequestLogObject(req)
path: req.params[0]
}
runtimeAPI.projects.stageFile(opts).then(function() {
getProjectStatus(req,res);
@@ -240,8 +228,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
path: req.body.files,
req: apiUtils.getRequestLogObject(req)
path: req.body.files
}
runtimeAPI.projects.stageFile(opts).then(function() {
getProjectStatus(req,res);
@@ -255,8 +242,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
message: req.body.message,
req: apiUtils.getRequestLogObject(req)
message: req.body.message
}
runtimeAPI.projects.commit(opts).then(function() {
getProjectStatus(req,res);
@@ -270,8 +256,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
path: req.params[0],
req: apiUtils.getRequestLogObject(req)
path: req.params[0]
}
runtimeAPI.projects.unstageFile(opts).then(function() {
getProjectStatus(req,res);
@@ -284,8 +269,7 @@ module.exports = {
app.delete("/:id/stage", needsPermission("projects.write"), function(req, res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.projects.unstageFile(opts).then(function() {
getProjectStatus(req,res);
@@ -300,8 +284,7 @@ module.exports = {
user: req.user,
id: req.params.id,
path: req.params[0],
type: req.params.type,
req: apiUtils.getRequestLogObject(req)
type: req.params.type
}
runtimeAPI.projects.getFileDiff(opts).then(function(data) {
res.json({
@@ -318,8 +301,7 @@ module.exports = {
user: req.user,
id: req.params.id,
limit: req.query.limit || 20,
before: req.query.before,
req: apiUtils.getRequestLogObject(req)
before: req.query.before
}
runtimeAPI.projects.getCommits(opts).then(function(data) {
res.json(data);
@@ -333,8 +315,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
sha: req.params.sha,
req: apiUtils.getRequestLogObject(req)
sha: req.params.sha
}
runtimeAPI.projects.getCommit(opts).then(function(data) {
res.json({commit:data});
@@ -349,8 +330,7 @@ module.exports = {
user: req.user,
id: req.params.id,
remote: req.params[0],
track: req.query.u,
req: apiUtils.getRequestLogObject(req)
track: req.query.u
}
runtimeAPI.projects.push(opts).then(function(data) {
res.status(204).end();
@@ -366,8 +346,7 @@ module.exports = {
id: req.params.id,
remote: req.params[0],
track: req.query.setUpstream,
allowUnrelatedHistories: req.query.allowUnrelatedHistories,
req: apiUtils.getRequestLogObject(req)
allowUnrelatedHistories: req.query.allowUnrelatedHistories
}
runtimeAPI.projects.pull(opts).then(function(data) {
res.status(204).end();
@@ -380,8 +359,7 @@ module.exports = {
app.delete("/:id/merge", needsPermission("projects.write"), function(req, res) {
var opts = {
user: req.user,
id: req.params.id,
req: apiUtils.getRequestLogObject(req)
id: req.params.id
}
runtimeAPI.projects.abortMerge(opts).then(function() {
res.status(204).end();
@@ -396,8 +374,7 @@ module.exports = {
user: req.user,
id: req.params.id,
path: req.params[0],
resolution: req.body.resolutions,
req: apiUtils.getRequestLogObject(req)
resolution: req.body.resolutions
}
runtimeAPI.projects.resolveMerge(opts).then(function() {
res.status(204).end();
@@ -411,8 +388,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
remote: false,
req: apiUtils.getRequestLogObject(req)
remote: false
}
runtimeAPI.projects.getBranches(opts).then(function(data) {
res.json(data);
@@ -427,8 +403,7 @@ module.exports = {
user: req.user,
id: req.params.id,
branch: req.params.branchName,
force: !!req.query.force,
req: apiUtils.getRequestLogObject(req)
force: !!req.query.force
}
runtimeAPI.projects.deleteBranch(opts).then(function(data) {
res.status(204).end();
@@ -442,8 +417,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
remote: true,
req: apiUtils.getRequestLogObject(req)
remote: true
}
runtimeAPI.projects.getBranches(opts).then(function(data) {
res.json(data);
@@ -457,8 +431,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
branch: req.params[0],
req: apiUtils.getRequestLogObject(req)
branch: req.params[0]
}
runtimeAPI.projects.getBranchStatus(opts).then(function(data) {
res.json(data);
@@ -473,8 +446,7 @@ module.exports = {
user: req.user,
id: req.params.id,
branch: req.body.name,
create: req.body.create,
req: apiUtils.getRequestLogObject(req)
create: req.body.create
}
runtimeAPI.projects.setBranch(opts).then(function(data) {
res.json(data);
@@ -491,8 +463,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
remote: req.body,
req: apiUtils.getRequestLogObject(req)
remote: req.body
}
if (/^https?:\/\/[^/]+@/i.test(req.body.url)) {
res.status(400).json({error:"unexpected_error", message:"Git http url must not include username/password"});
@@ -510,8 +481,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
remote: req.params.remoteName,
req: apiUtils.getRequestLogObject(req)
remote: req.params.remoteName
}
runtimeAPI.projects.removeRemote(opts).then(function(data) {
getProjectRemotes(req,res);
@@ -527,8 +497,7 @@ module.exports = {
var opts = {
user: req.user,
id: req.params.id,
remote: remote,
req: apiUtils.getRequestLogObject(req)
remote: remote
}
runtimeAPI.projects.updateRemote(opts).then(function() {
res.status(204).end();

View File

@@ -16,12 +16,56 @@
var apiUtils = require("../util");
var runtimeAPI;
var sshkeys = require("./sshkeys");
var theme = require("./theme");
var clone = require("clone");
var i18n = require("@node-red/util").i18n
function extend(target, source) {
var keys = Object.keys(source);
var i = keys.length;
while(i--) {
var value = source[keys[i]]
var type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean' || Array.isArray(value)) {
target[keys[i]] = value;
} else if (value === null) {
if (target.hasOwnProperty(keys[i])) {
delete target[keys[i]];
}
} else {
// Object
if (target.hasOwnProperty(keys[i])) {
target[keys[i]] = extend(target[keys[i]],value);
} else {
target[keys[i]] = value;
}
}
}
return target;
}
module.exports = {
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;
sshkeys.init(runtimeAPI);
},
runtimeSettings: function(req,res) {
var opts = {
user: req.user
}
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
result.editorTheme = result.editorTheme||{};
var themeSettings = theme.settings();
if (themeSettings) {
// result.editorTheme may already exist with the palette
// disabled. Need to merge that into the receive settings
result.editorTheme = extend(clone(themeSettings),result.editorTheme);
}
result.editorTheme.languages = i18n.availableLanguages("editor");
res.json(result);
});
},
userSettings: function(req, res) {
var opts = {
user: req.user

View File

@@ -28,7 +28,7 @@ var defaultContext = {
},
header: {
title: "Node-RED",
image: "red/images/node-red.svg"
image: "red/images/node-red.png"
},
asset: {
red: (process.env.NODE_ENV == "development")? "red/red.js":"red/red.min.js",

View File

@@ -25,7 +25,7 @@ var theme = require("./theme");
var runtimeAPI;
var editorClientDir = path.dirname(require.resolve("@node-red/editor-client"));
var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.svg");
var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.png");
var editorTemplatePath = path.join(editorClientDir,"templates","index.mst");
var editorTemplate;

View File

@@ -42,7 +42,7 @@ var editor;
/**
* Initialise the module.
* @param {Object} settings The runtime settings
* @param {HTTPServer} _server An instance of HTTP Server
* @param {HTTPServer} server An instance of HTTP Server
* @param {Storage} storage An instance of Node-RED Storage
* @param {Runtime} runtimeAPI An instance of Node-RED Runtime
* @memberof @node-red/editor-api
@@ -59,12 +59,6 @@ function init(settings,_server,storage,runtimeAPI) {
});
adminApp.use(corsHandler);
if (settings.httpAdminMiddleware) {
if (typeof settings.httpAdminMiddleware === "function") {
adminApp.use(settings.httpAdminMiddleware)
}
}
auth.init(settings,storage);
var maxApiRequestSize = settings.apiMaxLength || '5mb';
@@ -99,7 +93,7 @@ function init(settings,_server,storage,runtimeAPI) {
adminApp.use(corsHandler);
}
var adminApiApp = require("./admin").init(settings, runtimeAPI);
var adminApiApp = require("./admin").init(runtimeAPI);
adminApp.use(adminApiApp);
} else {
adminApp = null;

View File

@@ -43,26 +43,9 @@ module.exports = {
rejectHandler: function(req,res,err) {
//TODO: why this when errorHandler also?!
log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req);
if (!err.code) {
// by definition, an unexpected_error to log
log.error(err);
}
var response = {
res.status(err.status||400).json({
code: err.code||"unexpected_error",
message: err.message||err.toString()
};
// Handle auth failures on a specific remote
// TODO: don't hardcode this here - allow users of rejectHandler to identify extra props to send
if (err.remote) {
response.remote = err.remote;
}
res.status(err.status||400).json(response);
},
getRequestLogObject: function(req) {
return {
user: req.user,
path: req.path,
ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined
}
});
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "1.2.8",
"version": "1.0.0-beta.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,26 +16,25 @@
}
],
"dependencies": {
"@node-red/util": "1.2.8",
"@node-red/editor-client": "1.2.8",
"@node-red/util": "1.0.0-beta.2",
"@node-red/editor-client": "1.0.0-beta.2",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.1",
"express": "4.17.1",
"memorystore": "1.6.4",
"mime": "2.4.7",
"multer": "1.4.2",
"mustache": "4.1.0",
"express-session": "1.16.1",
"express": "4.17.0",
"memorystore": "1.6.1",
"mime": "2.4.3",
"mustache": "3.0.1",
"oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"passport": "0.4.1",
"passport": "0.4.0",
"when": "3.7.8",
"ws": "6.2.1"
},
"optionalDependencies": {
"bcrypt": "3.0.6"
"bcrypt": "3.0.5"
}
}

View File

@@ -26,19 +26,20 @@
"status" : "Status",
"enabled" : "Aktiviert",
"disabled" : "Inaktiviert",
"info" : "Beschreibung"
"info" : "Beschreibung",
"tip" : "Beschreibung akzeptiert Markdown und wird auf der Registerkarte Info angezeigt."
},
"menu" : {
"label" : {
"view" : {
"view" : "Ansicht",
"grid" : "Raster",
"grid" : "Gitter",
"showGrid" : "Raster anzeigen",
"snapGrid" : "Am Raster ausrichten",
"snapGrid" : "Einrasten am Raster",
"gridSize" : "Rastergröße",
"textDir" : "Textrichtung",
"defaultDir" : "Standard",
"ltr" : "Von links nach rechts",
"ltr" : "Links-nach-rechts",
"rtl" : "Von rechts nach links",
"auto" : "Kontextuell"
},
@@ -53,15 +54,15 @@
"import" : "Import",
"export" : "Exportieren",
"search" : "Flows durchsuchen",
"searchInput" : "Flows durchsuchen",
"searchInput" : "durchsuchen Sie Ihre Flows",
"subflows" : "Subflow",
"createSubflow" : "Subflow erstellen",
"selectionToSubflow" : "Auswahl zu Subflow",
"selectionToSubflow" : "Auswahl für Subflow",
"flows" : "Flows",
"add" : "Hinzufügen",
"rename" : "Umbenennen",
"delete" : "Löschen",
"keyboardShortcuts" : "Tastenkürzel",
"keyboardShortcuts" : "Tastaturkurzbefehle",
"login" : "Anmelden",
"logout" : "Abmelden",
"editPalette" : "Palette verwalten",
@@ -217,7 +218,7 @@
"remote" : "Ferne Änderungen",
"reviewChanges" : "Änderungen prüfen",
"noBinaryFileShowed" : "Der Inhalt der Binärdatei kann nicht angezeigt",
"viewCommitDiff" : "Änderungen committen",
"viewCommitDiff" : "Änderungen festschreiben",
"compareChanges" : "Änderungen vergleichen",
"saveConflict" : "Konfliktlösung speichern",
"conflictHeader" : "<span> __resolved__ </span> von <span> __unresolved__ </span> -Konflikten behoben",
@@ -226,8 +227,8 @@
"newVersionError" : "Neue Version enthält keine gültige JSON-Datei:"
},
"subflow" : {
"editSubflow" : "Subflow bearbeiten: __name__",
"edit" : "Subflow bearbeiten",
"editSubflow" : "Flowschablone bearbeiten: __name__",
"edit" : "Flowsschablone bearbeiten",
"subflowInstances" : "Es ist __count__ Instanz dieser Subflow-Vorlage vorhanden.",
"subflowInstances_plural" : "Es gibt __count__ Instanzen dieser Subflow-Vorlage.",
"editSubflowProperties" : "Eigenschaften bearbeiten",
@@ -236,6 +237,7 @@
"deleteSubflow" : "Subflow löschen",
"info" : "Beschreibung",
"category" : "Kategorie",
"format" : "Markdown-Format",
"errors" : {
"noNodesSelected" : "<strong> Subflow kann nicht erstellt werden </strong>: Es wurden keine Nodes ausgewählt.",
"multipleInputsToSelection" : "<strong> Subflow kann nicht erstellt werden </strong>: Mehrere Eingaben zur Auswahl"
@@ -266,7 +268,7 @@
}
},
"keyboard" : {
"title" : "Tastenkürzel",
"title" : "Tastaturkurzbefehle",
"keyboard" : "Tastatur",
"filterActions" : "Filteraktionen",
"shortcut" : "Direktaufruf",
@@ -283,7 +285,7 @@
"exportNode" : "Node exportieren",
"nudgeNode" : "Ausgewählte Nodes verschieben (1px)",
"moveNode" : "Ausgewählte Nodes verschieben (20px)",
"toggleSidebar" : "Seitenleiste ein-/ausblenden",
"toggleSidebar" : "Seitenleiste ein-/ausschalten",
"copyNode" : "Ausgewählte Nodes kopieren",
"cutNode" : "Ausgewählte Nodes ausschneiden",
"pasteNode" : "Node einfügen",
@@ -308,7 +310,7 @@
},
"palette" : {
"noInfo" : "Keine Informationen verfügbar",
"filter" : "Nodes filtern",
"filter" : "Filter Nodes",
"search" : "Suchmodule",
"addCategory" : "Neu hinzufügen ...",
"label" : {
@@ -366,11 +368,11 @@
"remove" : "entfernen",
"update" : "Update auf __version__",
"updated" : "aktualisiert",
"install" : "Installieren",
"installed" : "Installiert",
"install" : "installieren",
"installed" : "installiert",
"loading" : "Kataloge werden geladen ...",
"tab-nodes" : "Nodes",
"tab-install" : "Installieren",
"tab-install" : "installieren",
"sort" : "Sortierung:",
"sortAZ" : "a-z",
"sortRecent" : "kürzlich",
@@ -444,15 +446,15 @@
"none" : "keine",
"subflows" : "Subflows",
"flows" : "Flows",
"filterAll" : "alle",
"filterUnused" : "Nicht verwendet",
"filterAll" : "alle",
"filtered" : "__count__ verdeckt"
},
"context" : {
"name" : "Kontextdaten",
"label" : "Kontext",
"none" : "keine ausgewählt",
"refresh" : "Zum Aktualisieren neu laden",
"refresh" : "Aktualisierung zum Laden",
"empty" : "leer",
"node" : "Node",
"flow" : "Flow",
@@ -477,7 +479,7 @@
"none" : "Keine",
"install" : "installieren",
"removeFromProject" : "Aus Projekt entfernen",
"addToProject" : "Zu Projekt hinzufügen",
"addToProject" : "zu Projekt hinzufügen",
"files" : "Dateien",
"flow" : "Flow",
"credentials" : "Berechtigungsnachweis",
@@ -510,7 +512,7 @@
},
"userSettings" : {
"committerDetail" : "Committer-Details",
"committerTip" : "Leer lassen für Systemstandard",
"committerTip" : "Leer Wert für Systemstandardwert belassen",
"userName" : "Benutzername",
"email" : "E-Mail",
"sshKeys" : "SSH-Schlüssel",
@@ -544,7 +546,7 @@
"revertChanges" : "Änderungen zurücksetzen",
"localChanges" : "Lokale Änderungen",
"none" : "Keine",
"conflictResolve" : "Alle Konflikte wurden aufgelöst. Committe die Änderungen, um den Merge Request abzuschließen.",
"conflictResolve" : "Alle Konflikte wurden aufgelöst. Festschreiben der Änderungen, um den Mischvorgang abzuschließen.",
"localFiles" : "Lokale Dateien",
"all" : "alle",
"unmergedChanges" : "Nicht zusammengeführte Änderungen",

View File

@@ -14,37 +14,9 @@
"back": "Back",
"next": "Next",
"clone": "Clone project",
"cont": "Continue",
"style": "Style",
"line": "Outline",
"fill": "Fill",
"label": "Label",
"color": "Color",
"position": "Position",
"enable": "Enable",
"disable": "Disable",
"upload": "Upload"
},
"type": {
"string": "string",
"number": "number",
"boolean": "boolean",
"array": "array",
"buffer": "buffer",
"object": "object",
"jsonString": "JSON string",
"undefined": "undefined",
"null": "null"
"cont": "Continue"
}
},
"event": {
"loadPalette": "Loading Palette",
"loadNodeCatalogs": "Loading Node catalogs",
"loadNodes": "Loading Nodes __count__",
"loadFlows": "Loading Flows",
"importFlows": "Adding Flows to workspace",
"importError": "<p>Error adding flows</p><p>__message__</p>"
},
"workspace": {
"defaultName": "Flow __number__",
"editFlow": "Edit flow: __name__",
@@ -108,12 +80,7 @@
"projects-new": "New",
"projects-open": "Open",
"projects-settings": "Project Settings",
"showNodeLabelDefault": "Show label of newly added nodes",
"groups": "Groups",
"groupSelection": "Group selection",
"ungroupSelection": "Ungroup selection",
"groupMergeSelection": "Merge selection",
"groupRemoveSelection": "Remove from group"
"showNodeLabelDefault": "Show label of newly added nodes"
}
},
"actions": {
@@ -193,14 +160,10 @@
"node_plural": "__count__ nodes",
"configNode": "__count__ configuration node",
"configNode_plural": "__count__ configuration nodes",
"group": "__count__ group",
"group_plural": "__count__ groups",
"flow": "__count__ flow",
"flow_plural": "__count__ flows",
"subflow": "__count__ subflow",
"subflow_plural": "__count__ subflows",
"replacedNodes": "__count__ node replaced",
"replacedNodes_plural": "__count__ nodes replaced",
"pasteNodes": "Paste flow json or",
"selectFile": "select a file to import",
"importNodes": "Import nodes",
@@ -208,19 +171,11 @@
"download": "Download",
"importUnrecognised": "Imported unrecognised type:",
"importUnrecognised_plural": "Imported unrecognised types:",
"importDuplicate": "Imported duplicate node:",
"importDuplicate_plural": "Imported duplicate nodes:",
"nodesExported": "Nodes exported to clipboard",
"nodesImported": "Imported:",
"nodeCopied": "__count__ node copied",
"nodeCopied_plural": "__count__ nodes copied",
"groupCopied": "__count__ group copied",
"groupCopied_plural": "__count__ groups copied",
"groupStyleCopied": "Group style copied",
"invalidFlow": "Invalid flow: __message__",
"recoveredNodes": "Recovered Nodes",
"recoveredNodesInfo": "The nodes on this flow were missing a valid flow id when they were imported. They have been added to this flow so you can either restore or delete them.",
"recoveredNodesNotification": "<p>Imported nodes without a valid flow id</p><p>They have been added to a new flow called '__flowName__'.</p>",
"export": {
"selected":"selected nodes",
"current":"current flow",
@@ -235,19 +190,13 @@
},
"import": {
"import": "Import to",
"importSelected": "Import selected",
"importCopy": "Import copy",
"viewNodes": "View nodes...",
"newFlow": "new flow",
"replace": "replace",
"errors": {
"notArray": "Input not a JSON Array",
"itemNotObject": "Input not a valid flow - item __index__ not a node object",
"missingId": "Input not a valid flow - item __index__ missing 'id' property",
"missingType": "Input not a valid flow - item __index__ missing 'type' property"
},
"conflictNotification1": "Some of the nodes you are importing already exist in your workspace.",
"conflictNotification2": "Select which nodes to import and whether to replace the existing nodes, or to import a copy of them."
}
},
"copyMessagePath": "Path copied",
"copyMessageValue": "Value copied",
@@ -348,13 +297,6 @@
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
}
},
"group": {
"editGroup": "Edit group: __name__",
"errors": {
"cannotCreateDiffGroups": "Cannot create group using nodes from different groups",
"cannotAddSubflowPorts": "Cannot add subflow ports to a group"
}
},
"editor": {
"configEdit": "Edit",
"configAdd": "Add",
@@ -368,12 +310,10 @@
"addNewType": "Add new __type__...",
"nodeProperties": "node properties",
"label": "Label",
"color": "Color",
"portLabels": "Port labels",
"labelInputs": "Inputs",
"labelOutputs": "Outputs",
"settingIcon": "Icon",
"default": "default",
"noDefaultLabel": "none",
"defaultLabel": "use default label",
"searchIcons": "Search icons",
@@ -381,42 +321,6 @@
"description": "Description",
"show": "Show",
"hide": "Hide",
"locale": "Select UI Language",
"icon": "Icon",
"inputType": "Input type",
"selectType": "select types...",
"inputs" : {
"input": "input",
"select": "select",
"checkbox": "checkbox",
"spinner": "spinner",
"none": "none",
"hidden": "hide property"
},
"types": {
"str": "string",
"num": "number",
"bool": "bool",
"json": "JSON",
"bin": "buffer",
"env": "env variable",
"cred": "credential"
},
"menu": {
"input": "input",
"select": "select",
"checkbox": "checkbox",
"spinner": "spinner",
"hidden": "label only"
},
"select": {
"label": "Label",
"value": "Value"
},
"spinner": {
"min": "Minimum",
"max": "Maximum"
},
"errors": {
"scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it",
"invalidProperties": "Invalid properties:"
@@ -475,13 +379,9 @@
"addCategory": "Add new...",
"label": {
"subflows": "subflows",
"network": "network",
"common": "common",
"input": "input",
"output": "output",
"function": "function",
"sequence": "sequence",
"parser": "parser",
"social": "social",
"storage": "storage",
"analysis": "analysis",
@@ -547,8 +447,6 @@
"sortAZ": "a-z",
"sortRecent": "recent",
"more": "+ __count__ more",
"upload": "Upload module tgz file",
"refresh": "Refresh module list",
"errors": {
"catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
"installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
@@ -584,12 +482,11 @@
},
"sidebar": {
"info": {
"name": "Information",
"name": "Node information",
"tabName": "Name",
"label": "info",
"node": "Node",
"type": "Type",
"group": "Group",
"module": "Module",
"id": "ID",
"status": "Status",
@@ -612,29 +509,7 @@
"nodeHelp": "Node Help",
"none":"None",
"arrayItems": "__count__ items",
"showTips":"You can open the tips from the settings panel",
"outline": "Outline",
"empty": "empty",
"globalConfig": "Global Configuration Nodes",
"triggerAction": "Trigger action",
"find": "Find in workspace",
"search": {
"configNodes": "Configuration nodes",
"unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows"
}
},
"help": {
"name": "Help",
"label": "help",
"search": "Search help",
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showInOutline": "Show in outline",
"showTopics": "Show topics",
"noHelp": "No help topic selected"
"showTips":"You can open the tips from the settings panel"
},
"config": {
"name": "Configuration nodes",
@@ -643,10 +518,8 @@
"none": "none",
"subflows": "subflows",
"flows": "flows",
"filterAll": "all",
"showAllConfigNodes": "Show all config nodes",
"filterUnused": "unused",
"showAllUnusedConfigNodes": "Show all unused config nodes",
"filterUnused":"unused",
"filterAll":"all",
"filtered": "__count__ hidden"
},
"context": {
@@ -656,10 +529,11 @@
"refresh": "refresh to load",
"empty": "empty",
"node": "Node",
"subflow": "Subflow",
"flow": "Flow",
"global": "Global",
"deleteConfirm": "Are you sure you want to delete this item?",
"autoRefresh": "Refresh on selection change",
"autoRefresh": "Auto-refresh",
"refrsh": "Refresh",
"delete": "Delete"
},
@@ -676,7 +550,6 @@
"noSummaryAvailable": "No summary available",
"editDescription": "Edit project description",
"editDependencies": "Edit project dependencies",
"noDescriptionAvailable": "No description available",
"editReadme": "Edit README.md",
"showProjectSettings": "Show project settings",
"projectSettings": {
@@ -687,6 +560,7 @@
"removeFromProject": "remove from project",
"addToProject": "add to project",
"files": "Files",
"package": "Package",
"flow": "Flow",
"credentials": "Credentials",
"package":"Package",
@@ -725,12 +599,6 @@
"committerTip": "Leave blank to use system default",
"userName": "Username",
"email": "Email",
"workflow": "Workflow",
"workfowTip": "Choose your preferred git workflow",
"workflowManual": "Manual",
"workflowManualTip": "All changes must be manually committed under the 'history' sidebar",
"workflowAuto": "Automatic",
"workflowAutoTip": "Changes are committed automatically with every deploy",
"sshKeys": "SSH Keys",
"sshKeysTip": "Allows you to create secure connections to remote git repositories.",
"add": "add key",
@@ -836,8 +704,7 @@
"bin": "buffer",
"date": "timestamp",
"jsonata": "expression",
"env": "env variable",
"cred": "credential"
"env": "env variable"
}
},
"editableList": {
@@ -883,14 +750,10 @@
"copyPath": "Copy path to item",
"expandItems": "Expand items",
"collapseItems": "Collapse items",
"duplicate": "Duplicate",
"error": {
"invalidJSON": "Invalid JSON: "
}
"duplicate": "Duplicate"
},
"markdownEditor": {
"title": "Markdown editor",
"expand": "Expand",
"format": "Formatted with markdown",
"heading1": "Heading 1",
"heading2": "Heading 2",
@@ -1057,8 +920,7 @@
"passphrase": "Passphrase",
"retry": "Retry",
"update-failed": "Failed to update auth",
"unhandled": "Unhandled error response",
"host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again.</p>"
"unhandled": "Unhandled error response"
},
"create-branch-list": {
"invalid": "Invalid branch",
@@ -1078,19 +940,15 @@
},
"editor-tab": {
"properties": "Properties",
"envProperties": "Environment Variables",
"description": "Description",
"appearance": "Appearance",
"preview": "UI Preview",
"defaultValue": "Default value"
"env": "Environment Variables"
},
"languages" : {
"de": "German",
"en-US": "English",
"ja": "Japanese",
"ko": "Korean",
"ru": "Russian",
"zh-CN": "Chinese(Simplified)",
"zh-TW": "Chinese(Traditional)"
"zh-CN": "Chinese(Simplified)"
}
}

View File

@@ -1,7 +1,7 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "Casts the `arg` parameter to a string using the following casting rules:\n\n - Strings are unchanged\n - Functions are converted to an empty string\n - Numeric infinity and NaN throw an error because they cannot be represented as a JSON number\n - All other values are converted to a JSON string using the `JSON.stringify` function. If `prettify` is true, then \"prettified\" JSON is produced. i.e One line per field and lines will be indented based on the field depth."
"args": "arg",
"desc": "Casts the *arg* parameter to a string using the following casting rules:\n\n - Strings are unchanged\n - Functions are converted to an empty string\n - Numeric infinity and NaN throw an error because they cannot be represented as a JSON number\n - All other values are converted to a JSON string using the `JSON.stringify` function"
},
"$length": {
"args": "str",
@@ -185,7 +185,7 @@
},
"$reduce": {
"args":"array, function [, init]",
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation."
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`.\n\nThe optional `init` parameter is used as the initial value in the aggregation."
},
"$flowContext": {
"args": "string[, string]",
@@ -230,45 +230,6 @@
"$parseInteger": {
"args": "string, picture",
"desc": "Parses the contents of the `string` parameter to an integer (as a JSON number) using the format specified by the `picture` string. The `picture` string parameter has the same format as `$formatInteger`."
},
"$error": {
"args": "[str]",
"desc": "Throws an error with a message. The optional `str` will replace the default message of `$error() function evaluated`"
},
"$assert": {
"args": "arg, str",
"desc": "If `arg` is true the function returns undefined. If `arg` is false an exception is thrown with `str` as the message of the exception."
},
"$single": {
"args": "array, function",
"desc": "Returns the one and only value in the `array` parameter that satisfies the `function` predicate (i.e. the `function` returns Boolean `true` when passed the value). Throws an exception if the number of matching values is not exactly one.\n\nThe function should be supplied in the following signature: `function(value [, index [, array]])` where value is each input of the array, index is the position of that value and the whole array is passed as the third argument"
},
"$encodeUrl": {
"args": "str",
"desc": "Encodes a Uniform Resource Locator (URL) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character.\n\nExample: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Encodes a Uniform Resource Locator (URL) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character. \n\nExample: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "Decodes a Uniform Resource Locator (URL) component previously created by encodeUrlComponent. \n\nExample: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "Decodes a Uniform Resource Locator (URL) previously created by encodeUrl. \n\nExample: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "Returns an array with duplicate values removed from `array`"
},
"$type": {
"args": "value",
"desc": "Returns the type of `value` as a string. If `value` is undefined, this will return `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Gets a date object using the Moment library."
}
}

202
packages/node_modules/@node-red/editor-client/locales/ja/editor.json vendored Normal file → Executable file
View File

@@ -14,37 +14,9 @@
"back": "戻る",
"next": "進む",
"clone": "プロジェクトをクローン",
"cont": "続ける",
"style": "形式",
"line": "線",
"fill": "塗りつぶし",
"label": "ラベル",
"color": "色",
"position": "配置",
"enable": "有効",
"disable": "無効",
"upload": "アップロード"
},
"type": {
"string": "文字列",
"number": "数値",
"boolean": "真偽値",
"array": "配列",
"buffer": "バッファ",
"object": "オブジェクト",
"jsonString": "JSON文字列",
"undefined": "undefined",
"null": "null"
"cont": "続ける"
}
},
"event": {
"loadPalette": "パレットを読み込み中",
"loadNodeCatalogs": "ノードカタログを読み込み中",
"loadNodes": "ノードを読み込み中 __count__",
"loadFlows": "フローを読み込み中",
"importFlows": "ワークスペースにフローを追加中",
"importError": "<p>フロー追加エラー</p><p>__message__</p>"
},
"workspace": {
"defaultName": "フロー __number__",
"editFlow": "フローを編集: __name__",
@@ -84,7 +56,7 @@
"settings": "設定",
"userSettings": "ユーザ設定",
"nodes": "ノード",
"displayStatus": "ノードのステータスを表示",
"displayStatus": "ノードの状態を表示",
"displayConfig": "ノードの設定",
"import": "読み込み",
"export": "書き出し",
@@ -108,12 +80,7 @@
"projects-new": "新規",
"projects-open": "開く",
"projects-settings": "設定",
"showNodeLabelDefault": "追加したノードのラベルを表示",
"groups": "グループ",
"groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除"
"showNodeLabelDefault": "追加したノードのラベルを表示する"
}
},
"actions": {
@@ -193,34 +160,22 @@
"node_plural": "__count__ 個のノード",
"configNode": "__count__ 個の設定ノード",
"configNode_plural": "__count__ 個の設定ノード",
"group": "__count__ 個のグループ",
"group_plural": "__count__ 個のグループ",
"flow": "__count__ 個のフロー",
"flow_plural": "__count__ 個のフロー",
"subflow": "__count__ 個のサブフロー",
"subflow_plural": "__count__ 個のサブフロー",
"replacedNodes": "置換された __count__ 個のノード",
"replacedNodes_plural": "置換された __count__ 個のノード",
"pasteNodes": "JSON形式のフローデータを貼り付け",
"selectFile": "読み込むファイルを選択",
"importNodes": "フローをクリップボードから読み込み",
"pasteNodes": "JSON形式のフローデータを貼り付けてください",
"selectFile": "読み込むファイルを選択してください",
"importNodes": "フローをクリップボートから読み込み",
"exportNodes": "フローをクリップボードへ書き出し",
"download": "ダウンロード",
"importUnrecognised": "認識できない型が読み込まれました:",
"importUnrecognised_plural": "認識できない型が読み込まれました:",
"importDuplicate": "重複したノードを読み込みました:",
"importDuplicate_plural": "重複したノードを読み込みました:",
"nodesExported": "クリップボードへフローを書き出しました",
"nodesImported": "読み込みました:",
"nodeCopied": "__count__ 個のノードをコピーしました",
"nodeCopied_plural": "__count__ 個のノードをコピーしました",
"groupCopied": "__count__ 個のグループをコピーしました",
"groupCopied_plural": "__count__ 個のグループをコピーしました",
"groupStyleCopied": "グループの形式をコピーしました",
"invalidFlow": "不正なフロー: __message__",
"recoveredNodes": "復旧したノード",
"recoveredNodesInfo": "このフロー内のードは読み込み時に、有効なフローIDがありませんでした。これらフローIDは、フローに追加されているため、復元または削除できます。",
"recoveredNodesNotification": "<p>有効なフローIDを持たないードが読み込まれました</p><p>これらノードは '__flowName__' という新しいフローへ追加されました。</p>",
"export": {
"selected": "選択したフロー",
"current": "現在のタブ",
@@ -235,19 +190,13 @@
},
"import": {
"import": "読み込み先",
"importSelected": "選択したノードを読み込み",
"importCopy": "コピーを読み込み",
"viewNodes": "ノードを参照...",
"newFlow": "新規のタブ",
"replace": "置換",
"errors": {
"notArray": "JSON形式の配列ではありません",
"itemNotObject": "不正なフロー - __index__ 番目の要素はノードオブジェクトではありません",
"missingId": "不正なフロー - __index__ 番目の要素に'id'プロパティがありません",
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
},
"conflictNotification1": "読み込もうとしているノードのいくつかは、既にワークスペース内に存在しています。",
"conflictNotification2": "読み込むノードを選択し、また既存のノードを置き換えるか、もしくはそれらのコピーを読み込むかも選択してください。"
}
},
"copyMessagePath": "パスをコピーしました",
"copyMessageValue": "値をコピーしました",
@@ -348,13 +297,6 @@
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
}
},
"group": {
"editGroup": "__name__ グループを編集",
"errors": {
"cannotCreateDiffGroups": "異なるグループのノードを使用してグループを作成することはできません",
"cannotAddSubflowPorts": "グループにサブフローの端子を追加できません"
}
},
"editor": {
"configEdit": "編集",
"configAdd": "追加",
@@ -368,12 +310,10 @@
"addNewType": "新規に __type__ を追加...",
"nodeProperties": "プロパティ",
"label": "ラベル",
"color": "色",
"portLabels": "ポートラベル",
"labelInputs": "入力",
"labelOutputs": "出力",
"settingIcon": "アイコン",
"default": "デフォルト",
"noDefaultLabel": "なし",
"defaultLabel": "既定のラベルを使用",
"searchIcons": "アイコンを検索",
@@ -381,42 +321,6 @@
"description": "詳細",
"show": "表示",
"hide": "非表示",
"locale": "UI言語の選択",
"icon": "記号",
"inputType": "入力形式",
"selectType": "形式選択...",
"inputs": {
"input": "入力",
"select": "メニュー",
"checkbox": "チェックボックス",
"spinner": "スピナー",
"none": "無し",
"hidden": "非表示"
},
"types": {
"str": "文字列",
"num": "数値",
"bool": "真偽",
"json": "JSON",
"bin": "バッファ",
"env": "環境変数",
"cred": "認証情報"
},
"menu": {
"input": "入力",
"select": "選択",
"checkbox": "チェックボックス",
"spinner": "数値",
"hidden": "ラベルのみ"
},
"select": {
"label": "ラベル",
"value": "値"
},
"spinner": {
"min": "最小値",
"max": "最大値"
},
"errors": {
"scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします",
"invalidProperties": "プロパティが不正です:"
@@ -447,8 +351,7 @@
"pasteNode": "ノードを貼り付け",
"undoChange": "変更操作を戻す",
"searchBox": "ノードを検索",
"managePalette": "パレットの管理",
"actionList": "動作一覧"
"managePalette": "パレットの管理"
},
"library": {
"library": "ライブラリ",
@@ -475,13 +378,9 @@
"addCategory": "新規追加...",
"label": {
"subflows": "サブフロー",
"network": "ネットワーク",
"common": "共通",
"input": "入力",
"output": "出力",
"function": "機能",
"sequence": "シーケンス",
"parser": "パーサ",
"social": "ソーシャル",
"storage": "ストレージ",
"analysis": "分析",
@@ -547,8 +446,6 @@
"sortAZ": "辞書順",
"sortRecent": "日付順",
"more": "+ さらに __count__ 個",
"upload": "モジュールのtgzファイルをアップロード",
"refresh": "モジュールリスト更新",
"errors": {
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
@@ -589,7 +486,6 @@
"label": "情報",
"node": "ノード",
"type": "型",
"group": "グループ",
"module": "モジュール",
"id": "ID",
"status": "状態",
@@ -612,29 +508,7 @@
"nodeHelp": "ノードのヘルプ",
"none": "なし",
"arrayItems": "__count__ 要素",
"showTips": "設定からヒントを表示できます",
"outline": "アウトライン",
"empty": "空",
"globalConfig": "グローバル設定ノード",
"triggerAction": "アクションを実行",
"find": "ワークスペース内を検索",
"search": {
"configNodes": "設定ノード",
"unusedConfigNodes": "未使用の設定ノード",
"invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー"
}
},
"help": {
"name": "ヘルプ",
"label": "ヘルプ",
"search": "ヘルプを検索",
"nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示",
"showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択"
"showTips": "設定からヒントを表示できます"
},
"config": {
"name": "ノードの設定を表示",
@@ -643,10 +517,8 @@
"none": "なし",
"subflows": "サブフロー",
"flows": "フロー",
"filterAll": "全て",
"showAllConfigNodes": "全設定ノードを表示",
"filterUnused": "未使用",
"showAllUnusedConfigNodes": "未使用の全設定ノードを表示",
"filterAll": "全て",
"filtered": "__count__ 個が無効"
},
"context": {
@@ -655,13 +527,11 @@
"none": "選択されていません",
"refresh": "読み込みのため更新してください",
"empty": "データが存在しません",
"node": "ノード",
"flow": "フロー",
"global": "グローバル",
"node": "Node",
"flow": "Flow",
"global": "Global",
"deleteConfirm": "データを削除しても良いですか?",
"autoRefresh": "選択対象が変化した場合更新",
"refrsh": "更新",
"delete": "削除"
"autoRefresh": "自動更新"
},
"palette": {
"name": "パレットの管理",
@@ -673,10 +543,9 @@
"description": "詳細",
"dependencies": "依存関係",
"settings": "設定",
"noSummaryAvailable": "要約が存在しません",
"noSummaryAvailable": "サマリが存在しません",
"editDescription": "プロジェクトの詳細を編集",
"editDependencies": "プロジェクトの依存関係を編集",
"noDescriptionAvailable": "詳細が存在しません",
"editReadme": "README.mdを編集",
"showProjectSettings": "プロジェクト設定を表示",
"projectSettings": {
@@ -687,9 +556,9 @@
"removeFromProject": "プロジェクトから削除",
"addToProject": "プロジェクトへ追加",
"files": "ファイル",
"package": "パッケージ",
"flow": "フロー",
"credentials": "認証情報",
"package": "パッケージ",
"packageCreate": "変更が保存された時にファイルが作成されます",
"fileNotExist": "ファイルが存在しません",
"selectFile": "ファイルを選択",
@@ -725,12 +594,6 @@
"committerTip": "システムのデフォルトを使用する場合、空白のままにしてください",
"userName": "ユーザ名",
"email": "メールアドレス",
"workflow": "ワークフロー",
"workfowTip": "望ましいgitワークフローを選択してください",
"workflowManual": "手動",
"workflowManualTip": "全ての変更は「履歴」サイドバー内で手動でコミットする必要があります",
"workflowAuto": "自動",
"workflowAutoTip": "変更はデプロイの度に自動的にコミットされます",
"sshKeys": "SSH キー",
"sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。",
"add": "キーを追加",
@@ -836,8 +699,7 @@
"bin": "バッファ",
"date": "日時",
"jsonata": "JSONata式",
"env": "環境変数",
"cred": "認証情報"
"env": "環境変数"
}
},
"editableList": {
@@ -874,23 +736,10 @@
},
"jsonEditor": {
"title": "JSONエディタ",
"format": "JSONフォーマット",
"rawMode": "JSONを編集",
"uiMode": "ビジュアルエディタ",
"insertAbove": "上に挿入",
"insertBelow": "下に挿入",
"addItem": "要素を追加",
"copyPath": "要素のパスをコピー",
"expandItems": "要素を展開",
"collapseItems": "要素を折り畳む",
"duplicate": "複製",
"error": {
"invalidJSON": "不正なJSON: "
}
"format": "JSONフォーマット"
},
"markdownEditor": {
"title": "マークダウンエディタ",
"expand": "拡大",
"format": "マークダウン形式で記述",
"heading1": "見出しレベル1",
"heading2": "見出しレベル2",
@@ -1051,14 +900,13 @@
"confirm": "<p>デプロイされていない変更は失われます。</p><p>続けますか?</p>"
},
"send-req": {
"auth-req": "リポジトリ対する認証が必要です",
"auth-req": "リポジトリ対する認証が必要です",
"username": "ユーザ名",
"password": "パスワード",
"passphrase": "パスフレーズ",
"retry": "リトライ",
"update-failed": "認証の更新に失敗しました",
"unhandled": "エラー応答が処理されませんでした",
"host-key-verify-failed": "<p>ホストキーの検証に失敗</p><p>リポジトリのホストキーを検証できませんでした。<code>known_hosts</code>ファイルを更新して、もう一度試してください。</p>"
"unhandled": "エラー応答が処理されませんでした"
},
"create-branch-list": {
"invalid": "不正なブランチ",
@@ -1078,19 +926,15 @@
},
"editor-tab": {
"properties": "プロパティ",
"envProperties": "環境変数",
"description": "説明",
"appearance": "外観",
"preview": "UIプレビュー",
"defaultValue": "デフォルト値"
"env": "環境変数"
},
"languages": {
"languages" : {
"de": "ドイツ語",
"en-US": "英語",
"ja": "日本語",
"ko": "韓国語",
"ru": "ロシア語",
"zh-CN": "中国語(簡体)",
"zh-TW": "中国語(繁体)"
"zh-CN": "中国語(簡体)"
}
}

46
packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json vendored Normal file → Executable file
View File

@@ -1,7 +1,7 @@
{
"$string": {
"args": "arg[, prettify]",
"desc": "以下の型変換ルールを用いて、引数 *arg* を文字列へ型変換します。:\n\n - 文字列は変換しません。\n - 関数は空の文字列に変換します。\n - JSONの数値として表現できないため、無限大やNaNはエラーになります。\n - 他の値は `JSON.stringify` 関数を用いて、JSONの文字列へ変換します。`prettify`が真の場合、JSONを整形出力します。フィールドを1行毎に出力。フィールドのネスト深さによってインデントを行います。"
"args": "arg",
"desc": "以下の型変換ルールを用いて、引数 *arg* を文字列へ型変換します。:\n\n - 文字列は変換しません。\n - 関数は空の文字列に変換します。\n - JSONの数値として表現できないため、無限大やNaNはエラーになります。\n - 他の値は `JSON.stringify` 関数を用いて、JSONの文字列へ変換します。"
},
"$length": {
"args": "str",
@@ -185,7 +185,7 @@
},
"$reduce": {
"args": "array, function [, init]",
"desc": "配列の各要素値に関数 `function` を連続的に適用して得られる集約値を返します。 `function` の適用の際には、直前の `function` の適用結果と要素値が引数として与えられます。\n\n関数 `function` は引数を2つ取り、配列の各要素の間に配置する中置演算子のように作用しなくてはなりません。関数`function`のシグネチャは`myfunc($accumulator, $value[, $index[, $array]])`という形式でなければなりません。\n\n任意の引数 `init` には、集約時の初期値を設定します。"
"desc": "配列の各要素値に関数 `function` を連続的に適用して得られる集約値を返します。 `function` の適用の際には、直前の `function` の適用結果と要素値が引数として与えられます。\n\n関数 `function` は引数を2つ取り、配列の各要素の間に配置する中置演算子のように作用しなくてはなりません。\n\n任意の引数 `init` には、集約時の初期値を設定します。"
},
"$flowContext": {
"args": "string",
@@ -230,45 +230,5 @@
"$parseInteger": {
"args": "string, picture",
"desc": "`picture`文字列の指定に従って、`string`パラメータを整数(JSON数値)に変換します。`picture`文字列は`$formatInteger`と同じ形式です。"
},
"$error": {
"args": "[str]",
"desc": "メッセージを指定して例外を送出します。メッセージ`str`を省略した場合は`$error() function evaluated`をメッセージとします。"
},
"$assert": {
"args": "arg, str",
"desc": "`arg`が真の場合、undefinedを返します。偽の場合、`str`をメッセージとする例外を送出します。"
},
"$single": {
"args": "array, function",
"desc": "`array`の要素のうち、条件判定関数`function`を満たす(`function`に与えた場合に真偽値`true`を返す)要素が1つのみである場合、それを返します。マッチする要素が1つのみでない場合、例外を送出します。\n\n指定する関数は`function(value [, index [, array]])`というシグネチャでなければなりません。ここで、`value`は`array`の要素値、`index`は要素の添字、第三引数には配列全体を渡します。"
},
"$encodeUrl": {
"args": "str",
"desc": "Uniform Resource Locator (URL)を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "Uniform Resource Locator (URL)要素を構成する文字を1、2、3、もしくは、4文字エスケープシーケンスのUTF-8文字エンコーディングで置換します。\n\n例: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "encodeUrlComponentで置換したUniform Resource Locator (URL)をデコードします。\n\n例: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "encodeUrlで置換したUniform Resource Locator (URL)要素をデコードします。 \n\n例: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "配列`array`から重複要素を削除した配列を返します。"
},
"$type": {
"args": "value",
"desc": "`value` の型を文字列として返します。もし `value` が未定義の場合、 `undefined` が返されます。"
},
"$moment": {
"args": "[str]",
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
}
}

View File

@@ -273,6 +273,7 @@
"deleteSubflow": "서브 플로우 삭제",
"info": "상세내역",
"category": "카테고리",
"format": "Markdown 형식",
"errors": {
"noNodesSelected": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 노드가 선택되지 않았습니다",
"multipleInputsToSelection": "<strong>서브 플로우를 생성할 수 없습니다</strong> : 복수의 입력이 선택되었습니다"
@@ -494,8 +495,8 @@
"none": "없음",
"subflows": "보조 플로우",
"flows": "플로우",
"filterAll": "전체",
"filterUnused": "미사용",
"filterAll": "전체",
"filtered": "__count__ 개 숨김"
},
"context": {

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
{
"$string": {
"args": "arg",
"desc": "通过以下的类型转换规则将参数 *arg* 转换成字符串:\n\n - 字符串不转换。\n -函数转换成空的字符串。\n - JSON的值无法用数字表示所以用无限大或者NaN非数表示。\n - 用 `JSON.stringify` 函数将其他值转换成JSON字符串。"
"desc": "通过以下的类型转换规则将参数*arg*转换成字符串:\n\n - 字符串不转换。\n -函数转换成空的字符串。\n - JSON的值无法用数字表示所以用无限大或者NaN非数表示。\n - 用JSON.stringify函数将其他值转换成JSON字符串。"
},
"$length": {
"args": "str",
"desc": "输出字符串 `str` 的字数。如果 `str` 不是字符串,抛出错误。"
"desc": "输出字符串str的字数。如果str不是字符串,抛出错误。"
},
"$substring": {
"args": "str, start[, length]",
"desc": "输出 `start` 位置后的的首次出现的包括 `str` 的子字符串。 如果 `length` 被指定,那么的字符串中将只包括前 `length` 个文字。如果 `start` 是负数则输出从 `str` 末尾开始的 `length` 个文字"
"desc": "输出`start`位置后的的首次出现的包括`str`的子字符串。 如果`length`被指定,那么的字符串中将只包括前`length`个文字。如果`start`是负数则输出从`str`末尾开始的`length`个文字"
},
"$substringBefore": {
"args": "str, chars",
@@ -17,11 +17,11 @@
},
"$substringAfter": {
"args": "str, chars",
"desc": "输出 `str` 中首次出现的 `chars` 之后的子字符串,如果 `str` 中不包括 `chars` 则输出 `str` 。"
"desc": "输出str中首次出现的chars之后的子字符串,如果str中不包括chars则输出str。"
},
"$uppercase": {
"args": "str",
"desc": "将 `str` 中的所有字母变为大写后输出。"
"desc": "`将’str中的所有字母变为大写后输出。"
},
"$lowercase": {
"args": "str",
@@ -29,27 +29,27 @@
},
"$trim": {
"args": "str",
"desc": "将以下步骤应用于 `str` 来去除所有空白文字并实现标准化。\n\n 将全部tab制表符、回车键、换行字符用空白代替。\n- 将连续的空白文字变成一个空白文字。\n- 消除开头和末尾的空白文字。\n\n如果 `str` 没有被指定(即在无输入参数的情况下调用本函数),将上下文的值作为 `str` 来使用。 如果 `str` 不是字符串则抛出错误。"
"desc": "将以下步骤应用于`str`来去除所有空白文字并实现标准化。\n\n 将全部tab制表符、回车键、换行字符用空白代替。\n- 将连续的空白文字变成一个空白文字。\n- 消除开头和末尾的空白文字。\n\n如果`str`没有被指定(即在无输入参数的情况下调用本函数),将上下文的值作为`str`来使用。 如果`str` 不是字符串则抛出错误。"
},
"$contains": {
"args": "str, pattern",
"desc": "字符串 `str` 和 `pattern` 匹配的话输出 `true` ,不匹配的情况下输出 `false` 。 不指定 `str` 的情况下(比如用一个参数调用本函数时)、将上下文的值作为 `str` 来使用。参数 `pattern` 可以为字符串或正则表达。"
"desc": "字符串`str` 和 `pattern`匹配的话输出`true`,不匹配的情况下输出 `false`。 不指定`str`的情况下(比如用一个参数调用本函数时)、将上下文的值作为`str`来使用。参数 `pattern`可以为字符串或正则表达。"
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "将参数 `str` 分解成由子字符串组成的数组。 如果 `str` 不是字符串抛出错误。可以省略的参数 `separator` 中指定字符串 `str` 的分隔符。分隔符可以是文字或正则表达式。在不指定 `separator` 的情况下、将分隔符看作空的字符串并把 `str` 拆分成由单个字母组成的数组。如果 `separator` 不是字符串则抛出错误。在可省略的参数 `limit` 中指定分割后的子字符串的最大个数。超出个数的子字符串将被舍弃。如果 `limit` 没有被指定,`str` 将不考虑子字符串的个数而将字符串完全分隔。如果 `limit` 是负数则抛出错误。"
"desc": "将参数`str`分解成由子字符串组成的数组。 如果`str`不是字符串抛出错误。可以省略的参数 `separator`中指定字符串`str`的分隔符。分隔符可以是文字或正则表达式。在不指定`separator`的情况下、将分隔符看作空的字符串并把`str`拆分成由单个字母组成的数组。如果`separator`不是字符串则抛出错误。在可省略的参数`limit`中指定分割后的子字符串的最大个数。超出个数的子字符串将被舍弃。如果`limit`没有被指定,`str` 将不考虑子字符串的个数而将字符串完全分隔。如果`limit`是负数则抛出错误。"
},
"$join": {
"args": "array[, separator]",
"desc": "用可以省略的参数 `separator` 来把多个字符串连接。如果 `array` 不是字符串则抛出错误。 如果没有指定 `separator` ,则用空字符串来连接字符(即字符串之间没有 `separator` )。 如果 `separator` 不是字符则抛出错误。"
"desc": "用可以省略的参数 `separator`来把多个字符串连接。如果`array`不是字符串则抛出错误。 如果没有指定`separator`,则用空字符串来连接字符(即字符串之间没有`separator`)。 如果`separator`不是字符则抛出错误。"
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "对字符串 `str` 使用正则表达式 `pattern` 并输出与 `str` 相匹配的部分信息。"
"desc": "对字符串`str`使用正则表达式`pattern`并输出与`str`相匹配的部分信息。"
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "在字符串 `str` 中搜索 `pattern` 并用 `replacement` 来替换。\n\n可选参数 `limit` 用来指定替换次数的上限。"
"desc": "在字符串`str`中搜索`pattern`并用`replacement`来替换。\n\n可选参数`limit`用来指定替换次数的上限。"
},
"$now": {
"args": "",
@@ -65,31 +65,31 @@
},
"$number": {
"args": "arg",
"desc": "用下述的规则将参数 `arg` 转换为数值。:\n\n 数值不做转换。\n 将字符串中合法的JSON数値表示转换成数値。\n 其他形式的值则抛出错误。"
"desc": "用下述的规则将参数 `arg`转换为数值。:\n\n 数值不做转换。\n 将字符串中合法的JSON数値表示转换成数値。\n 其他形式的值则抛出错误。"
},
"$abs": {
"args": "number",
"desc": "输出参数 `number` 的绝对值。"
"desc": "输出参数`number`的绝对值。"
},
"$floor": {
"args": "number",
"desc": "输出比 `number` 的值小的最大整数。"
"desc": "输出比`number`的值小的最大整数。"
},
"$ceil": {
"args": "number",
"desc": "输出比 `number` 的值大的最小整数。"
"desc": "输出比`number`的值大的最小整数。"
},
"$round": {
"args": "number [, precision]",
"desc": "输出四舍五入后的参数 `number` 。可省略的参数 `precision` 指定四舍五入后小数点下的位数。"
"desc": "输出四舍五入后的参数`number`。可省略的参数 `precision`指定四舍五入后小数点下的位数。"
},
"$power": {
"args": "base, exponent",
"desc": "输出底数 `base``exponent` 次幂。"
"desc": "输出底数`base``exponent`次幂。"
},
"$sqrt": {
"args": "number",
"desc": "输出参数 `number` 的平方根。"
"desc": "输出参数 `number`的平方根。"
},
"$random": {
"args": "",
@@ -97,35 +97,35 @@
},
"$millis": {
"args": "",
"desc": "返回从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。在同一个表达式的测试中所有对 `$millis()` 的调用将会返回相同的值。"
"desc": "返回从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。在同一个表达式的测试中所有对`$millis()`的调用将会返回相同的值。"
},
"$sum": {
"args": "array",
"desc": "输出数组 `array` 的总和。如果 `array` 不是数值则抛出错误。"
"desc": "输出数组`array`的总和。如果`array`不是数值则抛出错误。"
},
"$max": {
"args": "array",
"desc": "输出数组 `array` 的最大值。如果 `array` 不是数值则抛出错误。"
"desc": "输出数组`array`的最大值。如果`array`不是数值则抛出错误。"
},
"$min": {
"args": "array",
"desc": "输出数组 `array` 的最小值。如果 `array` 不是数值则抛出错误。。"
"desc": "输出数组`array`的最小值。如果`array`不是数值则抛出错误。。"
},
"$average": {
"args": "array",
"desc": "输出数组 `array` 的平均数。如果 `array` 不是数值则抛出错误。。"
"desc": "输出数组`array`的平均数。如果`array`不是数值则抛出错误。。"
},
"$boolean": {
"args": "arg",
"desc": "用下述规则将数据转换成布尔值。:\n\n - 不转换布尔值 `Boolean` 。\n 将空的字符串 `string` 转换为 `false` \n 将不为空的字符串 `string` 转换为 `true` \n 将为0的数字 `number` 转换成 `false` \n 将不为0的数字 `number` 转换成 `true` \n –将 `null` 转换成 `false` \n –将空的数组 `array` 转换成 `false` \n –如果数组 `array` 中含有可以转换成 `true` 的要素则转换成 `true` \n –如果 `array` 中没有可转换成 `true` 的要素则转换成 `false` \n 空的对象 `object` 转换成 `false` \n 非空的对象 `object` 转换成 `true` \n –将函数 `function` 转换成 `false` "
"desc": "用下述规则将数据转换成布尔值。:\n\n - 不转换布尔值`Boolean`。\n 将空的字符串`string`转换为`false`\n 将不为空的字符串`string`转换为`true`\n 将为0的数字`number`转换成`false`\n 将不为0的数字`number`转换成`true`\n –将`null`转换成`false`\n –将空的数组`array`转换成`false`\n –如果数组`array`中含有可以转换成`true`的要素则转换成`true`\n –如果`array`中没有可转换成`true`的要素则转换成`false`\n 空的对象`object`转换成`false`\n 非空的对象`object`转换成`true`\n –将函数`function`转换成`false`"
},
"$not": {
"args": "arg",
"desc": "输出做取反运算后的布尔值。首先将 `arg` 转换为布尔值。"
"desc": "输出做取反运算后的布尔值。首先将`arg`转换为布尔值。"
},
"$exists": {
"args": "arg",
"desc": "如果算式 `arg` 的值存在则输出 `true` 。如果算式的值不存在(比如指向不存在区域的引用)则输出 `false` 。"
"desc": "如果算式`arg`的值存在则输出`true`。如果算式的值不存在(比如指向不存在区域的引用)则输出`false`。"
},
"$count": {
"args": "array",
@@ -137,15 +137,15 @@
},
"$sort": {
"args": "array [, function]",
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
"desc": "输出排序后的数组`array`。\n\n如果使用了比较函数`function`,则下述两个参数需要被指定。\n\n`function(left, right)`\n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值`true`来表示位置交换。而在不需要位置交换时函数必须输出`false`。"
},
"$reverse": {
"args": "array",
"desc": "输出倒序后的数组 `array` 。"
"desc": "输出倒序后的数组`array`。"
},
"$shuffle": {
"args": "array",
"desc": "输出随机排序后的数组 `array` 。"
"desc": "输出随机排序后的数组 `array`。"
},
"$zip": {
"args": "array, ...",
@@ -157,35 +157,35 @@
},
"$lookup": {
"args": "object, key",
"desc": "输出对象中与参数 `key` 对应的值。如果第一个参数 `object` 是数组,那么数组中所有的对象都将被搜索并输出这些对象中与参数 `key` 对应的值。"
"desc": "输出对象中与参数`key`对应的值。如果第一个参数`object`是数组,那么数组中所有的对象都将被搜索并输出这些对象中与参数`key`对应的值。"
},
"$spread": {
"args": "object",
"desc": "将对象中的键值对分隔成每个要素中只含有一个键值对的数组。如果参数 `object` 是数组,那么返回值的数组中包含所有对象中的键值对。"
"desc": "将对象中的键值对分隔成每个要素中只含有一个键值对的数组。如果参数`object`是数组,那么返回值的数组中包含所有对象中的键值对。"
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "将输入数组 `objects` 中所有的键值对合并到一个 `object` 中并返回。如果输入数组的要素中含有重复的键,则返回的 `object` 中将只包含数组中最后出现要素的值。如果输入数组中包括对象以外的元素,则抛出错误。"
"desc": "将输入数组`objects`中所有的键值对合并到一个`object`中并返回。如果输入数组的要素中含有重复的键,则返回的`object`中将只包含数组中最后出现要素的值。如果输入数组中包括对象以外的元素,则抛出错误。"
},
"$sift": {
"args": "object, function",
"desc": "输出参数 `object` 中符合 `function` 的键值对。\n\n `function` 必须含有下述参数。\n\n `function(value [, key [, object]])` "
"desc": "输出参数`object`中符合`function`的键值对。\n\n`function`必须含有下述参数。\n\n`function(value [, key [, object]])`"
},
"$each": {
"args": "object, function",
"desc": "将函数 `function` 应用于 `object` 中的所有键值对并输出由所有返回值组成的数组。"
"desc": "将函数`function`应用于`object`中的所有键值对并输出由所有返回值组成的数组。"
},
"$map": {
"args": "array, function",
"desc": "将函数 `function` 应用于数组 `array` 中所有的值并输出由返回值组成的数组。\n\n `function` 中必须含有下述参数。\n\n`function(value [, index [, array]])` "
"desc": "将函数`function`应用于数组`array`中所有的值并输出由返回值组成的数组。\n\n`function`中必须含有下述参数。\n\n`function(value [, index [, array]])`"
},
"$filter": {
"args": "array, function",
"desc": "输出数组 `array` 中符合函数 `function` 条件的值组成的数组。\n\n `function` 必须包括下述参数。\n\n `function(value [, index [, array]])`"
"desc": "输出数组`array`中符合函数`function`条件的值组成的数组。\n\n`function`必须包括下述参数。\n\n`function(value [, index [, array]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "将 `function` 依次应用于数组中的各要素值。 其中,前一个要素值的计算结果将参与到下一次的函数运算中。。\n\n函数 `function` 接受两个参数并作为中缀表示法中的操作符。\n\n可省略的参数 `init` 将作为运算的初始值。"
"desc": "将`function`依次应用于数组中的各要素值。 其中,前一个要素值的计算结果将参与到下一次的函数运算中。。\n\n函数`function`接受两个参数并作为中缀表示法中的操作符。\n\n可省略的参数`init`将作为运算的初始值。"
},
"$flowContext": {
"args": "string",
@@ -197,7 +197,7 @@
},
"$pad": {
"args": "string, width [, char]",
"desc": "根据需要,向字符串 `string` 的副本中填充文字使该字符串的字数达到 `width` 的绝对值并返回填充文字后的字符串。\n\n如果 `width` 的值为正,则向字符串 `string` 的右侧填充文字,如果 `width` 为负,则向字符串 `string` 的左侧填充文字。\n\n可选参数 `char` 用来指定填充的文字。如果未指定该参数,则填充空白文字。"
"desc": "根据需要,向字符串`string`的副本中填充文字使该字符串的字数达到`width`的绝对值并返回填充文字后的字符串。\n\n如果`width`的值为正,则向字符串`string`的右侧填充文字,如果`width`为负,则向字符串`string`的左侧填充文字。\n\n可选参数`char`用来指定填充的文字。如果未指定该参数,则填充空白文字。"
},
"$fromMillis": {
"args": "number",
@@ -205,70 +205,14 @@
},
"$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规格中记述的数值格式。"
"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之间否则抛出错误。"
"desc": "将`number`变换为以参数`radix`的值为基数形式的字符串。如果不指定`radix`的值则默认基数为10。指定的`radix`值必须在236之间否则抛出错误。"
},
"$toMillis": {
"args": "timestamp",
"desc": "将ISO 8601格式的字符串 `timestamp` 转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
},
"$env": {
"args": "arg",
"desc": "返回环境变量的值。\n\n这是Node-RED定义的函数。"
},
"$eval": {
"args": "expr [, context]",
"desc": "使用当前上下文来作为评估依据,分析并评估字符串 `expr` 其中包含文字JSON或JSONata表达式。"
},
"$formatInteger": {
"args": "number, picture",
"desc": "将“数字”转换为字符串并将其格式化为“图片”字符串指定的整数表示形式。图片字符串参数定义了数字的格式并具有与XPath F&O 3.1 规范中的fnformat-integer相同的语法。"
},
"$parseInteger": {
"args": "string, picture",
"desc": "使用“图片”字符串指定的格式将“字符串”参数的内容解析为整数作为JSON数字。图片字符串参数与$formatInteger格式相同。."
},
"$error": {
"args": "[str]",
"desc": "引发错误并显示一条消息。 可选的 `str` 将替代$error()函数评估的默认消息。"
},
"$assert": {
"args": "arg, str",
"desc": "如果 `arg` 为真,则该函数返回。 如果arg为假则抛出带有str的异常作为异常消息。"
},
"$single": {
"args": "array, function",
"desc": "返回满足参数function谓语的array参数中的唯一值 (比如传递值时函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数 `functionvalue [index [array []]]` 其中value是数组的每个输入index是该值的位置整个数组作为第三个参数传递。"
},
"$encodeUrl": {
"args": "str",
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL组件进行编码。\n\n示例 `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL进行编码。\n\n示例 `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "解码以前由encodeUrlComponent创建的统一资源定位器URL组件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "解码先前由encodeUrl创建的统一资源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "返回一个数组,其中重复的值已从 `数组` 中删除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回 `值` 的类型。 如果该 `值` 未定义,则将返回 `未定义` "
},
"$moment": {
"args": "[str]",
"desc": "使用Moment库获取日期对象。"
"desc": "将ISO 8601格式的字符串`timestamp`转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
{
"info": {
"tip0" : "您可以用 {{core:delete-selection}} 刪除選擇的節點或連結。",
"tip1" : "{{core:search}} 可以在流程內搜索節點。",
"tip2": "{{core:toggle-sidebar}} 可以顯示或隱藏邊側欄。",
"tip3": "您可以在 {{core:manage-palette}} 中管理節點的控制台。",
"tip4": "側邊欄中會列出流程中所有的配置節點。您可以通過功能表或者 {{core:show-config-tab}} 來訪問這些節點。",
"tip5": "您可以在設定中選擇顯示或隱藏這些提示。",
"tip6": "您可以用[left] [up] [down] [right]鍵來移動被選中的節點。按住[shift]可以更快地移動節點。",
"tip7": "把節點拖到連接上可以向連接中插入節點。",
"tip8": "您可以用 {{core:show-export-dialog}} 來匯出被選中的節點或標籤頁中的流程。",
"tip9": "您可以將流程的json文字檔拖入編輯方塊或 {{core:show-import-dialog}} 來導入流程。",
"tip10": "按住[shift]後按一下並拖動節點可以將該節點的多個連接一併移動到其他節點的埠。",
"tip11": "{{core:show-info-tab}} 可以顯示「資訊」標籤頁。 {{core:show-debug-tab}} 可以顯示「調試」標籤頁。",
"tip12": "按住[ctrl]的同時點擊工作介面可以在節點的對話欄中快速添加節點。",
"tip13": "按住[ctrl]的同時點擊節點的埠或後續節點可以快速連接多個節點。",
"tip14": "按住[shift]的同時點擊節點會選中所有被連接的節點。",
"tip15": "按住[ctrl]的同時點擊節點可以在選中或取消選中節點。",
"tip16": "{{core:show-previous-tab}} 和 {{core:show-next-tab}} 可以切換標籤頁。",
"tip17": "您可以在節點的屬性配置畫面中通過 {{core:confirm-edit-tray}} 來更改設置,或者用 {{core:cancel-edit-tray}} 來取消更改。",
"tip18": "您可以通過點擊 {{core:edit-selected-node}} 來顯示被選中節點的屬性設置畫面。"
}
}

View File

@@ -1,274 +0,0 @@
{
"$string": {
"args": "arg",
"desc": "通過以下的類型轉換規則將參數*arg*轉換成字串:\n\n - 字串不轉換。\n -函數轉換成空的字串。\n - JSON的值無法用數字表示所以用無限大或者NaN非數表示。\n - 用JSON.stringify函數將其他值轉換成JSON字串。"
},
"$length": {
"args": "str",
"desc": "輸出字串str的字數。如果str不是字串拋出錯誤。"
},
"$substring": {
"args": "str, start[, length]",
"desc": "輸出`start`位置後的的首次出現的包括`str`的子字串。 如果`length`被指定,那麼的字串中將只包括前`length`個文字。如果`start`是負數則輸出從`str`末尾開始的`length`個文字"
},
"$substringBefore": {
"args": "str, chars",
"desc": "輸出str中首次出現的chars之前的子字串如果str中不包括chars則輸出str。"
},
"$substringAfter": {
"args": "str, chars",
"desc": "輸出str中首次出現的chars之後的子字串如果str中不包括chars則輸出str。"
},
"$uppercase": {
"args": "str",
"desc": "`將str中的所有字母變為大寫後輸出。"
},
"$lowercase": {
"args": "str",
"desc": "將str中的所有字母變為小寫後輸出。"
},
"$trim": {
"args": "str",
"desc": "將以下步驟應用於`str`來去除所有空白文字並實現標準化。\n\n 將全部tab定位字元、Enter鍵、換行字元用空白代替。\n- 將連續的空白文字變成一個空白文字。\n- 消除開頭和末尾的空白文字。\n\n如果`str`沒有被指定(即在無輸入參數的情況下調用本函數),將上下文的值作為`str`來使用。 如果`str` 不是字串則拋出錯誤。"
},
"$contains": {
"args": "str, pattern",
"desc": "字串`str` 和 `pattern`匹配的話輸出`true`,不匹配的情況下輸出 `false`。 不指定`str`的情況下(比如用一個參數調用本函數時)、將上下文的值作為`str`來使用。參數 `pattern`可以為字串或正則表達。"
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "將參數`str`分解成由子字串組成的陣列。 如果`str`不是字串拋出錯誤。可以省略的參數 `separator`中指定字串`str`的分隔符號。分隔符號可以是文字或規則運算式。在不指定`separator`的情況下、將分隔符號看作空的字串並把`str`拆分成由單個字母組成的陣列。如果`separator`不是字串則拋出錯誤。在可省略的參數`limit`中指定分割後的子字串的最大個數。超出個數的子字串將被捨棄。如果`limit`沒有被指定,`str` 將不考慮子字串的個數而將字串完全分隔。如果`limit`是負數則拋出錯誤。"
},
"$join": {
"args": "array[, separator]",
"desc": "用可以省略的參數 `separator`來把多個字元串連接。如果`array`不是字串則拋出錯誤。 如果沒有指定`separator`,則用空字串來連接字元(即字串之間沒有`separator`)。 如果`separator`不是字元則拋出錯誤。"
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "對字串`str`使用規則運算式`pattern`並輸出與`str`相匹配的部分資訊。"
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "在字串`str`中搜索`pattern`並用`replacement`來替換。\n\n可選參數`limit`用來指定替換次數的上限。"
},
"$now": {
"args": "",
"desc": "生成ISO 8601互換格式的時刻並作為字串輸出。"
},
"$base64encode": {
"args": "string",
"desc": "將ASCII格式的字串轉換為Base 64格式。將字串中的文字視作二進位形式的資料處理。包含URI編碼在內的字串文字必須在0x00到0xFF的範圍內否則不會被支持。"
},
"$base64decode": {
"args": "string",
"desc": "用UTF-8內碼表將Base 64形式二進位值轉換為字串。"
},
"$number": {
"args": "arg",
"desc": "用下述的規則將參數 `arg`轉換為數值。:\n\n 數值不做轉換。\n 將字串中合法的JSON數値表示轉換成數値。\n 其他形式的值則拋出錯誤。"
},
"$abs": {
"args": "number",
"desc": "輸出參數`number`的絕對值。"
},
"$floor": {
"args": "number",
"desc": "輸出比`number`的值小的最大整數。"
},
"$ceil": {
"args": "number",
"desc": "輸出比`number`的值大的最小整數。"
},
"$round": {
"args": "number [, precision]",
"desc": "輸出四捨五入後的參數`number`。可省略的參數 `precision`指定四捨五入後小數點下的位數。"
},
"$power": {
"args": "base, exponent",
"desc": "輸出底數`base`的`exponent`次冪。"
},
"$sqrt": {
"args": "number",
"desc": "輸出參數 `number`的平方根。"
},
"$random": {
"args": "",
"desc": "輸出比0大比1小的偽亂數。"
},
"$millis": {
"args": "",
"desc": "返回從UNIX時間 (1970年1月1日 UTC/GMT的午夜開始到現在的毫秒數。在同一個運算式的測試中所有對`$millis()`的調用將會返回相同的值。"
},
"$sum": {
"args": "array",
"desc": "輸出陣列`array`的總和。如果`array`不是數值則拋出錯誤。"
},
"$max": {
"args": "array",
"desc": "輸出陣列`array`的最大值。如果`array`不是數值則拋出錯誤。"
},
"$min": {
"args": "array",
"desc": "輸出陣列`array`的最小值。如果`array`不是數值則拋出錯誤。。"
},
"$average": {
"args": "array",
"desc": "輸出陣列`array`的平均數。如果`array`不是數值則拋出錯誤。。"
},
"$boolean": {
"args": "arg",
"desc": "用下述規則將資料轉換成布林值。:\n\n - 不轉換布林值`Boolean`。\n 將空的字串`string`轉換為`false`\n 將不為空的字串`string`轉換為`true`\n 將為0的數位`number`轉換成`false`\n 將不為0的數位`number`轉換成`true`\n –將`null`轉換成`false`\n –將空的陣列`array`轉換成`false`\n –如果陣列`array`中含有可以轉換成`true`的要素則轉換成`true`\n –如果`array`中沒有可轉換成`true`的要素則轉換成`false`\n 空的物件`object`轉換成`false`\n 非空的物件`object`轉換成`true`\n –將函數`function`轉換成`false`"
},
"$not": {
"args": "arg",
"desc": "輸出做反轉運算後的布林值。首先將`arg`轉換為布林值。"
},
"$exists": {
"args": "arg",
"desc": "如果算式`arg`的值存在則輸出`true`。如果算式的值不存在(比如指向不存在區域的引用)則輸出`false`。"
},
"$count": {
"args": "array",
"desc": "輸出陣列中的元素數。"
},
"$append": {
"args": "array, array",
"desc": "將兩個陣列連接。"
},
"$sort": {
"args": "array [, function]",
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較left和right兩個值而被排序演算法調用的。如果使用者希望left的值被置於right的值之後那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
},
"$reverse": {
"args": "array",
"desc": "輸出倒序後的陣列`array`。"
},
"$shuffle": {
"args": "array",
"desc": "輸出隨機排序後的陣列 `array`。"
},
"$zip": {
"args": "array, ...",
"desc": "將陣列中的值按索引順序打包後輸出。"
},
"$keys": {
"args": "object",
"desc": "輸出由物件內的鍵組成的陣列。如果參數是物件的陣列則輸出由所有物件中的鍵去重後組成的佇列。"
},
"$lookup": {
"args": "object, key",
"desc": "輸出對象中與參數`key`對應的值。如果第一個參數`object`是陣列,那麼陣列中所有的物件都將被搜索並輸出這些物件中與參數`key`對應的值。"
},
"$spread": {
"args": "object",
"desc": "將物件中的鍵值對分隔成每個要素中只含有一個鍵值對的陣列。如果參數`object`是陣列,那麼返回值的陣列中包含所有物件中的鍵值對。"
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "將輸入陣列`objects`中所有的鍵值對合併到一個`object`中並返回。如果輸入陣列的要素中含有重複的鍵,則返回的`object`中將只包含陣列中最後出現要素的值。如果輸入陣列中包括物件以外的元素,則拋出錯誤。"
},
"$sift": {
"args": "object, function",
"desc": "輸出參數`object`中符合`function`的鍵值對。\n\n`function`必須含有下述參數。\n\n`function(value [, key [, object]])`"
},
"$each": {
"args": "object, function",
"desc": "將函數`function`應用於`object`中的所有鍵值對並輸出由所有返回值組成的陣列。"
},
"$map": {
"args": "array, function",
"desc": "將函數`function`應用於陣列`array`中所有的值並輸出由返回值組成的陣列。\n\n`function`中必須含有下述參數。\n\n`function(value [, index [, array]])`"
},
"$filter": {
"args": "array, function",
"desc": "輸出陣列`array`中符合函數`function`條件的值組成的陣列。\n\n`function`必須包括下述參數。\n\n`function(value [, index [, array]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "將`function`依次應用於陣列中的各要素值。 其中,前一個要素值的計算結果將參與到下一次的函數運算中。。\n\n函數`function`接受兩個參數並作為中綴標記法中的操作符。\n\n可省略的參數`init`將作為運算的初始值。"
},
"$flowContext": {
"args": "string",
"desc": "獲取流上下文(流等級的上下文,可以讓所有節點共用)的屬性。"
},
"$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的午夜開始到現在的毫秒數。如果該字串的格式不正確則拋出錯誤。"
},
"$env": {
"args": "arg",
"desc": "返回環境變量的值。\n\n這是Node-RED定義的函數。"
},
"$eval": {
"args": "expr [, context]",
"desc": "使用當前上下文來作為評估依據,分析並評估字符串`expr`其中包含文字JSON或JSONata表達式。"
},
"$formatInteger": {
"args": "number, picture",
"desc": "將“數字”轉換為字符串並將其格式化為“圖片”字符串指定的整數表示形式。圖片字符串參數定義了數字的格式並具有與XPath F&O 3.1 規範中的fnformat-integer相同的語法。"
},
"$parseInteger": {
"args": "string, picture",
"desc": "使用“圖片”字符串指定的格式將“字符串”參數的內容解析為整數作為JSON數字。圖片字符串參數與$formatInteger格式相同。."
},
"$error": {
"args": "[str]",
"desc": "引發錯誤並顯示一條消息。 可選的`str`將替代$error()函數評估的默認消息。"
},
"$assert": {
"args": "arg, str",
"desc": "如果`arg`為真,則該函數返回。 如果arg為假則拋出帶有str的異常作為異常消息。"
},
"$single": {
"args": "array, function",
"desc": "返回滿足參數function謂語的array參數中的唯一值 (比如傳遞值時函數返回布林值“true”)。如果匹配值的數量不唯一時,則拋出異常。\n\n應在以下簽名中提供函數`functionvalue [index [array []]]`其中value是數組的每個輸入index是該值的位置整個數組作為第三個參數傳遞。"
},
"$encodeUrl": {
"args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL組件進行編碼。\n\n示例`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
"desc": "通過用表示字符的UTF-8編碼的一個兩個三個或四個轉義序列替換某些字符的每個實例對統一資源定位符URL進行編碼。\n\n示例 `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`"
},
"$decodeUrl": {
"args": "str",
"desc": "解碼以前由encodeUrlComponent創建的統一資源定位器URL組件。 \n\n示例 `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`"
},
"$decodeUrlComponent": {
"args": "str",
"desc": "解碼先前由encodeUrl創建的統一資源定位符URL。 \n\n示例 `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`"
},
"$distinct": {
"args": "array",
"desc": "返回一個數組,其中重復的值已從`數組`中刪除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回`值`的類型。 如果該`值`未定義,則將返回`未定義`"
},
"$moment": {
"args": "[str]",
"desc": "使用Moment庫獲取日期對象。"
}
}

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,5 @@
; (function() {
ace.define("ace/snippets/nrjavascript",[],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="nrjavascript"});
(function() {
ace.require(["ace/snippets/nrjavascript"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;

File diff suppressed because one or more lines are too long

View File

@@ -76,12 +76,13 @@ oop.inherits(NRJavaScriptWorker, Mirror);
(function() {
this.setOptions = function(options) {
this.options = {
this.options = options || {
// undef: true,
// unused: true,
esversion: 9,
esnext: true,
moz: true,
devel: true,
browser: false,
browser: true,
node: true,
laxcomma: true,
laxbreak: true,
@@ -91,17 +92,8 @@ oop.inherits(NRJavaScriptWorker, Mirror);
maxerr: 100,
expr: true,
multistr: true,
strict: false,
sub: true,
asi: true
globalstrict: true
};
if (options) {
for (var opt in options) {
if (options.hasOwnProperty(opt)) {
this.options[opt] = options.opt;
}
}
}
this.doc.getValue() && this.deferredUpdate.schedule(100);
};
@@ -127,8 +119,6 @@ oop.inherits(NRJavaScriptWorker, Mirror);
if (!value)
return this.sender.emit("annotate", []);
var originalValue = value;
// [Node-RED] wrap the code in a function
value = "async function __nodered__(msg) {\n"+value+"\n}";
@@ -148,7 +138,6 @@ oop.inherits(NRJavaScriptWorker, Mirror);
continue;
var raw = error.raw;
var type = "warning";
var line = error.line - 2;
if (raw == "Missing semicolon.") {
var str = error.evidence.substr(error.character);
@@ -177,62 +166,9 @@ oop.inherits(NRJavaScriptWorker, Mirror);
type = "info";
}
if (raw === "Unmatched '{a}'." && line === -1) {
// This is an unmatched { error. It has incorrectly matched it
// against the { in the added line. Need to find the next valid {
// This code scans through the original code looking for the first '{'
// that is not in a comment or string.
// It will incorrectly find a '{' if it is inside a regex... but
// at least the error will be shown somwhere. There are only
// so many hours in the day to fix every tiny edge case of an
// edge case.
var inSingleComment = false;
var inMultiComment = false;
var inString = false;
var stringQ;
var lineNumber = 0;
for (var pos = 0;pos<originalValue.length;pos++) {
var c = originalValue[pos];
if (c === "\\") {
pos++;
} else if (inSingleComment) {
if (c === "\n") {
lineNumber++;
inSingleComment = false;
}
} else if (inMultiComment) {
if (c === "*" && originalValue[pos+1] === "/") {
pos++;
inMultiComment = false;
} else if (c === "\n") {
lineNumber++;
}
} else if (inString) {
if (c === stringQ) {
inString = false;
}
} else if (c === "'" || c === "\"") {
inString = true;
stringQ = c;
} else if (c === "/") {
if (originalValue[pos+1] === "/") {
inSingleComment = true;
} else if (originalValue[pos+1] === "*") {
inMultiComment = true;
}
} else if (c === "\n") {
lineNumber++;
} else if (c === "{") {
// found it!
break;
}
}
line = lineNumber;
}
errors.push({
// [Node-RED] offset the row for the added line
row: Math.max(0,line),
row: error.line-2,
column: error.character-1,
text: error.reason,
type: type,

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

View File

@@ -1 +0,0 @@
<svg width="27" height="18" xmlns="http://www.w3.org/2000/svg"><g color="#000"><path fill="#fff" d="M0 5.002h10v5H0zM17 .002h10v5H17z"/><path d="M17 13.002h10v5H17z"/></g><path d="M9.5 7.502h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg>

Before

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

View File

@@ -1 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path color="#000" fill="#8c101c" d="M0 .002h32v32H0z"/><g color="#000"><path fill="#fff" d="M2 13.002h10v5H2zM19 8.002h10v5H19z"/><path d="M19 21.002h10v5H19z"/></g><path d="M11.5 15.502h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg>

Before

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

View File

@@ -1 +0,0 @@
<svg width="27" height="18" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" color="#000"><path d="M0 5h10v5H0zM17 0h10v5H17zM17 13h10v5H17z"/></g><path d="M9.5 7.5h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg>

Before

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

View File

@@ -1 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path color="#000" fill="#8c101c" d="M0 0h32v32H0z"/><g fill="#fff" color="#000"><path d="M2 13h10v5H2zM19 8h10v5H19zM19 21h10v5H19z"/></g><path d="M11.5 15.5h2l4-5h2" fill="none" stroke="#fff" stroke-width="1.5"/></svg>

Before

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

View File

@@ -1 +0,0 @@
<svg width="27" height="18" xmlns="http://www.w3.org/2000/svg"><path color="#000" d="M0 5.002h10v5H0zM17 13.002h10v5H17z"/><path d="M9.5 7.502h2l4-5h2" fill="none" stroke="#000" stroke-width="1.5"/><path color="#000" fill="#fff" d="M17 .002h10v5H17z"/></svg>

Before

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

View File

@@ -1 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path color="#000" fill="#8c101c" d="M0 .002h32v32H0z"/><path color="#000" d="M2 13.002h10v5H2zM19 21.002h10v5H19z"/><path d="M11.5 15.502h2l4-5h2" fill="none" stroke="#000" stroke-width="1.5"/><path color="#000" fill="#fff" d="M19 8.002h10v5H19z"/></svg>

Before

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 B

View File

@@ -1 +0,0 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><g color="#000"><path fill="#8c101c" d="M0 .006h32v32H0z"/><path d="M11.81 25.429a10.02 10.02 0 0 0 4.19.914c5.562 0 10.107-4.545 10.107-10.106S21.562 6.131 16 6.131 5.895 10.676 5.895 16.237h3.368c0-3.74 2.997-6.737 6.738-6.737s6.737 2.996 6.737 6.737-2.996 6.738-6.737 6.738a6.775 6.775 0 0 1-2.533-.486l1.43-3.48-6.947 1.317 2.13 8.485z" fill="#fff" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/></g></svg>

Before

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

View File

@@ -1 +0,0 @@
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M18 5v12H7v26h11v12l14-25z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1019 B

View File

@@ -1 +0,0 @@
<svg width="46.994" height="18.006" xmlns="http://www.w3.org/2000/svg"><g stroke="#d6d6d6"><g fill="#9e3131" stroke-linejoin="round" stroke-width="3.847" transform="matrix(.25848 0 0 .2614 -63.87 -108.483)"><rect x="249.04" y="435.92" width="50.294" height="22.953" ry="6.608"/><rect x="345.63" y="416.93" width="50.294" height="22.953" ry="6.608"/><rect x="376.71" y="459.01" width="50.294" height="22.953" ry="6.608"/></g><path d="M301.04 447.43c24.406.184 7.107-18.84 42.708-19.03M374.82 470.48c-46.966.538-28.989-22.664-73.619-22.944" fill="none" stroke-width="5.771" transform="matrix(.25848 0 0 .2614 -63.87 -108.483)"/></g></svg>

Before

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

View File

@@ -1 +0,0 @@
<svg width="40" height="40" viewBox="0, 0, 40, 40" xmlns="http://www.w3.org/2000/svg"><path d="M25 16h7c.58 0 1-.42 1-1v-2c0-.58-.42-1-1-1h-7c-.58 0-1 .42-1 1v2c0 .58.42 1 1 1zM8 28h7c.58 0 1-.42 1-1v-2c0-.58-.42-1-1-1H8c-.58 0-1 .42-1 1v2c0 .58.42 1 1 1zm-.416 11C5.624 39 4 37.375 4 35.416V4.582C4 2.622 5.625 1 7.584 1h24.832C34.376 1 36 2.623 36 4.582v30.834C36 37.376 34.375 39 32.416 39zM32 27H19c0 2.19-1.81 4-4 4H7v4.416c0 .35.235.584.584.584h24.832c.35 0 .584-.235.584-.584v-8.417zm1-2v-6h-8c-2.19 0-4-1.81-4-4h-1c-4.333-.002-8.667.004-13 0v6h8c2.19 0 4 1.81 4 4h13zm0-16V4.582c0-.35-.235-.582-.584-.582H7.584C7.234 4 7 4.233 7 4.582v8.417c4.333.002 8.667.001 13 .001h1c0-2.19 1.81-4 4-4z" color="#000" fill="#333"/></svg>

Before

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M14.16 27.38l1.555-.144c.132.731.383 1.261.755 1.591.371.33.848.494 1.429.494.497 0 .931-.114 1.303-.341.377-.228.686-.53.926-.908.24-.383.44-.899.602-1.546a8.122 8.122 0 0 0 .233-2.3 3.732 3.732 0 0 1-1.33 1.258 3.605 3.605 0 0 1-1.815.476c-1.09 0-2.013-.395-2.768-1.186s-1.133-1.834-1.133-3.128c0-1.336.393-2.411 1.178-3.226.79-.815 1.78-1.223 2.966-1.223.856 0 1.638.231 2.345.692.713.462 1.253 1.12 1.618 1.978.372.85.557 2.085.557 3.702 0 1.684-.182 3.026-.548 4.027-.365.994-.91 1.752-1.636 2.274-.719.52-1.563.781-2.534.781-1.03 0-1.872-.284-2.525-.853-.654-.576-1.046-1.381-1.178-2.418zm6.624-5.815c0-.928-.249-1.666-.746-2.21-.492-.546-1.085-.819-1.78-.819-.719 0-1.345.294-1.878.881s-.8 1.348-.8 2.283c0 .839.252 1.522.755 2.05.51.52 1.135.781 1.878.781.75 0 1.363-.26 1.843-.782.485-.527.728-1.255.728-2.184zM4.858 10.466c0-1.558.158-2.81.476-3.757.324-.952.8-1.686 1.429-2.201.635-.516 1.432-.773 2.39-.773.708 0 1.328.143 1.861.431.533.282.974.692 1.321 1.231.348.534.62 1.187.818 1.96.198.767.297 1.803.297 3.11 0 1.545-.16 2.794-.477 3.747-.317.947-.794 1.68-1.429 2.202-.629.515-1.426.773-2.39.773-1.27 0-2.268-.456-2.993-1.366-.869-1.097-1.303-2.882-1.303-5.357zm1.662 0c0 2.163.252 3.604.755 4.323.51.713 1.136 1.07 1.879 1.07.743 0 1.366-.36 1.87-1.079.508-.719.763-2.157.763-4.314 0-2.169-.255-3.61-.764-4.323-.503-.713-1.132-1.07-1.887-1.07-.743 0-1.336.315-1.78.944-.557.803-.836 2.286-.836 4.45z" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M13.27 29.15l6.733-8.143h-6.235V19.3h8.8v1.559l-6.69 8.09h6.892v1.707h-9.5zm4.909-10.125zM6.577 12.58q0 .827.604 1.304.605.478 1.432.478 1.007 0 1.95-.467 1.59-.774 1.59-2.534V9.824q-.349.222-.9.37-.552.15-1.082.213l-1.155.148q-1.04.138-1.56.435-.88.498-.88 1.59zM11.2 8.721q.657-.085.88-.551.127-.255.127-.732 0-.975-.7-1.41-.689-.445-1.983-.445-1.495 0-2.12.805-.35.446-.456 1.326H5.167q.053-2.1 1.357-2.916 1.315-.827 3.043-.827 2.004 0 3.255.763 1.24.764 1.24 2.375v6.542q0 .297.117.477.127.18.52.18.127 0 .286-.01.159-.021.34-.053v1.41q-.446.127-.68.16-.233.031-.636.031-.986 0-1.43-.7-.234-.37-.33-1.05-.583.764-1.675 1.326t-2.407.562q-1.58 0-2.587-.954-.996-.965-.996-2.407 0-1.58.986-2.45.986-.869 2.587-1.07zm-1.58-4.75z" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M18.8 33.9c3.328 0 4.776-2.603 4.776-7.066s-1.448-7.066-4.776-7.066-4.776 2.603-4.776 7.066S15.473 33.9 18.8 33.9zm0-1.429c-2.192 0-3.073-1.781-3.073-4.522v-2.23c0-2.741.88-4.523 3.073-4.523s3.073 1.782 3.073 4.522v2.231c0 2.74-.88 4.522-3.073 4.522zm-6.306 1.194v-1.429H8.892V20.002H6.328l-3.621 3.386.959 1.038 3.445-3.21h.137v11.02H3.333v1.429zm11.2-17.7v-1.429h-3.602V2.302h-2.564l-3.621 3.386.959 1.038 3.445-3.21h.137v11.02h-3.915v1.429zM7.5 16.2c3.327 0 4.776-2.603 4.776-7.066S10.828 2.068 7.5 2.068 2.725 4.67 2.725 9.134 4.173 16.2 7.5 16.2zm0-1.429c-2.193 0-3.074-1.781-3.074-4.522V8.02c0-2.741.881-4.523 3.074-4.523s3.073 1.782 3.073 4.522v2.231c0 2.74-.881 4.522-3.073 4.522z" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M9.96 21.98a5 5 0 1 1 6.11-7.917zm3.035-13.973c-5.512 0-10 4.488-10 10s4.488 9.998 10 9.998 10-4.486 10-9.998-4.488-10-10-10zm0 1.816c4.53 0 8.182 3.655 8.182 8.184s-3.652 8.182-8.182 8.182-8.181-3.653-8.181-8.182 3.652-8.184 8.181-8.184z" color="#000" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M14.33 27.19q2.916-.136 4.024-2.131.58-1.024.58-2.37 0-2.132-1.569-3.24-.904-.648-3.035-1.228zM8.55 10.736q0 1.688 1.108 2.643 1.125.955 3.018 1.33V6.695q-2.234.085-3.189 1.364-.937 1.279-.937 2.677zm-3.07.205q0-2.592 1.893-4.672 1.91-2.08 5.337-2.115V1.887h1.62V4.12q3.393.239 5.2 2.012 1.825 1.757 1.91 4.655h-2.984q-.119-1.296-.699-2.233-1.074-1.723-3.427-1.808v8.287q3.956 1.108 5.371 2.08 2.302 1.603 2.302 4.74 0 4.536-2.95 6.446-1.637 1.057-4.723 1.398v3.308h-1.62v-3.308q-4.962-.324-6.735-3.513-.972-1.722-.972-4.655h3.018q.136 2.336.733 3.41 1.057 1.927 3.922 2.166v-9.293q-3.683-.699-5.44-2.336Q5.48 13.84 5.48 10.941z" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 745 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-337.103 -913.25) scale(1.2585)" fill="#444" stroke-width=".795"><circle cx="284.36" cy="733.68" r="1.5" color="#000" style="isolation:auto;mix-blend-mode:normal"/><circle cx="284.33" cy="740.74" r="1.5" color="#000" style="isolation:auto;mix-blend-mode:normal"/><path d="M276.18 727.78l4.396-1.565v18.515c-.711 2.606-2.922 4.394-5.812 5.812l-4.135 1.974-.559-1.192 3.353-1.639c1.459-.724 2.689-1.87 2.869-4.955z" fill-rule="evenodd"/></g></svg>

Before

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M15 5.225v-1.92h2.24q.608 0 1.216.288.608.256 1.12.8.48.512.8 1.312.32.768.32 1.792v5.824q0 .832.224 1.536t.608 1.216q.352.48.832.768.48.256.992.256v2.176q-.512 0-.992.256t-.832.736q-.384.48-.608 1.184t-.224 1.568v5.792q0 1.024-.32 1.792-.32.8-.8 1.312-.512.544-1.12.8-.608.288-1.216.288H15v-1.92h1.6q.48 0 .768-.256.288-.224.48-.64.16-.384.224-.896.064-.48.064-.96v-5.824q0-1.216.352-2.016.32-.8.768-1.28.448-.512.928-.736.448-.224.736-.256v-.096q-.288-.064-.736-.32-.48-.256-.928-.768t-.768-1.28q-.352-.8-.352-1.92V7.977q0-.512-.064-.992-.064-.512-.224-.896-.192-.384-.48-.608-.288-.256-.768-.256zm-3.648 0v-1.92h-2.24q-.608 0-1.216.288-.608.256-1.12.8-.48.512-.8 1.312-.32.768-.32 1.792v5.824q0 .832-.224 1.536t-.608 1.216q-.352.48-.832.768-.48.256-.992.256v2.176q.512 0 .992.256t.832.736q.384.48.608 1.184t.224 1.568v5.792q0 1.024.32 1.792.32.8.8 1.312.512.544 1.12.8.608.288 1.216.288h2.24v-1.92h-1.6q-.48 0-.768-.256-.288-.224-.48-.64-.16-.384-.224-.896-.064-.48-.064-.96v-5.824q0-1.216-.352-2.016-.32-.8-.768-1.28-.448-.512-.928-.736-.448-.224-.736-.256v-.096q.288-.064.736-.32.48-.256.928-.768t.768-1.28q.352-.8.352-1.92V7.977q0-.512.064-.992.064-.512.224-.896.192-.384.48-.608.288-.256.768-.256z" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M2 19h5v5H2zm16.099-3.304v-5.659h-2.654v5.66l-5.309-2.004-.901 2.404L14.543 18l-3.255 4.557 2.254 1.553 3.255-4.808 3.455 4.808 2.054-1.553L19 18l5.46-1.903-1.002-2.404z" color="#000" fill="#444444"/></svg>

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

View File

@@ -1 +0,0 @@
<svg width="26" height="36" viewBox="0, 0, 26, 36" xmlns="http://www.w3.org/2000/svg"><path d="M11 5v5.77a7.542 7.542 0 0 0-5.234 5.25L1 16c-1.432 1.397-1.232 2.722 0 4l4.75-.078a7.542 7.542 0 0 0 5.22 5.297L11 31c1.316 1.303 2.649 1.363 4 0l.009-5.775A7.542 7.542 0 0 0 20.228 20H25c1.261-1.294 1.404-2.623 0-4l-4.774-.01a7.542 7.542 0 0 0-5.23-5.22L15 5c-1.3-1.273-2.63-1.393-4 0zm2 7.499c3.05 0 5.5 2.45 5.5 5.5s-2.45 5.5-5.5 5.5-5.5-2.45-5.5-5.5 2.45-5.5 5.5-5.5z" color="#000" fill="#444"/></svg>

Before

Width:  |  Height:  |  Size: 502 B

View File

@@ -32,19 +32,14 @@
}
}
}
function emit() {
var evt = arguments[0]
var args = Array.prototype.slice.call(arguments,1);
if (RED.events.DEBUG) {
console.warn(evt,args);
}
function emit(evt,arg) {
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
try {
handlers[evt][i].apply(null, args);
handlers[evt][i](arg);
} catch(err) {
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.warn(err);
console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err);
}
}

View File

@@ -808,7 +808,17 @@ RED.nodes.fontAwesome = (function() {
"fa-youtube": "\uf167",
};
var iconList = Object.keys(iconMap);
var iconList = [];
var isUsed = {};
Object.keys(iconMap).forEach(function(icon) {
var unicode = iconMap[icon];
// skip icons with a same unicode
if (isUsed[unicode] !== true) {
iconList.push(icon);
isUsed[unicode] = true;
}
});
isUsed = undefined;
return {
getIconUnicode: function(name) {

View File

@@ -14,126 +14,60 @@
* limitations under the License.
**/
RED.history = (function() {
var undoHistory = [];
var redoHistory = [];
var undo_history = [];
function undoEvent(ev) {
var i;
var len;
var node;
var group;
var subflow;
var modifiedTabs = {};
var inverseEv;
if (ev) {
if (ev.t == 'multi') {
inverseEv = {
t: 'multi',
events: []
};
len = ev.events.length;
for (i=len-1;i>=0;i--) {
var r = undoEvent(ev.events[i]);
inverseEv.events.push(r);
undoEvent(ev.events[i]);
}
} else if (ev.t == 'replace') {
if (ev.complete) {
// This is a replace of everything. We can short-cut
// the logic by clearing everyting first, then importing
// the ev.config.
// Used by RED.diff.mergeDiff
inverseEv = {
t: 'replace',
config: RED.nodes.createCompleteNodeSet(),
changed: {},
rev: RED.nodes.version()
};
RED.nodes.clear();
var imported = RED.nodes.import(ev.config);
imported.nodes.forEach(function(n) {
if (ev.changed[n.id]) {
n.changed = true;
inverseEv.changed[n.id] = true;
}
})
RED.nodes.version(ev.rev);
} else {
var importMap = {};
ev.config.forEach(function(n) {
importMap[n.id] = "replace";
})
var importedResult = RED.nodes.import(ev.config,{importMap: importMap})
inverseEv = {
t: 'replace',
config: importedResult.removedNodes
RED.nodes.clear();
var imported = RED.nodes.import(ev.config);
imported[0].forEach(function(n) {
if (ev.changed[n.id]) {
n.changed = true;
}
}
})
RED.nodes.version(ev.rev);
} else if (ev.t == 'add') {
inverseEv = {
t: "delete",
};
if (ev.nodes) {
inverseEv.nodes = [];
for (i=0;i<ev.nodes.length;i++) {
node = RED.nodes.node(ev.nodes[i]);
if (node.z) {
modifiedTabs[node.z] = true;
}
inverseEv.nodes.push(node);
RED.nodes.remove(ev.nodes[i]);
if (node.g) {
var group = RED.nodes.group(node.g);
var index = group.nodes.indexOf(node);
if (index !== -1) {
group.nodes.splice(index,1);
RED.group.markDirty(group);
}
}
}
}
if (ev.links) {
inverseEv.links = [];
for (i=0;i<ev.links.length;i++) {
inverseEv.links.push(ev.links[i]);
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.groups) {
inverseEv.groups = [];
for (i = ev.groups.length - 1;i>=0;i--) {
group = ev.groups[i];
modifiedTabs[group.z] = true;
// The order of groups is important
// - to invert the action, the order is reversed
inverseEv.groups.unshift(group);
RED.nodes.removeGroup(group);
}
}
if (ev.workspaces) {
inverseEv.workspaces = [];
for (i=0;i<ev.workspaces.length;i++) {
var workspaceOrder = RED.nodes.getWorkspaceOrder();
ev.workspaces[i]._index = workspaceOrder.indexOf(ev.workspaces[i].id);
inverseEv.workspaces.push(ev.workspaces[i]);
RED.nodes.removeWorkspace(ev.workspaces[i].id);
RED.workspaces.remove(ev.workspaces[i]);
}
}
if (ev.subflows) {
inverseEv.subflows = [];
for (i=0;i<ev.subflows.length;i++) {
inverseEv.subflows.push(ev.subflows[i]);
RED.nodes.removeSubflow(ev.subflows[i]);
RED.workspaces.remove(ev.subflows[i]);
}
}
if (ev.subflow) {
inverseEv.subflow = {};
if (ev.subflow.instances) {
inverseEv.subflow.instances = [];
ev.subflow.instances.forEach(function(n) {
inverseEv.subflow.instances.push(n);
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
@@ -149,30 +83,21 @@ RED.history = (function() {
}
}
if (ev.removedLinks) {
inverseEv.createdLinks = [];
for (i=0;i<ev.removedLinks.length;i++) {
inverseEv.createdLinks.push(ev.removedLinks[i]);
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "delete") {
inverseEv = {
t: "add"
};
if (ev.workspaces) {
inverseEv.workspaces = [];
for (i=0;i<ev.workspaces.length;i++) {
inverseEv.workspaces.push(ev.workspaces[i]);
RED.nodes.addWorkspace(ev.workspaces[i],ev.workspaces[i]._index);
RED.workspaces.add(ev.workspaces[i],undefined,ev.workspaces[i]._index);
delete ev.workspaces[i]._index;
}
}
if (ev.subflows) {
inverseEv.subflows = [];
for (i=0;i<ev.subflows.length;i++) {
inverseEv.subflows.push(ev.subflows[i]);
RED.nodes.addSubflow(ev.subflows[i]);
}
}
@@ -201,11 +126,8 @@ RED.history = (function() {
}
}
if (ev.subflow) {
inverseEv.subflow = {};
if (ev.subflow.hasOwnProperty('instances')) {
inverseEv.subflow.instances = [];
ev.subflow.instances.forEach(function(n) {
inverseEv.subflow.instances.push(n);
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
@@ -222,60 +144,22 @@ RED.history = (function() {
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
n.inputs = subflow.in.length;
n.outputs = subflow.out.length;
while (n.outputs > n.ports.length) {
n.ports.push(n.ports.length);
}
n.resize = true;
n.dirty = true;
});
}
if (ev.groups) {
inverseEv.groups = [];
var groupsToAdd = {};
ev.groups.forEach(function(g) { groupsToAdd[g.id] = g; });
for (i = ev.groups.length - 1;i>=0;i--) {
RED.nodes.addGroup(ev.groups[i])
modifiedTabs[ev.groups[i].z] = true;
// The order of groups is important
// - to invert the action, the order is reversed
inverseEv.groups.unshift(ev.groups[i]);
if (ev.groups[i].g) {
if (!groupsToAdd[ev.groups[i].g]) {
group = RED.nodes.group(ev.groups[i].g);
} else {
group = groupsToAdd[ev.groups[i].g];
}
if (group.nodes.indexOf(ev.groups[i]) === -1) {
group.nodes.push(ev.groups[i]);
}
RED.group.markDirty(ev.groups[i])
}
}
}
if (ev.nodes) {
inverseEv.nodes = [];
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.add(ev.nodes[i]);
modifiedTabs[ev.nodes[i].z] = true;
inverseEv.nodes.push(ev.nodes[i].id);
if (ev.nodes[i].g) {
group = RED.nodes.group(ev.nodes[i].g);
if (group.nodes.indexOf(ev.nodes[i]) === -1) {
group.nodes.push(ev.nodes[i]);
}
RED.group.markDirty(group)
}
}
}
if (ev.links) {
inverseEv.links = [];
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
inverseEv.links.push(ev.links[i]);
}
}
if (ev.createdLinks) {
inverseEv.removedLinks = [];
for (i=0;i<ev.createdLinks.length;i++) {
inverseEv.removedLinks.push(ev.createdLinks[i]);
RED.nodes.removeLink(ev.createdLinks[i]);
}
}
if (ev.changes) {
@@ -290,22 +174,13 @@ RED.history = (function() {
}
node.dirty = true;
}
RED.events.emit("nodes:change",node);
}
}
}
if (subflow) {
RED.events.emit("subflows:change", subflow);
}
} else if (ev.t == "move") {
inverseEv = {
t: 'move',
nodes: []
};
for (i=0;i<ev.nodes.length;i++) {
var n = ev.nodes[i];
var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.moved};
inverseEv.nodes.push(rn);
n.n.x = n.ox;
n.n.y = n.oy;
n.n.dirty = true;
@@ -313,90 +188,53 @@ RED.history = (function() {
}
// A move could have caused a link splice
if (ev.links) {
inverseEv.removedLinks = [];
for (i=0;i<ev.links.length;i++) {
inverseEv.removedLinks.push(ev.links[i]);
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.removedLinks) {
inverseEv.links = [];
for (i=0;i<ev.removedLinks.length;i++) {
inverseEv.links.push(ev.removedLinks[i]);
RED.nodes.addLink(ev.removedLinks[i]);
}
}
if (ev.addToGroup) {
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
inverseEv.removeFromGroup = ev.addToGroup;
} else if (ev.removeFromGroup) {
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
inverseEv.addToGroup = ev.removeFromGroup;
}
} else if (ev.t == "edit") {
inverseEv = {
t: "edit",
changes: {}
};
inverseEv.node = ev.node;
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
inverseEv.changes[i] = ev.node[i];
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) {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
RED.events.emit("nodes:change",currentConfigNode);
}
var newConfigNode = RED.nodes.node(ev.changes[i]);
if (newConfigNode) {
newConfigNode.users.push(ev.node);
RED.events.emit("nodes:change",newConfigNode);
}
}
ev.node[i] = ev.changes[i];
}
}
var eventType;
switch(ev.node.type) {
case 'tab': eventType = "flows"; break;
case 'group': eventType = "groups"; break;
case 'subflow': eventType = "subflows"; break;
default: eventType = "nodes"; break;
}
eventType += ":change";
RED.events.emit(eventType,ev.node);
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
}
if (ev.subflow) {
inverseEv.subflow = {};
if (ev.subflow.hasOwnProperty('inputCount')) {
inverseEv.subflow.inputCount = ev.node.in.length;
if (ev.node.in.length > ev.subflow.inputCount) {
inverseEv.subflow.inputs = ev.node.in.slice(ev.subflow.inputCount);
ev.node.in.splice(ev.subflow.inputCount);
} else if (ev.subflow.inputs.length > 0) {
ev.node.in = ev.node.in.concat(ev.subflow.inputs);
}
}
if (ev.subflow.hasOwnProperty('outputCount')) {
inverseEv.subflow.outputCount = ev.node.out.length;
if (ev.node.out.length > ev.subflow.outputCount) {
inverseEv.subflow.outputs = ev.node.out.slice(ev.subflow.outputCount);
ev.node.out.splice(ev.subflow.outputCount);
} else if (ev.subflow.outputs.length > 0) {
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
}
}
if (ev.subflow.hasOwnProperty('instances')) {
inverseEv.subflow.instances = [];
ev.subflow.instances.forEach(function(n) {
inverseEv.subflow.instances.push(n);
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
@@ -420,185 +258,52 @@ RED.history = (function() {
var outputMap;
if (ev.outputMap) {
outputMap = {};
inverseEv.outputMap = {};
for (var port in ev.outputMap) {
if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") {
outputMap[ev.outputMap[port]] = port;
inverseEv.outputMap[ev.outputMap[port]] = port;
}
}
}
ev.node.__outputs = inverseEv.changes.outputs;
RED.editor.updateNodeProperties(ev.node,outputMap);
RED.editor.validateNode(ev.node);
}
if (ev.links) {
inverseEv.createdLinks = [];
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
inverseEv.createdLinks.push(ev.links[i]);
}
}
if (ev.createdLinks) {
inverseEv.links = [];
for (i=0;i<ev.createdLinks.length;i++) {
RED.nodes.removeLink(ev.createdLinks[i]);
inverseEv.links.push(ev.createdLinks[i]);
}
}
ev.node.dirty = true;
ev.node.changed = ev.changed;
} else if (ev.t == "createSubflow") {
inverseEv = {
t: "deleteSubflow",
activeWorkspace: ev.activeWorkspace,
dirty: RED.nodes.dirty()
};
if (ev.nodes) {
inverseEv.movedNodes = [];
var z = ev.activeWorkspace;
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
fullNodeList.forEach(function(n) {
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
n.x += ev.subflow.offsetX;
n.y += ev.subflow.offsetY;
n.z = ev.activeWorkspace;
n.dirty = true;
inverseEv.movedNodes.push(n.id);
RED.nodes.moveNodeToTab(n, z);
});
inverseEv.subflows = [];
for (i=0;i<ev.nodes.length;i++) {
inverseEv.subflows.push(RED.nodes.node(ev.nodes[i]));
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
inverseEv.links = [];
for (i=0;i<ev.links.length;i++) {
inverseEv.links.push(ev.links[i]);
RED.nodes.removeLink(ev.links[i]);
}
}
inverseEv.subflow = ev.subflow;
RED.nodes.removeSubflow(ev.subflow.subflow);
RED.workspaces.remove(ev.subflow.subflow);
if (ev.removedLinks) {
inverseEv.createdLinks = [];
for (i=0;i<ev.removedLinks.length;i++) {
inverseEv.createdLinks.push(ev.removedLinks[i]);
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "deleteSubflow") {
inverseEv = {
t: "createSubflow",
activeWorkspace: ev.activeWorkspace,
dirty: RED.nodes.dirty(),
};
if (ev.subflow) {
RED.nodes.addSubflow(ev.subflow.subflow);
inverseEv.subflow = ev.subflow;
if (ev.subflow.subflow.g) {
RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.subflow);
}
}
if (ev.subflows) {
inverseEv.nodes = [];
for (i=0;i<ev.subflows.length;i++) {
RED.nodes.add(ev.subflows[i]);
inverseEv.nodes.push(ev.subflows[i].id);
}
}
if (ev.movedNodes) {
ev.movedNodes.forEach(function(nid) {
nn = RED.nodes.node(nid);
if (!nn) {
nn = RED.nodes.group(nid);
}
nn.x -= ev.subflow.offsetX;
nn.y -= ev.subflow.offsetY;
nn.dirty = true;
RED.nodes.moveNodeToTab(nn, ev.subflow.subflow.id);
});
}
if (ev.links) {
inverseEv.links = [];
for (i=0;i<ev.links.length;i++) {
inverseEv.links.push(ev.links[i]);
RED.nodes.addLink(ev.links[i]);
}
}
if (ev.createdLinks) {
inverseEv.removedLinks = [];
for (i=0;i<ev.createdLinks.length;i++) {
inverseEv.removedLinks.push(ev.createdLinks[i]);
RED.nodes.removeLink(ev.createdLinks[i]);
}
}
} else if (ev.t == "reorder") {
inverseEv = {
t: 'reorder',
order: RED.nodes.getWorkspaceOrder()
};
if (ev.order) {
RED.workspaces.order(ev.order);
}
} else if (ev.t == "createGroup") {
inverseEv = {
t: "ungroup",
dirty: RED.nodes.dirty(),
groups: []
}
if (ev.groups) {
for (i=0;i<ev.groups.length;i++) {
inverseEv.groups.push(ev.groups[i]);
RED.group.ungroup(ev.groups[i]);
}
}
} else if (ev.t == "ungroup") {
inverseEv = {
t: "createGroup",
dirty: RED.nodes.dirty(),
groups: []
}
if (ev.groups) {
for (i=0;i<ev.groups.length;i++) {
inverseEv.groups.push(ev.groups[i]);
var nodes = ev.groups[i].nodes.slice();
ev.groups[i].nodes = [];
RED.nodes.addGroup(ev.groups[i]);
RED.group.addToGroup(ev.groups[i],nodes);
}
}
} else if (ev.t == "addToGroup") {
inverseEv = {
t: "removeFromGroup",
dirty: RED.nodes.dirty(),
group: ev.group,
nodes: ev.nodes,
reparent: ev.reparent
}
if (ev.nodes) {
RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true);
}
} else if (ev.t == "removeFromGroup") {
inverseEv = {
t: "addToGroup",
dirty: RED.nodes.dirty(),
group: ev.group,
nodes: ev.nodes,
reparent: ev.reparent
}
if (ev.nodes) {
RED.group.addToGroup(ev.group,ev.nodes);
}
}
if(ev.callback && typeof ev.callback === 'function') {
inverseEv.callback = ev.callback;
ev.callback(ev);
}
Object.keys(modifiedTabs).forEach(function(id) {
@@ -609,13 +314,12 @@ RED.history = (function() {
});
RED.nodes.dirty(ev.dirty);
RED.view.updateActive();
RED.view.select(null);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
RED.subflow.refresh();
return inverseEv;
}
}
@@ -623,45 +327,28 @@ RED.history = (function() {
return {
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
markAllDirty: function() {
for (var i=0;i<undoHistory.length;i++) {
undoHistory[i].dirty = true;
for (var i=0;i<undo_history.length;i++) {
undo_history[i].dirty = true;
}
},
list: function() {
return undoHistory;
},
listRedo: function() {
return redoHistory;
return undo_history
},
depth: function() {
return undoHistory.length;
return undo_history.length;
},
push: function(ev) {
undoHistory.push(ev);
redoHistory = [];
undo_history.push(ev);
},
pop: function() {
var ev = undoHistory.pop();
var rev = undoEvent(ev);
if (rev) {
redoHistory.push(rev);
}
var ev = undo_history.pop();
undoEvent(ev);
},
peek: function() {
return undoHistory[undoHistory.length-1];
return undo_history[undo_history.length-1];
},
clear: function() {
undoHistory = [];
redoHistory = [];
},
redo: function() {
var ev = redoHistory.pop();
if (ev) {
var uev = undoEvent(ev);
if (uev) {
undoHistory.push(uev);
}
}
undo_history = [];
}
}

View File

@@ -50,19 +50,6 @@ RED.i18n = (function() {
}
},
lang: function() {
// Gets the active message catalog language. This is based on what
// locale the editor is using and what languages are available.
//
var preferredLangs = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var knownLangs = RED.settings.theme("languages")||["en-US"];
for (var i=0;i<preferredLangs.length;i++) {
if (knownLangs.indexOf(preferredLangs[i]) > -1) {
return preferredLangs[i]
}
}
return 'end-US'
},
loadNodeCatalog: function(namespace,done) {
var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var toLoad = languageList.length;

View File

@@ -8,9 +8,7 @@
"ctrl-0": "core:zoom-reset",
"ctrl-enter": "core:confirm-edit-tray",
"ctrl-escape": "core:cancel-edit-tray",
"ctrl-d": "core:deploy-flows",
"ctrl-g i": "core:show-info-tab",
"ctrl-g h": "core:show-help-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g c": "core:show-config-tab",
"ctrl-g x": "core:show-context-tab",
@@ -31,8 +29,7 @@
"backspace": "core:delete-config-selection",
"delete": "core:delete-config-selection",
"ctrl-a": "core:select-all-config-nodes",
"ctrl-z": "core:undo",
"ctrl-y": "core:redo"
"ctrl-z": "core:undo"
},
"red-ui-workspace": {
"backspace": "core:delete-selection",
@@ -42,17 +39,8 @@
"ctrl-x": "core:cut-selection-to-internal-clipboard",
"ctrl-v": "core:paste-from-internal-clipboard",
"ctrl-z": "core:undo",
"ctrl-y": "core:redo",
"ctrl-a": "core:select-all-nodes",
"shift-?": "core:show-help",
"w": "core:scroll-view-up",
"d": "core:scroll-view-right",
"s": "core:scroll-view-down",
"a": "core:scroll-view-left",
"shift-w": "core:step-view-up",
"shift-d": "core:step-view-right",
"shift-s": "core:step-view-down",
"shift-a": "core:step-view-left",
"up": "core:move-selection-up",
"right": "core:move-selection-right",
"down": "core:move-selection-down",
@@ -62,10 +50,6 @@
"shift-down": "core:step-selection-down",
"shift-left": "core:step-selection-left",
"ctrl-shift-j": "core:show-previous-tab",
"ctrl-shift-k": "core:show-next-tab",
"ctrl-shift-g": "core:group-selection",
"ctrl-shift-u": "core:ungroup-selection",
"ctrl-shift-c": "core:copy-group-style",
"ctrl-shift-v": "core:paste-group-style"
"ctrl-shift-k": "core:show-next-tab"
}
}

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