Compare commits
No commits in common. "master" and "0.19.6" have entirely different histories.
1
.gitattributes
vendored
@ -1 +0,0 @@
|
|||||||
/packages/node_modules/** linguist-generated=false
|
|
34
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<!--
|
||||||
|
## Before you hit that Submit button....
|
||||||
|
|
||||||
|
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
|
||||||
|
|
||||||
|
If your issue is:
|
||||||
|
- a general 'how-to' type question,
|
||||||
|
- a feature request or suggestion for a change,
|
||||||
|
- or problems with 3rd party (`node-red-contrib-`) nodes
|
||||||
|
|
||||||
|
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||||
|
|
||||||
|
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||||
|
|
||||||
|
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
||||||
|
|
||||||
|
## So you have a real issue to raise...
|
||||||
|
|
||||||
|
To help us understand the issue, please fill-in as much of the following information as you can:
|
||||||
|
-->
|
||||||
|
|
||||||
|
### What are the steps to reproduce?
|
||||||
|
|
||||||
|
### What happens?
|
||||||
|
|
||||||
|
### What do you expect to happen?
|
||||||
|
|
||||||
|
### Please tell us about your environment:
|
||||||
|
|
||||||
|
- [ ] Node-RED version:
|
||||||
|
- [ ] node.js version:
|
||||||
|
- [ ] npm version:
|
||||||
|
- [ ] Platform/OS:
|
||||||
|
- [ ] Browser:
|
61
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,61 +0,0 @@
|
|||||||
name: 🐞 Report a bug
|
|
||||||
description: File a bug/issue on the core of Node-RED
|
|
||||||
labels: [needs-triage]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
|
|
||||||
|
|
||||||
If your issue is:
|
|
||||||
- a general 'how-to' type question,
|
|
||||||
- a feature request or suggestion for a change,
|
|
||||||
- or problems with 3rd party (`node-red-contrib-`) nodes
|
|
||||||
|
|
||||||
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
|
||||||
|
|
||||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
|
||||||
|
|
||||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
|
||||||
|
|
||||||
To help us understand the issue, please fill-in as much of the following information as you can:
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Current Behavior
|
|
||||||
description: A clear & concise description of what you're experiencing.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Expected Behavior
|
|
||||||
description: A clear & concise description of what you expected to happen.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Steps To Reproduce
|
|
||||||
description: Steps to reproduce the behavior.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Example flow
|
|
||||||
description: If you have a minimal example flow that demonstrates the issue, share it here.
|
|
||||||
value: |
|
|
||||||
```
|
|
||||||
paste your flow here
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Environment
|
|
||||||
description: Please tell us about your environment. Include any relevant information on how you are running Node-RED.
|
|
||||||
value: |
|
|
||||||
- Node-RED version:
|
|
||||||
- Node.js version:
|
|
||||||
- npm version:
|
|
||||||
- Platform/OS:
|
|
||||||
- Browser:
|
|
||||||
validations:
|
|
||||||
required: false
|
|
14
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,14 +0,0 @@
|
|||||||
blank_issues_enabled: true
|
|
||||||
contact_links:
|
|
||||||
- name: ❓ Questions
|
|
||||||
url: https://discourse.nodered.org
|
|
||||||
about: Ask your question on the Node-RED forum
|
|
||||||
- name: ⭐️ Feature Request
|
|
||||||
url: https://discourse.nodered.org/c/development/feature-requests
|
|
||||||
about: Discuss your request with the community
|
|
||||||
- name: 🗂 Documentation
|
|
||||||
url: https://nodered.org/docs
|
|
||||||
about: Go straight to the documentation
|
|
||||||
- name: 💬 Slack
|
|
||||||
url: https://nodered.org/slack
|
|
||||||
about: Chat about the project on our slack team
|
|
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -29,6 +29,6 @@ the [forum](https://discourse.nodered.org) or
|
|||||||
<!-- Put an `x` in the boxes that apply -->
|
<!-- Put an `x` in the boxes that apply -->
|
||||||
|
|
||||||
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
|
- [ ] 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 `npm run test` to verify the unit tests pass
|
- [ ] I have run `grunt` to verify the unit tests pass
|
||||||
- [ ] I have added suitable unit tests to cover the new/changed functionality
|
- [ ] I have added suitable unit tests to cover the new/changed functionality
|
||||||
|
15
.github/dependabot.yml
vendored
@ -1,15 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
|
||||||
directory: "/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
groups:
|
|
||||||
github-actions:
|
|
||||||
patterns:
|
|
||||||
- "*"
|
|
29
.github/scripts/update-node-red-docker.js
vendored
@ -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);
|
|
||||||
}
|
|
18
.github/scripts/update-node-red-website.js
vendored
@ -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);
|
|
62
.github/workflows/release.yml
vendored
@ -1,62 +0,0 @@
|
|||||||
name: Publish Release
|
|
||||||
env:
|
|
||||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
generate:
|
|
||||||
name: 'Update node-red-docker image'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Check out node-red repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: 'node-red'
|
|
||||||
- name: Check out node-red-docker repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: 'node-red/node-red-docker'
|
|
||||||
path: 'node-red-docker'
|
|
||||||
- name: Check out node-red.github.io repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: 'node-red/node-red.github.io'
|
|
||||||
path: 'node-red.github.io'
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '16'
|
|
||||||
- run: node ./node-red/.github/scripts/update-node-red-docker.js
|
|
||||||
- name: Create Docker Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@v6
|
|
||||||
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@v6
|
|
||||||
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
|
|
30
.github/workflows/tests.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
name: Run tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master, dev ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master, dev ]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
permissions:
|
|
||||||
contents: read # for actions/checkout to fetch code
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [18, 20, 22]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: Run tests
|
|
||||||
run: |
|
|
||||||
npm run test
|
|
12
.gitignore
vendored
@ -7,9 +7,7 @@
|
|||||||
.sessions.json
|
.sessions.json
|
||||||
.settings
|
.settings
|
||||||
.tern-project
|
.tern-project
|
||||||
.i18n-editor-metadata
|
|
||||||
*.backup
|
*.backup
|
||||||
*.bak
|
|
||||||
*_cred*
|
*_cred*
|
||||||
coverage
|
coverage
|
||||||
credentials.json
|
credentials.json
|
||||||
@ -19,13 +17,3 @@ node_modules
|
|||||||
public
|
public
|
||||||
locales/zz-ZZ
|
locales/zz-ZZ
|
||||||
nodes/core/locales/zz-ZZ
|
nodes/core/locales/zz-ZZ
|
||||||
!packages/node_modules
|
|
||||||
packages/node_modules/@node-red/editor-client/public
|
|
||||||
!test/**/node_modules
|
|
||||||
docs
|
|
||||||
!packages/node_modules/**/docs
|
|
||||||
.vscode
|
|
||||||
.nyc_output
|
|
||||||
sync.ffs_db
|
|
||||||
package-lock.json
|
|
||||||
.editorconfig
|
|
||||||
|
@ -15,5 +15,5 @@
|
|||||||
"shadow": true, // allow variable shadowing (re-use of names...)
|
"shadow": true, // allow variable shadowing (re-use of names...)
|
||||||
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
||||||
"proto": true, // allow setting of __proto__ in node < v0.12,
|
"proto": true, // allow setting of __proto__ in node < v0.12,
|
||||||
"esversion": 11 // allow es11(ES2020)
|
"esversion": 6 // allow es6
|
||||||
}
|
}
|
||||||
|
5
.nodemonignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/Gruntfile.js
|
||||||
|
/.git/*
|
||||||
|
/lib/*
|
||||||
|
*.backup
|
||||||
|
/public/*
|
7
.npmignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.settings
|
||||||
|
.jshintignore
|
||||||
|
.jshintrc
|
||||||
|
.project
|
||||||
|
.tern-project
|
||||||
|
.travis.yml
|
||||||
|
.git
|
12
.travis.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
sudo: false
|
||||||
|
language: node_js
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- node_js: "10"
|
||||||
|
script:
|
||||||
|
- ./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"
|
||||||
|
- node_js: "6"
|
||||||
|
- node_js: "4"
|
19
API.md
@ -1,19 +0,0 @@
|
|||||||
Node-RED consists of 6 node modules under the `@node-red` scope, which are pulled together
|
|
||||||
by the top-level `node-red` module. The typical scenario is where you are embedding Node-RED into your
|
|
||||||
own application, in which case you would use the `node-red` module rather than any of the
|
|
||||||
internal modules directly.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
let RED = require("node-red");
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Module | Description
|
|
||||||
-------|-------
|
|
||||||
[node-red](node-red.html) | the main module that pulls together all of the internal modules and provides the executable version of Node-RED
|
|
||||||
[@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API
|
|
||||||
[@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED
|
|
||||||
[@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules
|
|
||||||
[@node-red/registry](@node-red_registry.html) | the internal node registry
|
|
||||||
@node-red/nodes | the default set of core nodes. This module only contains the Node-RED nodes - it does not expose any APIs.
|
|
||||||
@node-red/editor-client | the client-side resources of the Node-RED editor application
|
|
1553
CHANGELOG.md
@ -1,7 +0,0 @@
|
|||||||
cff-version: 1.2.0
|
|
||||||
message: "If you use this software, please cite it as below."
|
|
||||||
title: "Node-RED"
|
|
||||||
authors:
|
|
||||||
- family-names: "OpenJS Foundation"
|
|
||||||
- family-names: "Contributors"
|
|
||||||
url: "https://nodered.org"
|
|
@ -16,9 +16,6 @@ behavior to the project's core team at team@nodered.org.
|
|||||||
Please raise any bug reports on the relevant project's issue tracker. Be sure to
|
Please raise any bug reports on the relevant project's issue tracker. Be sure to
|
||||||
search the list to see if your issue has already been raised.
|
search the list to see if your issue has already been raised.
|
||||||
|
|
||||||
If your issue is more of a question on how to do something with Node-RED, please
|
|
||||||
consider using the [community forum](https://discourse.nodered.org/).
|
|
||||||
|
|
||||||
A good bug report is one that make it easy for us to understand what you were
|
A good bug report is one that make it easy for us to understand what you were
|
||||||
trying to do and what went wrong.
|
trying to do and what went wrong.
|
||||||
|
|
||||||
@ -29,7 +26,7 @@ relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
|
|||||||
At a minimum, please include:
|
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-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
|
## Feature requests
|
||||||
|
|
||||||
@ -38,25 +35,16 @@ For feature requests, please raise them on the [forum](https://discourse.nodered
|
|||||||
## Pull-Requests
|
## Pull-Requests
|
||||||
|
|
||||||
If you want to raise a pull-request with a new feature, or a refactoring
|
If you want to raise a pull-request with a new feature, or a refactoring
|
||||||
of existing code, please come and discuss it with us first. We prefer to
|
of existing code, it may well get rejected if you haven't discussed it on
|
||||||
do it that way to make sure your time and effort is well spent on something
|
the [forum](https://discourse.nodered.org) first.
|
||||||
that fits with our goals.
|
|
||||||
|
|
||||||
If you've got a bug-fix or similar for us, then you are most welcome to
|
All contributors need to sign the JS Foundation's Contributor License Agreement.
|
||||||
get it raised - just make sure you link back to the issue it's fixing and
|
It is an online process and quick to do. You can read the details of the agreement
|
||||||
try to include some tests!
|
here: https://cla.js.foundation/node-red/node-red.
|
||||||
|
|
||||||
All contributors need to sign the OpenJS Foundation's Contributor License Agreement.
|
If you raise a pull-request without having signed the CLA, you will be prompted
|
||||||
It is an online process and quick to do. If you raise a pull-request without
|
to do so automatically.
|
||||||
having signed the CLA, you will be prompted to do so automatically.
|
|
||||||
|
|
||||||
### Code Branches
|
|
||||||
|
|
||||||
When raising a PR for a fix or a new feature, it is important to target the right branch.
|
|
||||||
|
|
||||||
- `master` - this is the main branch for the latest stable release of Node-RED. All bug fixes for that release should target this branch.
|
|
||||||
- `v1.x` - this is the maintenance branch for the 1.x stream. If a fix *only* applies to 1.x, then it should target this branch. If it applies to the current stable release as well, target `master` first. We will then decide if it needs to be back ported to the 1.x stream.
|
|
||||||
- `dev` - this is the branch for new feature development targeting the next milestone release.
|
|
||||||
|
|
||||||
### Coding standards
|
### Coding standards
|
||||||
|
|
||||||
|
607
Gruntfile.js
@ -15,35 +15,21 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs-extra");
|
|
||||||
var sass = require("sass");
|
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
var nodemonArgs = ["-V"];
|
var nodemonArgs = ["-v"];
|
||||||
var flowFile = grunt.option('flowFile');
|
var flowFile = grunt.option('flowFile');
|
||||||
if (flowFile) {
|
if (flowFile) {
|
||||||
nodemonArgs.push(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');
|
var nonHeadless = grunt.option('non-headless');
|
||||||
if (nonHeadless) {
|
if (nonHeadless) {
|
||||||
process.env.NODE_RED_NON_HEADLESS = true;
|
process.env.NODE_RED_NON_HEADLESS = 'true';
|
||||||
}
|
}
|
||||||
const pkg = grunt.file.readJSON('package.json');
|
|
||||||
process.env.NODE_RED_PACKAGE_VERSION = pkg.version;
|
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
pkg: pkg,
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
paths: {
|
paths: {
|
||||||
dist: ".dist"
|
dist: ".dist"
|
||||||
},
|
},
|
||||||
@ -55,8 +41,8 @@ module.exports = function(grunt) {
|
|||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
reporter: 'spec'
|
reporter: 'spec'
|
||||||
},
|
},
|
||||||
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
all: { src: ['test/**/*_spec.js'] },
|
||||||
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
|
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||||
},
|
},
|
||||||
webdriver: {
|
webdriver: {
|
||||||
@ -64,19 +50,18 @@ module.exports = function(grunt) {
|
|||||||
configFile: 'test/editor/wdio.conf.js'
|
configFile: 'test/editor/wdio.conf.js'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
nyc: {
|
mocha_istanbul: {
|
||||||
options: {
|
options: {
|
||||||
cwd: '.',
|
globals: ['expect'],
|
||||||
include: ['packages/node_modules/**'],
|
timeout: 3000,
|
||||||
excludeNodeModules: false,
|
ignoreLeaks: false,
|
||||||
exclude: ['packages/node_modules/@node-red/editor-client/**'],
|
ui: 'bdd',
|
||||||
reporter: ['lcov', 'html','text-summary'],
|
reportFormats: ['lcov','html'],
|
||||||
reportDir: 'coverage',
|
print: 'both'
|
||||||
all: true
|
|
||||||
},
|
},
|
||||||
all: { cmd: false, args: ['grunt', 'simplemocha:all'] },
|
all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||||
core: { options: { exclude:['packages/node_modules/@node-red/editor-client/**', 'packages/node_modules/@node-red/nodes/**']},cmd: false, args: ['grunt', 'simplemocha:core'] },
|
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||||
nodes: { cmd: false, args: ['grunt', 'simplemocha:nodes'] }
|
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||||
},
|
},
|
||||||
jshint: {
|
jshint: {
|
||||||
options: {
|
options: {
|
||||||
@ -92,20 +77,22 @@ module.exports = function(grunt) {
|
|||||||
//"loopfunc": true, // allow functions to be defined in loops
|
//"loopfunc": true, // allow functions to be defined in loops
|
||||||
//"sub": true // don't warn that foo['bar'] should be written as foo.bar
|
//"sub": true // don't warn that foo['bar'] should be written as foo.bar
|
||||||
},
|
},
|
||||||
// all: [
|
all: [
|
||||||
// 'Gruntfile.js',
|
'Gruntfile.js',
|
||||||
// 'red.js',
|
'red.js',
|
||||||
// 'packages/**/*.js'
|
'red/**/*.js',
|
||||||
// ],
|
'nodes/core/*/*.js',
|
||||||
// core: {
|
'editor/js/**/*.js'
|
||||||
// files: {
|
],
|
||||||
// src: [
|
core: {
|
||||||
// 'Gruntfile.js',
|
files: {
|
||||||
// 'red.js',
|
src: [
|
||||||
// 'packages/**/*.js',
|
'Gruntfile.js',
|
||||||
// ]
|
'red.js',
|
||||||
// }
|
'red/**/*.js'
|
||||||
// },
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
nodes: {
|
nodes: {
|
||||||
files: {
|
files: {
|
||||||
src: [ 'nodes/core/*/*.js' ]
|
src: [ 'nodes/core/*/*.js' ]
|
||||||
@ -113,7 +100,7 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
editor: {
|
editor: {
|
||||||
files: {
|
files: {
|
||||||
src: [ 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ]
|
src: [ 'editor/js/**/*.js' ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tests: {
|
tests: {
|
||||||
@ -133,188 +120,145 @@ module.exports = function(grunt) {
|
|||||||
src: [
|
src: [
|
||||||
// Ensure editor source files are concatenated in
|
// Ensure editor source files are concatenated in
|
||||||
// the right order
|
// the right order
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/polyfills.js",
|
"editor/js/red.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
|
"editor/js/events.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/red.js",
|
"editor/js/i18n.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/events.js",
|
"editor/js/settings.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/hooks.js",
|
"editor/js/user.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
|
"editor/js/comms.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
|
"editor/js/text/bidi.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/user.js",
|
"editor/js/text/format.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/comms.js",
|
"editor/js/ui/state.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/runtime.js",
|
"editor/js/nodes.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/multiplayer.js",
|
"editor/js/history.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
|
"editor/js/validators.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/text/format.js",
|
"editor/js/ui/utils.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
|
"editor/js/ui/common/editableList.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/plugins.js",
|
"editor/js/ui/common/checkboxSet.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/nodes.js",
|
"editor/js/ui/common/menu.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/font-awesome.js",
|
"editor/js/ui/common/panels.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/history.js",
|
"editor/js/ui/common/popover.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
|
"editor/js/ui/common/searchBox.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
|
"editor/js/ui/common/tabs.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
|
"editor/js/ui/common/stack.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
|
"editor/js/ui/common/typedInput.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
|
"editor/js/ui/actions.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
|
"editor/js/ui/deploy.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
|
"editor/js/ui/diff.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
|
"editor/js/ui/keyboard.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
|
"editor/js/ui/workspaces.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
|
"editor/js/ui/view.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
"editor/js/ui/view-navigator.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
"editor/js/ui/sidebar.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
|
"editor/js/ui/palette.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js",
|
"editor/js/ui/tab-info.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
"editor/js/ui/tab-config.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
"editor/js/ui/tab-context.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js",
|
"editor/js/ui/palette-editor.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
"editor/js/ui/editor.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
|
"editor/js/ui/editors/*.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js",
|
"editor/js/ui/tray.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
|
"editor/js/ui/clipboard.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
|
"editor/js/ui/library.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
|
"editor/js/ui/notifications.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js",
|
"editor/js/ui/search.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
|
"editor/js/ui/typeSearch.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
|
"editor/js/ui/subflow.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
"editor/js/ui/userSettings.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
|
"editor/js/ui/projects/projects.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
|
"editor/js/ui/projects/projectSettings.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js",
|
"editor/js/ui/projects/projectUserSettings.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js",
|
"editor/js/ui/projects/tab-versionControl.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
|
"editor/js/ui/touch/radialMenu.js"
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/*.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/*.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js",
|
|
||||||
"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",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tour/*.js"
|
|
||||||
],
|
],
|
||||||
nonull: true,
|
dest: "public/red/red.js"
|
||||||
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
|
|
||||||
},
|
},
|
||||||
vendor: {
|
vendor: {
|
||||||
files: [
|
files: {
|
||||||
{
|
"public/vendor/vendor.js": [
|
||||||
src: [
|
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
|
"editor/vendor/bootstrap/js/bootstrap.min.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
|
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
|
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
"editor/vendor/marked/marked.min.js",
|
||||||
"node_modules/marked/marked.min.js",
|
"editor/vendor/d3/d3.v3.min.js",
|
||||||
"node_modules/dompurify/dist/purify.min.js",
|
"editor/vendor/i18next/i18next.min.js"
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
|
],
|
||||||
"node_modules/i18next/i18next.min.js",
|
"public/vendor/vendor.css": [
|
||||||
"node_modules/i18next-http-backend/i18nextHttpBackend.min.js",
|
// TODO: resolve relative resource paths in
|
||||||
"node_modules/jquery-i18next/jquery-i18next.min.js",
|
// bootstrap/FA/jquery
|
||||||
"node_modules/jsonata/jsonata-es5.min.js",
|
],
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js",
|
"public/vendor/jsonata/jsonata.min.js": [
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js",
|
"node_modules/jsonata/jsonata-es5.min.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js"
|
"editor/vendor/jsonata/formatter.js"
|
||||||
],
|
],
|
||||||
nonull: true,
|
"public/vendor/ace/worker-jsonata.js": [
|
||||||
dest: "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js"
|
"node_modules/jsonata/jsonata-es5.min.js",
|
||||||
},
|
"editor/vendor/jsonata/worker-jsonata.js"
|
||||||
// {
|
]
|
||||||
// src: [
|
}
|
||||||
// // TODO: resolve relative resource paths in
|
|
||||||
// // bootstrap/FA/jquery
|
|
||||||
// ],
|
|
||||||
// dest: "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css"
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
src: [
|
|
||||||
"node_modules/jsonata/jsonata-es5.min.js",
|
|
||||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
|
|
||||||
],
|
|
||||||
nonull: true,
|
|
||||||
dest: "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: "node_modules/mermaid/dist/mermaid.min.js",
|
|
||||||
nonull: true,
|
|
||||||
dest: "packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
uglify: {
|
uglify: {
|
||||||
build: {
|
build: {
|
||||||
files: {
|
files: {
|
||||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js',
|
'public/red/red.min.js': 'public/red/red.js',
|
||||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js',
|
'public/red/main.min.js': 'public/red/main.js',
|
||||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js',
|
'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js',
|
||||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js'
|
'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sass: {
|
sass: {
|
||||||
build: {
|
build: {
|
||||||
options: {
|
options: {
|
||||||
implementation: sass,
|
|
||||||
outputStyle: 'compressed'
|
outputStyle: 'compressed'
|
||||||
},
|
},
|
||||||
files: [{
|
files: [{
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css',
|
dest: 'public/red/style.min.css',
|
||||||
src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss'
|
src: 'editor/sass/style.scss'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
|
||||||
|
src: 'editor/vendor/bootstrap/css/bootstrap.css'
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
jsonlint: {
|
jsonlint: {
|
||||||
messages: {
|
messages: {
|
||||||
src: [
|
src: [
|
||||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
'nodes/core/locales/en-US/messages.json',
|
||||||
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
|
'red/api/locales/en-US/editor.json',
|
||||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
'red/runtime/locales/en-US/runtime.json'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
keymaps: {
|
keymaps: {
|
||||||
src: [
|
src: [
|
||||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
'editor/js/keymap.json'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
attachCopyright: {
|
attachCopyright: {
|
||||||
js: {
|
js: {
|
||||||
src: [
|
src: [
|
||||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js',
|
'public/red/red.min.js',
|
||||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js'
|
'public/red/main.min.js'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
src: [
|
src: [
|
||||||
'packages/node_modules/@node-red/editor-client/public/red/style.min.css'
|
'public/red/style.min.css'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clean: {
|
clean: {
|
||||||
build: {
|
build: {
|
||||||
src: [
|
src: [
|
||||||
"packages/node_modules/@node-red/editor-client/public/red",
|
"public/red",
|
||||||
"packages/node_modules/@node-red/editor-client/public/index.html",
|
"public/index.html",
|
||||||
"packages/node_modules/@node-red/editor-client/public/favicon.ico",
|
"public/favicon.ico",
|
||||||
"packages/node_modules/@node-red/editor-client/public/icons",
|
"public/icons",
|
||||||
"packages/node_modules/@node-red/editor-client/public/vendor",
|
"public/vendor"
|
||||||
"packages/node_modules/@node-red/editor-client/public/types/node",
|
|
||||||
"packages/node_modules/@node-red/editor-client/public/types/node-red",
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
release: {
|
release: {
|
||||||
@ -326,36 +270,30 @@ module.exports = function(grunt) {
|
|||||||
watch: {
|
watch: {
|
||||||
js: {
|
js: {
|
||||||
files: [
|
files: [
|
||||||
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
|
'editor/js/**/*.js'
|
||||||
],
|
],
|
||||||
tasks: ['copy:build','concat',/*'uglify',*/ 'attachCopyright:js']
|
tasks: ['copy:build','concat','uglify','attachCopyright:js']
|
||||||
},
|
},
|
||||||
sass: {
|
sass: {
|
||||||
files: [
|
files: [
|
||||||
'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss'
|
'editor/sass/**/*.scss'
|
||||||
],
|
],
|
||||||
tasks: ['sass','attachCopyright:css']
|
tasks: ['sass','attachCopyright:css']
|
||||||
},
|
},
|
||||||
json: {
|
json: {
|
||||||
files: [
|
files: [
|
||||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
'nodes/core/locales/en-US/messages.json',
|
||||||
'packages/node_modules/@node-red/editor-client/locales/**/*.json',
|
'red/api/locales/en-US/editor.json',
|
||||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
'red/runtime/locales/en-US/runtime.json'
|
||||||
],
|
],
|
||||||
tasks: ['jsonlint:messages']
|
tasks: ['jsonlint:messages']
|
||||||
},
|
},
|
||||||
keymaps: {
|
keymaps: {
|
||||||
files: [
|
files: [
|
||||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
'editor/js/keymap.json'
|
||||||
],
|
],
|
||||||
tasks: ['jsonlint:keymaps','copy:build']
|
tasks: ['jsonlint:keymaps','copy:build']
|
||||||
},
|
},
|
||||||
tours: {
|
|
||||||
files: [
|
|
||||||
'packages/node_modules/@node-red/editor-client/src/tours/**/*.js'
|
|
||||||
],
|
|
||||||
tasks: ['copy:build']
|
|
||||||
},
|
|
||||||
misc: {
|
misc: {
|
||||||
files: [
|
files: [
|
||||||
'CHANGELOG.md'
|
'CHANGELOG.md'
|
||||||
@ -367,13 +305,12 @@ module.exports = function(grunt) {
|
|||||||
nodemon: {
|
nodemon: {
|
||||||
/* uses .nodemonignore */
|
/* uses .nodemonignore */
|
||||||
dev: {
|
dev: {
|
||||||
script: 'packages/node_modules/node-red/red.js',
|
script: 'red.js',
|
||||||
options: {
|
options: {
|
||||||
args: nodemonArgs,
|
args: nodemonArgs,
|
||||||
ext: 'js,html,json',
|
ext: 'js,html,json',
|
||||||
watch: [
|
watch: [
|
||||||
'packages/node_modules',
|
'red','nodes'
|
||||||
'!packages/node_modules/@node-red/editor-client'
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,75 +329,69 @@ module.exports = function(grunt) {
|
|||||||
build: {
|
build: {
|
||||||
files:[
|
files:[
|
||||||
{
|
{
|
||||||
src: 'packages/node_modules/@node-red/editor-client/src/js/main.js',
|
src: 'editor/js/main.js',
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js'
|
dest: 'public/red/main.js'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json',
|
src: 'editor/js/keymap.json',
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json'
|
dest: 'public/red/keymap.json'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src/images',
|
cwd: 'editor/images',
|
||||||
src: '**',
|
src: '**',
|
||||||
expand: true,
|
expand: true,
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/images/'
|
dest: 'public/red/images/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src/vendor',
|
cwd: 'editor/vendor',
|
||||||
src: [
|
src: [
|
||||||
'ace/**',
|
'ace/**',
|
||||||
'jquery/css/base/**',
|
//'bootstrap/css/**',
|
||||||
'font-awesome/**',
|
'bootstrap/img/**',
|
||||||
'monaco/dist/**',
|
'jquery/css/**',
|
||||||
'monaco/types/extraLibs.js',
|
'font-awesome/**'
|
||||||
'monaco/style.css',
|
|
||||||
'monaco/monaco-bootstrap.js'
|
|
||||||
],
|
],
|
||||||
expand: true,
|
expand: true,
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
|
dest: 'public/vendor/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src',
|
cwd: 'editor/icons',
|
||||||
src: [
|
|
||||||
'types/node/**/*.ts',
|
|
||||||
'types/node-red/*.ts',
|
|
||||||
],
|
|
||||||
expand: true,
|
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
|
|
||||||
src: '**',
|
src: '**',
|
||||||
expand: true,
|
expand: true,
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/icons/'
|
dest: 'public/icons/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expand: true,
|
expand: true,
|
||||||
src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'],
|
src: ['editor/index.html','editor/favicon.ico'],
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/',
|
dest: 'public/',
|
||||||
flatten: true
|
flatten: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: 'CHANGELOG.md',
|
src: 'CHANGELOG.md',
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
|
dest: 'public/red/about'
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'CHANGELOG.md',
|
|
||||||
dest: 'packages/node_modules/node-red/'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/',
|
|
||||||
src: '**',
|
|
||||||
expand: true,
|
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cwd: 'packages/node_modules/@node-red/editor-client/src/tours',
|
|
||||||
src: '**',
|
|
||||||
expand: true,
|
|
||||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/tours/'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
release: {
|
||||||
|
files: [{
|
||||||
|
mode: true,
|
||||||
|
expand: true,
|
||||||
|
src: [
|
||||||
|
'*.md',
|
||||||
|
'LICENSE',
|
||||||
|
'package.json',
|
||||||
|
'settings.js',
|
||||||
|
'red.js',
|
||||||
|
'lib/.gitignore',
|
||||||
|
'nodes/*.demo',
|
||||||
|
'nodes/core/**',
|
||||||
|
'red/**',
|
||||||
|
'public/**',
|
||||||
|
'editor/templates/**',
|
||||||
|
'bin/**'
|
||||||
|
],
|
||||||
|
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chmod: {
|
chmod: {
|
||||||
@ -469,95 +400,19 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
release: {
|
release: {
|
||||||
src: [
|
src: [
|
||||||
"packages/node_modules/@node-red/nodes/core/hardware/nrgpio",
|
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'),
|
||||||
"packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh"
|
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh')
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'npm-command': {
|
|
||||||
options: {
|
|
||||||
cmd: "pack",
|
|
||||||
cwd: "<%= paths.dist %>/modules"
|
|
||||||
},
|
|
||||||
'node-red': { options: { args: [__dirname+'/packages/node_modules/node-red'] } },
|
|
||||||
'@node-red/editor-api': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-api'] } },
|
|
||||||
'@node-red/editor-client': { options: { args: [__dirname+'/packages/node_modules/@node-red/editor-client'] } },
|
|
||||||
'@node-red/nodes': { options: { args: [__dirname+'/packages/node_modules/@node-red/nodes'] } },
|
|
||||||
'@node-red/registry': { options: { args: [__dirname+'/packages/node_modules/@node-red/registry'] } },
|
|
||||||
'@node-red/runtime': { options: { args: [__dirname+'/packages/node_modules/@node-red/runtime'] } },
|
|
||||||
'@node-red/util': { options: { args: [__dirname+'/packages/node_modules/@node-red/util'] } }
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
mkdir: {
|
|
||||||
release: {
|
|
||||||
options: {
|
|
||||||
create: ['<%= paths.dist %>/modules']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
compress: {
|
compress: {
|
||||||
release: {
|
release: {
|
||||||
options: {
|
options: {
|
||||||
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
|
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
|
||||||
},
|
},
|
||||||
expand: true,
|
expand: true,
|
||||||
cwd: 'packages/node_modules/',
|
cwd: '<%= paths.dist %>/',
|
||||||
src: [
|
src: ['node-red-<%= pkg.version %>/**']
|
||||||
'**',
|
|
||||||
'!@node-red/editor-client/src/**'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
jsdoc : {
|
|
||||||
modules: {
|
|
||||||
src: [
|
|
||||||
'API.md',
|
|
||||||
'packages/node_modules/node-red/lib/red.js',
|
|
||||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
|
||||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
|
||||||
'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',
|
|
||||||
'packages/node_modules/@node-red/registry/lib/index.js'
|
|
||||||
],
|
|
||||||
options: {
|
|
||||||
destination: 'docs',
|
|
||||||
configure: './jsdoc.json',
|
|
||||||
fred: "hi there"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_editor: {
|
|
||||||
src: [
|
|
||||||
'packages/node_modules/@node-red/editor-client/src/js'
|
|
||||||
],
|
|
||||||
options: {
|
|
||||||
destination: 'packages/node_modules/@node-red/editor-client/docs',
|
|
||||||
configure: './jsdoc.json'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
jsdoc2md: {
|
|
||||||
runtimeAPI: {
|
|
||||||
options: {
|
|
||||||
separators: true
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
|
||||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
|
||||||
'packages/node_modules/@node-red/runtime/lib/events.js'
|
|
||||||
],
|
|
||||||
dest: 'packages/node_modules/@node-red/runtime/docs/api.md'
|
|
||||||
},
|
|
||||||
nodeREDUtil: {
|
|
||||||
options: {
|
|
||||||
separators: true
|
|
||||||
},
|
|
||||||
src: 'packages/node_modules/@node-red/util/**/*.js',
|
|
||||||
dest: 'packages/node_modules/@node-red/util/docs/api.md'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -570,42 +425,18 @@ module.exports = function(grunt) {
|
|||||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||||
grunt.loadNpmTasks('grunt-concurrent');
|
grunt.loadNpmTasks('grunt-concurrent');
|
||||||
grunt.loadNpmTasks('grunt-sass');
|
grunt.loadNpmTasks('grunt-sass');
|
||||||
|
grunt.loadNpmTasks('grunt-nodemon');
|
||||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||||
grunt.loadNpmTasks('grunt-chmod');
|
grunt.loadNpmTasks('grunt-chmod');
|
||||||
grunt.loadNpmTasks('grunt-jsonlint');
|
grunt.loadNpmTasks('grunt-jsonlint');
|
||||||
if (fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
|
grunt.loadNpmTasks('grunt-mocha-istanbul');
|
||||||
grunt.loadNpmTasks('grunt-webdriver');
|
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() {
|
grunt.registerMultiTask('attachCopyright', function() {
|
||||||
var files = this.data.src;
|
var files = this.data.src;
|
||||||
var copyright = "/**\n"+
|
var copyright = "/**\n"+
|
||||||
" * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\n"+
|
" * Copyright JS Foundation and other contributors, http://js.foundation\n"+
|
||||||
" *\n"+
|
" *\n"+
|
||||||
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
|
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
|
||||||
" * you may not use this file except in compliance with the License.\n"+
|
" * you may not use this file except in compliance with the License.\n"+
|
||||||
@ -642,38 +473,6 @@ module.exports = function(grunt) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
grunt.registerTask('verifyPackageDependencies', function() {
|
|
||||||
var done = this.async();
|
|
||||||
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
|
|
||||||
verifyDependencies().then(function(failures) {
|
|
||||||
if (failures.length > 0) {
|
|
||||||
failures.forEach(f => grunt.log.error(f));
|
|
||||||
grunt.fail.fatal("Failed to verify package dependencies");
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.registerTask('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"');
|
|
||||||
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',
|
grunt.registerTask('setDevEnv',
|
||||||
'Sets NODE_ENV=development so non-minified assets are used',
|
'Sets NODE_ENV=development so non-minified assets are used',
|
||||||
function () {
|
function () {
|
||||||
@ -682,61 +481,37 @@ module.exports = function(grunt) {
|
|||||||
|
|
||||||
grunt.registerTask('default',
|
grunt.registerTask('default',
|
||||||
'Builds editor content then runs code style checks and unit tests on all components',
|
'Builds editor content then runs code style checks and unit tests on all components',
|
||||||
['build','verifyPackageDependencies','jshint:editor','nyc:all']);
|
['build','jshint:editor','mocha_istanbul:all']);
|
||||||
|
|
||||||
grunt.registerTask('no-coverage',
|
|
||||||
'Builds editor content then runs code style checks and unit tests on all components without code coverage',
|
|
||||||
['build','verifyPackageDependencies','jshint:editor','simplemocha:all']);
|
|
||||||
|
|
||||||
|
|
||||||
grunt.registerTask('test-core',
|
grunt.registerTask('test-core',
|
||||||
'Runs code style check and unit tests on core runtime code',
|
'Runs code style check and unit tests on core runtime code',
|
||||||
['build','nyc:core']);
|
['build','mocha_istanbul:core']);
|
||||||
|
|
||||||
grunt.registerTask('test-editor',
|
grunt.registerTask('test-editor',
|
||||||
'Runs code style check on editor code',
|
'Runs code style check on editor code',
|
||||||
['jshint:editor']);
|
['jshint:editor']);
|
||||||
|
|
||||||
if (!fs.existsSync(path.join("node_modules", "grunt-webdriver"))) {
|
grunt.registerTask('test-ui',
|
||||||
grunt.registerTask('test-ui',
|
'Builds editor content then runs unit tests on editor ui',
|
||||||
'Builds editor content then runs unit tests on editor ui',
|
['build','jshint:editor','webdriver:all']);
|
||||||
['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-nodes',
|
grunt.registerTask('test-nodes',
|
||||||
'Runs unit tests on core nodes',
|
'Runs unit tests on core nodes',
|
||||||
['build','nyc:nodes']);
|
['build','mocha_istanbul:nodes']);
|
||||||
|
|
||||||
grunt.registerTask('build',
|
grunt.registerTask('build',
|
||||||
'Builds editor content',
|
'Builds editor content',
|
||||||
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
|
['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',
|
grunt.registerTask('dev',
|
||||||
'Developer mode: run node-red, watch for source changes and build/restart',
|
'Developer mode: run node-red, watch for source changes and build/restart',
|
||||||
['build','setDevEnv','concurrent:dev']);
|
['build','setDevEnv','concurrent:dev']);
|
||||||
|
|
||||||
grunt.registerTask('release',
|
grunt.registerTask('release',
|
||||||
'Create distribution zip file',
|
'Create distribution zip file',
|
||||||
['build','verifyPackageDependencies','clean:release','mkdir:release','chmod:release','compress:release','pack-modules','generatePublishScript']);
|
['build','clean:release','copy:release','chmod:release','compress:release']);
|
||||||
|
|
||||||
grunt.registerTask('pack-modules',
|
|
||||||
'Create module pack files for release',
|
|
||||||
['mkdir:release','npm-command']);
|
|
||||||
|
|
||||||
|
|
||||||
grunt.registerTask('coverage',
|
grunt.registerTask('coverage',
|
||||||
'Run Istanbul code test coverage task',
|
'Run Istanbul code test coverage task',
|
||||||
['build','nyc:all']);
|
['build','mocha_istanbul:all']);
|
||||||
|
|
||||||
grunt.registerTask('docs',
|
|
||||||
'Generates API documentation',
|
|
||||||
['jsdoc']);
|
|
||||||
};
|
};
|
||||||
|
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
|
Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
|
28
README.md
@ -1,16 +1,17 @@
|
|||||||
# Node-RED
|
# Node-RED
|
||||||
|
|
||||||
https://nodered.org
|
http://nodered.org
|
||||||
|
|
||||||
[](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
|
[](https://travis-ci.org/node-red/node-red)
|
||||||
|
[](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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
|
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||||
started.
|
started.
|
||||||
|
|
||||||
1. `sudo npm install -g --unsafe-perm node-red`
|
1. `sudo npm install -g --unsafe-perm node-red`
|
||||||
@ -19,7 +20,7 @@ started.
|
|||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
More documentation can be found [here](https://nodered.org/docs).
|
More documentation can be found [here](http://nodered.org/docs).
|
||||||
|
|
||||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||||
|
|
||||||
@ -43,6 +44,9 @@ If you want to run the latest code from git, here's how to get started:
|
|||||||
4. Run
|
4. Run
|
||||||
|
|
||||||
npm start
|
npm start
|
||||||
|
or
|
||||||
|
|
||||||
|
node red.js
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@ -55,15 +59,15 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena
|
|||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
Node-RED is a project of the [OpenJS Foundation](http://openjsf.org).
|
Node-RED is a project of the [JS Foundation](http://js.foundation).
|
||||||
|
|
||||||
It is maintained by:
|
It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
|
||||||
|
|
||||||
|
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
|
||||||
|
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
|
||||||
|
|
||||||
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
|
|
||||||
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
|
|
||||||
* And many others...
|
|
||||||
|
|
||||||
|
|
||||||
## Copyright and license
|
## 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).
|
||||||
|
@ -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.
|
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# Copyright JS Foundation and other contributors, http://js.foundation
|
# Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
#
|
#
|
||||||
@ -29,16 +29,15 @@ do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Find the real location of this script
|
# Find the real location of this script
|
||||||
CURRENT_PATH=$(pwd)
|
CURRENT_PATH=`pwd`
|
||||||
SCRIPT_PATH=$(readlink -f "$0")
|
SCRIPT_PATH="${BASH_SOURCE[0]}";
|
||||||
while [ -h "${SCRIPT_PATH}" ]; do
|
while [ -h "${SCRIPT_PATH}" ]; do
|
||||||
cd "$(dirname "${SCRIPT_PATH}")" || exit 1
|
cd "`dirname "${SCRIPT_PATH}"`"
|
||||||
P=$(basename "${SCRIPT_PATH}")
|
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
|
||||||
SCRIPT_PATH=$(readlink "${P}")
|
|
||||||
done
|
done
|
||||||
cd "$(dirname "${SCRIPT_PATH}")" > /dev/null || exit 1
|
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
|
||||||
SCRIPT_PATH=$(pwd)
|
SCRIPT_PATH="`pwd`";
|
||||||
cd "$CURRENT_PATH" || exit 1
|
cd $CURRENT_PATH
|
||||||
|
|
||||||
# Run Node-RED
|
# Run Node-RED
|
||||||
exec /usr/bin/env node ${OPTIONS} "${SCRIPT_PATH}"/../red.js ${ARGS}
|
exec /usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
BIN
editor/icons/alert.png
Normal file
After Width: | Height: | Size: 308 B |
BIN
editor/icons/arduino.png
Normal file
After Width: | Height: | Size: 603 B |
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B |
BIN
editor/icons/batch.png
Normal file
After Width: | Height: | Size: 712 B |
BIN
editor/icons/bluetooth.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
editor/icons/bridge-dash.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
editor/icons/bridge.png
Normal file
After Width: | Height: | Size: 575 B |
BIN
editor/icons/cog.png
Normal file
After Width: | Height: | Size: 493 B |
BIN
editor/icons/comment.png
Normal file
After Width: | Height: | Size: 601 B |
BIN
editor/icons/db.png
Normal file
After Width: | Height: | Size: 459 B |
BIN
editor/icons/debug.png
Normal file
After Width: | Height: | Size: 218 B |
BIN
editor/icons/envelope.png
Normal file
After Width: | Height: | Size: 324 B |
BIN
editor/icons/feed.png
Normal file
After Width: | Height: | Size: 378 B |
BIN
editor/icons/file-in.png
Normal file
After Width: | Height: | Size: 542 B |
BIN
editor/icons/file-out.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
editor/icons/file.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
editor/icons/function.png
Normal file
After Width: | Height: | Size: 457 B |
BIN
editor/icons/hash.png
Normal file
After Width: | Height: | Size: 502 B |
BIN
editor/icons/inject.png
Normal file
After Width: | Height: | Size: 449 B |
BIN
editor/icons/join.png
Normal file
After Width: | Height: | Size: 253 B |
BIN
editor/icons/leveldb.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
editor/icons/light.png
Normal file
After Width: | Height: | Size: 639 B |
BIN
editor/icons/link-out.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
editor/icons/mongodb.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
editor/icons/mouse.png
Normal file
After Width: | Height: | Size: 671 B |
BIN
editor/icons/node-changed.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
editor/icons/node-error.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
editor/icons/parser-csv.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
editor/icons/parser-html.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
editor/icons/parser-json.png
Normal file
After Width: | Height: | Size: 467 B |
BIN
editor/icons/parser-xml.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
editor/icons/parser-yaml.png
Normal file
After Width: | Height: | Size: 423 B |
BIN
editor/icons/range.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
editor/icons/redis.png
Normal file
After Width: | Height: | Size: 736 B |
BIN
editor/icons/rpi.png
Normal file
After Width: | Height: | Size: 482 B |
BIN
editor/icons/serial.png
Normal file
After Width: | Height: | Size: 273 B |
BIN
editor/icons/sort.png
Normal file
After Width: | Height: | Size: 793 B |
BIN
editor/icons/split.png
Normal file
After Width: | Height: | Size: 256 B |
BIN
editor/icons/subflow.png
Normal file
After Width: | Height: | Size: 439 B |
BIN
editor/icons/swap.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
editor/icons/switch.png
Normal file
After Width: | Height: | Size: 509 B |
BIN
editor/icons/template.png
Normal file
After Width: | Height: | Size: 488 B |
BIN
editor/icons/timer.png
Normal file
After Width: | Height: | Size: 628 B |
BIN
editor/icons/trigger.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
editor/icons/twitter.png
Normal file
After Width: | Height: | Size: 404 B |
BIN
editor/icons/watch.png
Normal file
After Width: | Height: | Size: 591 B |
BIN
editor/icons/white-globe.png
Normal file
After Width: | Height: | Size: 707 B |
BIN
editor/images/deploy-flows-o.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
editor/images/deploy-flows.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
editor/images/deploy-full-o.png
Normal file
After Width: | Height: | Size: 289 B |
BIN
editor/images/deploy-full.png
Normal file
After Width: | Height: | Size: 368 B |
BIN
editor/images/deploy-nodes-o.png
Normal file
After Width: | Height: | Size: 290 B |
BIN
editor/images/deploy-nodes.png
Normal file
After Width: | Height: | Size: 392 B |
BIN
editor/images/grip.png
Normal file
After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
editor/images/node-red.png
Normal file
After Width: | Height: | Size: 1019 B |
BIN
editor/images/pw_maze_white.png
Normal file
After Width: | Height: | Size: 600 B |
BIN
editor/images/subflow_tab.png
Normal file
After Width: | Height: | Size: 410 B |
BIN
editor/images/typedInput/09.png
Normal file
After Width: | Height: | Size: 638 B |
BIN
editor/images/typedInput/az.png
Normal file
After Width: | Height: | Size: 546 B |
BIN
editor/images/typedInput/bin.png
Normal file
After Width: | Height: | Size: 638 B |
BIN
editor/images/typedInput/bool.png
Normal file
After Width: | Height: | Size: 646 B |
BIN
editor/images/typedInput/env.png
Normal file
After Width: | Height: | Size: 809 B |
BIN
editor/images/typedInput/expr.png
Normal file
After Width: | Height: | Size: 563 B |
BIN
editor/images/typedInput/json.png
Normal file
After Width: | Height: | Size: 588 B |
BIN
editor/images/typedInput/re.png
Normal file
After Width: | Height: | Size: 502 B |
@ -26,35 +26,16 @@ RED.comms = (function() {
|
|||||||
var reconnectAttempts = 0;
|
var reconnectAttempts = 0;
|
||||||
var active = false;
|
var active = false;
|
||||||
|
|
||||||
RED.events.on('login', function(username) {
|
|
||||||
// User has logged in
|
|
||||||
// Need to upgrade the connection to be authenticated
|
|
||||||
if (ws && ws.readyState == 1) {
|
|
||||||
const auth_tokens = RED.settings.get("auth-tokens");
|
|
||||||
ws.send(JSON.stringify({auth:auth_tokens.access_token}))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function connectWS() {
|
function connectWS() {
|
||||||
active = true;
|
active = true;
|
||||||
var wspath;
|
var path = location.hostname;
|
||||||
|
var port = location.port;
|
||||||
if (RED.settings.apiRootUrl) {
|
if (port.length !== 0) {
|
||||||
var m = /^(https?):\/\/(.*)$/.exec(RED.settings.apiRootUrl);
|
path = path+":"+port;
|
||||||
if (m) {
|
|
||||||
console.log(m);
|
|
||||||
wspath = "ws"+(m[1]==="https"?"s":"")+"://"+m[2]+"comms";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var path = location.hostname;
|
|
||||||
var port = location.port;
|
|
||||||
if (port.length !== 0) {
|
|
||||||
path = path+":"+port;
|
|
||||||
}
|
|
||||||
path = path+document.location.pathname;
|
|
||||||
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
|
|
||||||
wspath = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
|
|
||||||
}
|
}
|
||||||
|
path = path+document.location.pathname;
|
||||||
|
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
|
||||||
|
path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
|
||||||
|
|
||||||
var auth_tokens = RED.settings.get("auth-tokens");
|
var auth_tokens = RED.settings.get("auth-tokens");
|
||||||
pendingAuth = (auth_tokens!=null);
|
pendingAuth = (auth_tokens!=null);
|
||||||
@ -65,10 +46,9 @@ RED.comms = (function() {
|
|||||||
ws.send(JSON.stringify({subscribe:t}));
|
ws.send(JSON.stringify({subscribe:t}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit('connect')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ws = new WebSocket(wspath);
|
ws = new WebSocket(path);
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
reconnectAttempts = 0;
|
reconnectAttempts = 0;
|
||||||
if (errornotification) {
|
if (errornotification) {
|
||||||
@ -85,39 +65,29 @@ RED.comms = (function() {
|
|||||||
}
|
}
|
||||||
ws.onmessage = function(event) {
|
ws.onmessage = function(event) {
|
||||||
var message = JSON.parse(event.data);
|
var message = JSON.parse(event.data);
|
||||||
if (message.auth) {
|
for (var m = 0; m < message.length; m++) {
|
||||||
if (pendingAuth) {
|
var msg = message[m];
|
||||||
if (message.auth === "ok") {
|
if (pendingAuth && msg.auth) {
|
||||||
|
if (msg.auth === "ok") {
|
||||||
pendingAuth = false;
|
pendingAuth = false;
|
||||||
completeConnection();
|
completeConnection();
|
||||||
} else if (message.auth === "fail") {
|
} else if (msg.auth === "fail") {
|
||||||
// anything else is an error...
|
// anything else is an error...
|
||||||
active = false;
|
active = false;
|
||||||
RED.user.login({updateMenu:true},function() {
|
RED.user.login({updateMenu:true},function() {
|
||||||
connectWS();
|
connectWS();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (message.auth === "fail") {
|
|
||||||
// Our current session has expired
|
|
||||||
active = false;
|
|
||||||
RED.user.login({updateMenu:true},function() {
|
|
||||||
connectWS();
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
else if (msg.topic) {
|
||||||
// Otherwise, 'message' is an array of actual comms messages
|
for (var t in subscriptions) {
|
||||||
for (var m = 0; m < message.length; m++) {
|
if (subscriptions.hasOwnProperty(t)) {
|
||||||
var msg = message[m];
|
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
|
||||||
if (msg.topic) {
|
if (re.test(msg.topic)) {
|
||||||
for (var t in subscriptions) {
|
var subscribers = subscriptions[t];
|
||||||
if (subscriptions.hasOwnProperty(t)) {
|
if (subscribers) {
|
||||||
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
|
for (var i=0;i<subscribers.length;i++) {
|
||||||
if (re.test(msg.topic)) {
|
subscribers[i](msg.topic,msg.data);
|
||||||
var subscribers = subscriptions[t];
|
|
||||||
if (subscribers) {
|
|
||||||
for (var i=0;i<subscribers.length;i++) {
|
|
||||||
subscribers[i](msg.topic,msg.data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,10 +122,10 @@ RED.comms = (function() {
|
|||||||
connectWS();
|
connectWS();
|
||||||
} else {
|
} else {
|
||||||
var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>';
|
var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>';
|
||||||
errornotification.update(msg,{silent:true});
|
errornotification.update(msg);
|
||||||
$(errornotification).find("a").on("click", function(e) {
|
$(errornotification).find("a").click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
errornotification.update(RED._("notification.errors.lostConnection"),{silent:true});
|
errornotification.update(RED._("notification.errors.lostConnection"));
|
||||||
clearInterval(connectCountdownTimer);
|
clearInterval(connectCountdownTimer);
|
||||||
connectWS();
|
connectWS();
|
||||||
})
|
})
|
||||||
@ -190,53 +160,9 @@ RED.comms = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function send(topic, msg) {
|
|
||||||
if (ws && ws.readyState == 1) {
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
topic,
|
|
||||||
data: msg
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventHandlers = {};
|
|
||||||
function on(evt,func) {
|
|
||||||
eventHandlers[evt] = eventHandlers[evt]||[];
|
|
||||||
eventHandlers[evt].push(func);
|
|
||||||
}
|
|
||||||
function off(evt,func) {
|
|
||||||
const handler = eventHandlers[evt];
|
|
||||||
if (handler) {
|
|
||||||
for (let i=0;i<handler.length;i++) {
|
|
||||||
if (handler[i] === func) {
|
|
||||||
handler.splice(i,1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function emit() {
|
|
||||||
const evt = arguments[0]
|
|
||||||
const args = Array.prototype.slice.call(arguments,1);
|
|
||||||
if (eventHandlers[evt]) {
|
|
||||||
let cpyHandlers = [...eventHandlers[evt]];
|
|
||||||
for (let i=0;i<cpyHandlers.length;i++) {
|
|
||||||
try {
|
|
||||||
cpyHandlers[i].apply(null, args);
|
|
||||||
} catch(err) {
|
|
||||||
console.warn("RED.comms.emit error: ["+evt+"] "+(err.toString()));
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connect: connectWS,
|
connect: connectWS,
|
||||||
subscribe: subscribe,
|
subscribe: subscribe,
|
||||||
unsubscribe:unsubscribe,
|
unsubscribe:unsubscribe
|
||||||
on,
|
|
||||||
off,
|
|
||||||
send
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
@ -32,23 +32,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function emit() {
|
function emit(evt,arg) {
|
||||||
var evt = arguments[0]
|
|
||||||
var args = Array.prototype.slice.call(arguments,1);
|
|
||||||
if (RED.events.DEBUG) {
|
|
||||||
console.warn(evt,args);
|
|
||||||
}
|
|
||||||
if (handlers[evt]) {
|
if (handlers[evt]) {
|
||||||
let cpyHandlers = [...handlers[evt]];
|
for (var i=0;i<handlers[evt].length;i++) {
|
||||||
|
|
||||||
for (var i=0;i<cpyHandlers.length;i++) {
|
|
||||||
try {
|
try {
|
||||||
cpyHandlers[i].apply(null, args);
|
handlers[evt][i](arg);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
|
console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
|
||||||
console.warn(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
332
editor/js/history.js
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
RED.history = (function() {
|
||||||
|
var undo_history = [];
|
||||||
|
|
||||||
|
function undoEvent(ev) {
|
||||||
|
var i;
|
||||||
|
var len;
|
||||||
|
var node;
|
||||||
|
var subflow;
|
||||||
|
var modifiedTabs = {};
|
||||||
|
if (ev) {
|
||||||
|
if (ev.t == 'multi') {
|
||||||
|
len = ev.events.length;
|
||||||
|
for (i=len-1;i>=0;i--) {
|
||||||
|
undoEvent(ev.events[i]);
|
||||||
|
}
|
||||||
|
} else if (ev.t == 'replace') {
|
||||||
|
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') {
|
||||||
|
if (ev.nodes) {
|
||||||
|
for (i=0;i<ev.nodes.length;i++) {
|
||||||
|
node = RED.nodes.node(ev.nodes[i]);
|
||||||
|
if (node.z) {
|
||||||
|
modifiedTabs[node.z] = true;
|
||||||
|
}
|
||||||
|
RED.nodes.remove(ev.nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.links) {
|
||||||
|
for (i=0;i<ev.links.length;i++) {
|
||||||
|
RED.nodes.removeLink(ev.links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.workspaces) {
|
||||||
|
for (i=0;i<ev.workspaces.length;i++) {
|
||||||
|
RED.nodes.removeWorkspace(ev.workspaces[i].id);
|
||||||
|
RED.workspaces.remove(ev.workspaces[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.subflows) {
|
||||||
|
for (i=0;i<ev.subflows.length;i++) {
|
||||||
|
RED.nodes.removeSubflow(ev.subflows[i]);
|
||||||
|
RED.workspaces.remove(ev.subflows[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.subflow) {
|
||||||
|
if (ev.subflow.instances) {
|
||||||
|
ev.subflow.instances.forEach(function(n) {
|
||||||
|
var node = RED.nodes.node(n.id);
|
||||||
|
if (node) {
|
||||||
|
node.changed = n.changed;
|
||||||
|
node.dirty = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ev.subflow.hasOwnProperty('changed')) {
|
||||||
|
subflow = RED.nodes.subflow(ev.subflow.id);
|
||||||
|
if (subflow) {
|
||||||
|
subflow.changed = ev.subflow.changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.removedLinks) {
|
||||||
|
for (i=0;i<ev.removedLinks.length;i++) {
|
||||||
|
RED.nodes.addLink(ev.removedLinks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ev.t == "delete") {
|
||||||
|
if (ev.workspaces) {
|
||||||
|
for (i=0;i<ev.workspaces.length;i++) {
|
||||||
|
RED.nodes.addWorkspace(ev.workspaces[i]);
|
||||||
|
RED.workspaces.add(ev.workspaces[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.subflow && ev.subflow.subflow) {
|
||||||
|
RED.nodes.addSubflow(ev.subflow.subflow);
|
||||||
|
}
|
||||||
|
if (ev.subflowInputs && ev.subflowInputs.length > 0) {
|
||||||
|
subflow = RED.nodes.subflow(ev.subflowInputs[0].z);
|
||||||
|
subflow.in.push(ev.subflowInputs[0]);
|
||||||
|
subflow.in[0].dirty = true;
|
||||||
|
}
|
||||||
|
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
|
||||||
|
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
|
||||||
|
ev.subflowOutputs.sort(function(a,b) { return a.i-b.i});
|
||||||
|
for (i=0;i<ev.subflowOutputs.length;i++) {
|
||||||
|
var output = ev.subflowOutputs[i];
|
||||||
|
subflow.out.splice(output.i,0,output);
|
||||||
|
for (var j=output.i+1;j<subflow.out.length;j++) {
|
||||||
|
subflow.out[j].i++;
|
||||||
|
subflow.out[j].dirty = true;
|
||||||
|
}
|
||||||
|
RED.nodes.eachLink(function(l) {
|
||||||
|
if (l.source.type == "subflow:"+subflow.id) {
|
||||||
|
if (l.sourcePort >= output.i) {
|
||||||
|
l.sourcePort++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
|
||||||
|
ev.subflow.instances.forEach(function(n) {
|
||||||
|
var node = RED.nodes.node(n.id);
|
||||||
|
if (node) {
|
||||||
|
node.changed = n.changed;
|
||||||
|
node.dirty = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (subflow) {
|
||||||
|
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.nodes) {
|
||||||
|
for (i=0;i<ev.nodes.length;i++) {
|
||||||
|
RED.nodes.add(ev.nodes[i]);
|
||||||
|
modifiedTabs[ev.nodes[i].z] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.links) {
|
||||||
|
for (i=0;i<ev.links.length;i++) {
|
||||||
|
RED.nodes.addLink(ev.links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.changes) {
|
||||||
|
for (i in ev.changes) {
|
||||||
|
if (ev.changes.hasOwnProperty(i)) {
|
||||||
|
node = RED.nodes.node(i);
|
||||||
|
if (node) {
|
||||||
|
for (var d in ev.changes[i]) {
|
||||||
|
if (ev.changes[i].hasOwnProperty(d)) {
|
||||||
|
node[d] = ev.changes[i][d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (ev.t == "move") {
|
||||||
|
for (i=0;i<ev.nodes.length;i++) {
|
||||||
|
var n = ev.nodes[i];
|
||||||
|
n.n.x = n.ox;
|
||||||
|
n.n.y = n.oy;
|
||||||
|
n.n.dirty = true;
|
||||||
|
n.n.moved = n.moved;
|
||||||
|
}
|
||||||
|
// A move could have caused a link splice
|
||||||
|
if (ev.links) {
|
||||||
|
for (i=0;i<ev.links.length;i++) {
|
||||||
|
RED.nodes.removeLink(ev.links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.removedLinks) {
|
||||||
|
for (i=0;i<ev.removedLinks.length;i++) {
|
||||||
|
RED.nodes.addLink(ev.removedLinks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev.t == "edit") {
|
||||||
|
for (i in ev.changes) {
|
||||||
|
if (ev.changes.hasOwnProperty(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);
|
||||||
|
}
|
||||||
|
var newConfigNode = RED.nodes.node(ev.changes[i]);
|
||||||
|
if (newConfigNode) {
|
||||||
|
newConfigNode.users.push(ev.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ev.node[i] = ev.changes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.subflow) {
|
||||||
|
if (ev.subflow.hasOwnProperty('inputCount')) {
|
||||||
|
if (ev.node.in.length > 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')) {
|
||||||
|
if (ev.node.out.length > 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')) {
|
||||||
|
ev.subflow.instances.forEach(function(n) {
|
||||||
|
var node = RED.nodes.node(n.id);
|
||||||
|
if (node) {
|
||||||
|
node.changed = n.changed;
|
||||||
|
node.dirty = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.editor.validateNode(ev.node);
|
||||||
|
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
||||||
|
n.inputs = ev.node.in.length;
|
||||||
|
n.outputs = ev.node.out.length;
|
||||||
|
RED.editor.updateNodeProperties(n);
|
||||||
|
RED.editor.validateNode(n);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var outputMap;
|
||||||
|
if (ev.outputMap) {
|
||||||
|
outputMap = {};
|
||||||
|
for (var port in ev.outputMap) {
|
||||||
|
if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") {
|
||||||
|
outputMap[ev.outputMap[port]] = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RED.editor.updateNodeProperties(ev.node,outputMap);
|
||||||
|
RED.editor.validateNode(ev.node);
|
||||||
|
}
|
||||||
|
if (ev.links) {
|
||||||
|
for (i=0;i<ev.links.length;i++) {
|
||||||
|
RED.nodes.addLink(ev.links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ev.node.dirty = true;
|
||||||
|
ev.node.changed = ev.changed;
|
||||||
|
} else if (ev.t == "createSubflow") {
|
||||||
|
if (ev.nodes) {
|
||||||
|
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
|
||||||
|
n.z = ev.activeWorkspace;
|
||||||
|
n.dirty = true;
|
||||||
|
});
|
||||||
|
for (i=0;i<ev.nodes.length;i++) {
|
||||||
|
RED.nodes.remove(ev.nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.links) {
|
||||||
|
for (i=0;i<ev.links.length;i++) {
|
||||||
|
RED.nodes.removeLink(ev.links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.nodes.removeSubflow(ev.subflow.subflow);
|
||||||
|
RED.workspaces.remove(ev.subflow.subflow);
|
||||||
|
|
||||||
|
if (ev.removedLinks) {
|
||||||
|
for (i=0;i<ev.removedLinks.length;i++) {
|
||||||
|
RED.nodes.addLink(ev.removedLinks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev.t == "reorder") {
|
||||||
|
if (ev.order) {
|
||||||
|
RED.workspaces.order(ev.order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.keys(modifiedTabs).forEach(function(id) {
|
||||||
|
var subflow = RED.nodes.subflow(id);
|
||||||
|
if (subflow) {
|
||||||
|
RED.editor.validateNode(subflow);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RED.nodes.dirty(ev.dirty);
|
||||||
|
RED.view.redraw(true);
|
||||||
|
RED.palette.refresh();
|
||||||
|
RED.workspaces.refresh();
|
||||||
|
RED.sidebar.config.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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<undo_history.length;i++) {
|
||||||
|
undo_history[i].dirty = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list: function() {
|
||||||
|
return undo_history
|
||||||
|
},
|
||||||
|
depth: function() {
|
||||||
|
return undo_history.length;
|
||||||
|
},
|
||||||
|
push: function(ev) {
|
||||||
|
undo_history.push(ev);
|
||||||
|
},
|
||||||
|
pop: function() {
|
||||||
|
var ev = undo_history.pop();
|
||||||
|
undoEvent(ev);
|
||||||
|
},
|
||||||
|
peek: function() {
|
||||||
|
return undo_history[undo_history.length-1];
|
||||||
|
},
|
||||||
|
clear: function() {
|
||||||
|
undo_history = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
86
editor/js/i18n.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
RED.i18n = (function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function(done) {
|
||||||
|
i18n.init({
|
||||||
|
resGetPath: 'locales/__ns__?lng=__lng__',
|
||||||
|
dynamicLoad: false,
|
||||||
|
load:'current',
|
||||||
|
ns: {
|
||||||
|
namespaces: ["editor","node-red","jsonata","infotips"],
|
||||||
|
defaultNs: "editor"
|
||||||
|
},
|
||||||
|
fallbackLng: ['en-US'],
|
||||||
|
useCookie: false
|
||||||
|
},function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
RED["_"] = function() {
|
||||||
|
return i18n.t.apply(null,arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
loadCatalog: function(namespace,done) {
|
||||||
|
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
|
||||||
|
var toLoad = languageList.length;
|
||||||
|
languageList.forEach(function(lang) {
|
||||||
|
$.ajax({
|
||||||
|
headers: {
|
||||||
|
"Accept":"application/json"
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
url: 'locales/'+namespace+'?lng='+lang,
|
||||||
|
success: function(data) {
|
||||||
|
i18n.addResourceBundle(lang,namespace,data);
|
||||||
|
toLoad--;
|
||||||
|
if (toLoad === 0) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
loadNodeCatalogs: function(done) {
|
||||||
|
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
|
||||||
|
var toLoad = languageList.length;
|
||||||
|
|
||||||
|
languageList.forEach(function(lang) {
|
||||||
|
$.ajax({
|
||||||
|
headers: {
|
||||||
|
"Accept":"application/json"
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
url: 'locales/nodes?lng='+lang,
|
||||||
|
success: function(data) {
|
||||||
|
var namespaces = Object.keys(data);
|
||||||
|
namespaces.forEach(function(ns) {
|
||||||
|
i18n.addResourceBundle(lang,ns,data[ns]);
|
||||||
|
});
|
||||||
|
toLoad--;
|
||||||
|
if (toLoad === 0) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
44
editor/js/keymap.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"*": {
|
||||||
|
"ctrl-shift-p":"core:manage-palette",
|
||||||
|
"ctrl-f": "core:search",
|
||||||
|
"ctrl-=": "core:zoom-in",
|
||||||
|
"ctrl--": "core:zoom-out",
|
||||||
|
"ctrl-0": "core:zoom-reset",
|
||||||
|
"ctrl-enter": "core:confirm-edit-tray",
|
||||||
|
"ctrl-escape": "core:cancel-edit-tray",
|
||||||
|
"ctrl-g i": "core:show-info-tab",
|
||||||
|
"ctrl-g d": "core:show-debug-tab",
|
||||||
|
"ctrl-g c": "core:show-config-tab",
|
||||||
|
"ctrl-g x": "core:show-context-tab",
|
||||||
|
"ctrl-e": "core:show-export-dialog",
|
||||||
|
"ctrl-i": "core:show-import-dialog",
|
||||||
|
"ctrl-space": "core:toggle-sidebar",
|
||||||
|
"ctrl-,": "core:show-user-settings",
|
||||||
|
"ctrl-alt-r": "core:show-remote-diff",
|
||||||
|
"ctrl-alt-n": "core:new-project",
|
||||||
|
"ctrl-alt-o": "core:open-project",
|
||||||
|
"ctrl-g v": "core:show-version-control-tab"
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"backspace": "core:delete-selection",
|
||||||
|
"delete": "core:delete-selection",
|
||||||
|
"enter": "core:edit-selected-node",
|
||||||
|
"ctrl-c": "core:copy-selection-to-internal-clipboard",
|
||||||
|
"ctrl-x": "core:cut-selection-to-internal-clipboard",
|
||||||
|
"ctrl-v": "core:paste-from-internal-clipboard",
|
||||||
|
"ctrl-z": "core:undo",
|
||||||
|
"ctrl-a": "core:select-all-nodes",
|
||||||
|
"shift-?": "core:show-help",
|
||||||
|
"up": "core:move-selection-up",
|
||||||
|
"right": "core:move-selection-right",
|
||||||
|
"down": "core:move-selection-down",
|
||||||
|
"left": "core:move-selection-left",
|
||||||
|
"shift-up": "core:step-selection-up",
|
||||||
|
"shift-right": "core:step-selection-right",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
501
editor/js/main.js
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
function appendNodeConfig(nodeConfig) {
|
||||||
|
var m = /<!-- --- \[red-module:(\S+)\] --- -->/.exec(nodeConfig.trim());
|
||||||
|
var moduleId;
|
||||||
|
if (m) {
|
||||||
|
moduleId = m[1];
|
||||||
|
} else {
|
||||||
|
moduleId = "unknown";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$("body").append(nodeConfig);
|
||||||
|
} catch(err) {
|
||||||
|
RED.notify(RED._("notification.errors.failedToAppendNode",{module:moduleId, error:err.toString()}),{
|
||||||
|
type: "error",
|
||||||
|
timeout: 10000
|
||||||
|
});
|
||||||
|
console.log("["+moduleId+"] "+err.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadNodeList() {
|
||||||
|
$.ajax({
|
||||||
|
headers: {
|
||||||
|
"Accept":"application/json"
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
url: 'nodes',
|
||||||
|
success: function(data) {
|
||||||
|
RED.nodes.setNodeList(data);
|
||||||
|
RED.i18n.loadNodeCatalogs(function() {
|
||||||
|
loadIconList(loadNodes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadIconList(done) {
|
||||||
|
$.ajax({
|
||||||
|
headers: {
|
||||||
|
"Accept":"application/json"
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
url: 'icons',
|
||||||
|
success: function(data) {
|
||||||
|
RED.nodes.setIconSets(data);
|
||||||
|
if (done) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadNodes() {
|
||||||
|
$.ajax({
|
||||||
|
headers: {
|
||||||
|
"Accept":"text/html"
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
url: 'nodes',
|
||||||
|
success: function(data) {
|
||||||
|
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
|
||||||
|
configs.forEach(function(data) {
|
||||||
|
appendNodeConfig(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("body").i18n();
|
||||||
|
$("#palette > .palette-spinner").hide();
|
||||||
|
$(".palette-scroll").removeClass("hide");
|
||||||
|
$("#palette-search").removeClass("hide");
|
||||||
|
loadFlows(function() {
|
||||||
|
if (RED.settings.theme("projects.enabled",false)) {
|
||||||
|
RED.projects.refresh(function(activeProject) {
|
||||||
|
RED.sidebar.info.refresh()
|
||||||
|
if (!activeProject) {
|
||||||
|
// Projects enabled but no active project
|
||||||
|
RED.menu.setDisabled('menu-item-projects-open',true);
|
||||||
|
RED.menu.setDisabled('menu-item-projects-settings',true);
|
||||||
|
if (activeProject === false) {
|
||||||
|
// User previously decline the migration to projects.
|
||||||
|
} else { // null/undefined
|
||||||
|
RED.projects.showStartup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completeLoad();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Projects disabled by the user
|
||||||
|
RED.sidebar.info.refresh()
|
||||||
|
completeLoad();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFlows(done) {
|
||||||
|
$.ajax({
|
||||||
|
headers: {
|
||||||
|
"Accept":"application/json",
|
||||||
|
},
|
||||||
|
cache: false,
|
||||||
|
url: 'flows',
|
||||||
|
success: function(nodes) {
|
||||||
|
if (nodes) {
|
||||||
|
var currentHash = window.location.hash;
|
||||||
|
RED.nodes.version(nodes.rev);
|
||||||
|
RED.nodes.import(nodes.flows);
|
||||||
|
RED.nodes.dirty(false);
|
||||||
|
RED.view.redraw(true);
|
||||||
|
if (/^#flow\/.+$/.test(currentHash)) {
|
||||||
|
RED.workspaces.show(currentHash.substring(6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeLoad() {
|
||||||
|
var persistentNotifications = {};
|
||||||
|
RED.comms.subscribe("notification/#",function(topic,msg) {
|
||||||
|
var parts = topic.split("/");
|
||||||
|
var notificationId = parts[1];
|
||||||
|
if (notificationId === "runtime-deploy") {
|
||||||
|
// handled in ui/deploy.js
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (notificationId === "node") {
|
||||||
|
// handled below
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (notificationId === "project-update") {
|
||||||
|
RED.nodes.clear();
|
||||||
|
RED.history.clear();
|
||||||
|
RED.view.redraw(true);
|
||||||
|
RED.projects.refresh(function() {
|
||||||
|
loadFlows(function() {
|
||||||
|
var project = RED.projects.getActiveProject();
|
||||||
|
var message = {
|
||||||
|
"change-branch": RED._("notification.project.change-branch", {project: project.git.branches.local}),
|
||||||
|
"merge-abort": RED._("notification.project.merge-abort"),
|
||||||
|
"loaded": RED._("notification.project.loaded", {project: msg.project}),
|
||||||
|
"updated": RED._("notification.project.updated", {project: msg.project}),
|
||||||
|
"pull": RED._("notification.project.pull", {project: msg.project}),
|
||||||
|
"revert": RED._("notification.project.revert", {project: msg.project}),
|
||||||
|
"merge-complete": RED._("notification.project.merge-complete")
|
||||||
|
}[msg.action];
|
||||||
|
RED.notify("<p>"+message+"</p>");
|
||||||
|
RED.sidebar.info.refresh()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.text) {
|
||||||
|
msg.default = msg.text;
|
||||||
|
var text = RED._(msg.text,msg);
|
||||||
|
var options = {
|
||||||
|
type: msg.type,
|
||||||
|
fixed: msg.timeout === undefined,
|
||||||
|
timeout: msg.timeout,
|
||||||
|
id: notificationId
|
||||||
|
}
|
||||||
|
if (notificationId === "runtime-state") {
|
||||||
|
if (msg.error === "missing-types") {
|
||||||
|
text+="<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||||
|
if (!!RED.projects.getActiveProject()) {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.manage-project-dep"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
RED.projects.settings.show('deps');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
// } else if (RED.settings.theme('palette.editable') !== false) {
|
||||||
|
} else {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("common.label.close"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (msg.error === "credentials_load_failed") {
|
||||||
|
if (RED.settings.theme("projects.enabled",false)) {
|
||||||
|
// projects enabled
|
||||||
|
if (RED.user.hasPermission("projects.write")) {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.setup-cred"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
RED.projects.showCredentialsPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("common.label.close"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (msg.error === "missing_flow_file") {
|
||||||
|
if (RED.user.hasPermission("projects.write")) {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.setup-project"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
RED.projects.showFilesPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (msg.error === "missing_package_file") {
|
||||||
|
if (RED.user.hasPermission("projects.write")) {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.create-default-package"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
RED.projects.createDefaultPackageFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (msg.error === "project_empty") {
|
||||||
|
if (RED.user.hasPermission("projects.write")) {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.no-thanks"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.create-default-project"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
RED.projects.createDefaultFileSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (msg.error === "git_merge_conflict") {
|
||||||
|
RED.nodes.clear();
|
||||||
|
RED.sidebar.versionControl.refresh(true);
|
||||||
|
if (RED.user.hasPermission("projects.write")) {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: RED._("notification.label.show-merge-conflicts"),
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].hideNotification();
|
||||||
|
RED.sidebar.versionControl.showLocalChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!persistentNotifications.hasOwnProperty(notificationId)) {
|
||||||
|
persistentNotifications[notificationId] = RED.notify(text,options);
|
||||||
|
} else {
|
||||||
|
persistentNotifications[notificationId].update(text,options);
|
||||||
|
}
|
||||||
|
} else if (persistentNotifications.hasOwnProperty(notificationId)) {
|
||||||
|
persistentNotifications[notificationId].close();
|
||||||
|
delete persistentNotifications[notificationId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.comms.subscribe("status/#",function(topic,msg) {
|
||||||
|
var parts = topic.split("/");
|
||||||
|
var node = RED.nodes.node(parts[1]);
|
||||||
|
if (node) {
|
||||||
|
if (msg.hasOwnProperty("text")) {
|
||||||
|
if (msg.text[0] !== ".") {
|
||||||
|
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.status = msg;
|
||||||
|
node.dirty = true;
|
||||||
|
RED.view.redraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.comms.subscribe("notification/node/#",function(topic,msg) {
|
||||||
|
var i,m;
|
||||||
|
var typeList;
|
||||||
|
var info;
|
||||||
|
if (topic == "notification/node/added") {
|
||||||
|
var addedTypes = [];
|
||||||
|
msg.forEach(function(m) {
|
||||||
|
var id = m.id;
|
||||||
|
RED.nodes.addNodeSet(m);
|
||||||
|
addedTypes = addedTypes.concat(m.types);
|
||||||
|
RED.i18n.loadCatalog(id, function() {
|
||||||
|
$.get('nodes/'+id, function(data) {
|
||||||
|
appendNodeConfig(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (addedTypes.length) {
|
||||||
|
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
|
||||||
|
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||||
|
}
|
||||||
|
loadIconList();
|
||||||
|
} else if (topic == "notification/node/removed") {
|
||||||
|
for (i=0;i<msg.length;i++) {
|
||||||
|
m = msg[i];
|
||||||
|
info = RED.nodes.removeNodeSet(m.id);
|
||||||
|
if (info.added) {
|
||||||
|
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
|
||||||
|
RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadIconList();
|
||||||
|
} else if (topic == "notification/node/enabled") {
|
||||||
|
if (msg.types) {
|
||||||
|
info = RED.nodes.getNodeSet(msg.id);
|
||||||
|
if (info.added) {
|
||||||
|
RED.nodes.enableNodeSet(msg.id);
|
||||||
|
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||||
|
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||||
|
} else {
|
||||||
|
$.get('nodes/'+msg.id, function(data) {
|
||||||
|
appendNodeConfig(data);
|
||||||
|
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||||
|
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (topic == "notification/node/disabled") {
|
||||||
|
if (msg.types) {
|
||||||
|
RED.nodes.disableNodeSet(msg.id);
|
||||||
|
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||||
|
RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success");
|
||||||
|
}
|
||||||
|
} else if (topic == "node/upgraded") {
|
||||||
|
RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success");
|
||||||
|
RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version);
|
||||||
|
}
|
||||||
|
// Refresh flow library to ensure any examples are updated
|
||||||
|
RED.library.loadFlowLibrary();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAbout() {
|
||||||
|
$.get('red/about', function(data) {
|
||||||
|
var aboutHeader = '<div style="text-align:center;">'+
|
||||||
|
'<img width="50px" src="red/images/node-red-icon.svg" />'+
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
RED.sidebar.info.set(aboutHeader+marked(data));
|
||||||
|
RED.sidebar.info.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadEditor() {
|
||||||
|
var menuOptions = [];
|
||||||
|
if (RED.settings.theme("projects.enabled",false)) {
|
||||||
|
menuOptions.push({id:"menu-item-projects-menu",label:RED._("menu.label.projects"),options:[
|
||||||
|
{id:"menu-item-projects-new",label:RED._("menu.label.projects-new"),disabled:false,onselect:"core:new-project"},
|
||||||
|
{id:"menu-item-projects-open",label:RED._("menu.label.projects-open"),disabled:false,onselect:"core:open-project"},
|
||||||
|
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
|
||||||
|
]});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
|
||||||
|
// {id:"menu-item-view-show-grid",setting:"view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"},
|
||||||
|
// {id:"menu-item-view-snap-grid",setting:"view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"},
|
||||||
|
// {id:"menu-item-status",setting:"node-show-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true},
|
||||||
|
//null,
|
||||||
|
// {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[
|
||||||
|
// {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}},
|
||||||
|
// {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}},
|
||||||
|
// {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}},
|
||||||
|
// {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}}
|
||||||
|
// ]},
|
||||||
|
// null,
|
||||||
|
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true},
|
||||||
|
null
|
||||||
|
]});
|
||||||
|
menuOptions.push(null);
|
||||||
|
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
|
||||||
|
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"},
|
||||||
|
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
|
||||||
|
]});
|
||||||
|
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[
|
||||||
|
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"},
|
||||||
|
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"}
|
||||||
|
]});
|
||||||
|
menuOptions.push(null);
|
||||||
|
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"});
|
||||||
|
menuOptions.push(null);
|
||||||
|
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"});
|
||||||
|
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
|
||||||
|
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"},
|
||||||
|
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:"core:edit-flow"},
|
||||||
|
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"}
|
||||||
|
]});
|
||||||
|
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
|
||||||
|
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"},
|
||||||
|
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"},
|
||||||
|
]});
|
||||||
|
menuOptions.push(null);
|
||||||
|
if (RED.settings.theme('palette.editable') !== false) {
|
||||||
|
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"});
|
||||||
|
menuOptions.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.settings"),onselect:"core:show-user-settings"});
|
||||||
|
menuOptions.push(null);
|
||||||
|
|
||||||
|
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"});
|
||||||
|
menuOptions.push({id:"menu-item-help",
|
||||||
|
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
|
||||||
|
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||||
|
});
|
||||||
|
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
|
||||||
|
|
||||||
|
|
||||||
|
RED.view.init();
|
||||||
|
RED.userSettings.init();
|
||||||
|
RED.user.init();
|
||||||
|
RED.library.init();
|
||||||
|
RED.keyboard.init();
|
||||||
|
RED.palette.init();
|
||||||
|
if (RED.settings.theme('palette.editable') !== false) {
|
||||||
|
RED.palette.editor.init();
|
||||||
|
} else {
|
||||||
|
console.log("Palette editor disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.sidebar.init();
|
||||||
|
|
||||||
|
if (RED.settings.theme("projects.enabled",false)) {
|
||||||
|
RED.projects.init();
|
||||||
|
} else {
|
||||||
|
console.log("Projects disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.subflow.init();
|
||||||
|
RED.workspaces.init();
|
||||||
|
RED.clipboard.init();
|
||||||
|
RED.search.init();
|
||||||
|
RED.editor.init();
|
||||||
|
RED.diff.init();
|
||||||
|
|
||||||
|
RED.menu.init({id:"btn-sidemenu",options: menuOptions});
|
||||||
|
|
||||||
|
RED.deploy.init(RED.settings.theme("deployButton",null));
|
||||||
|
RED.notifications.init();
|
||||||
|
|
||||||
|
RED.actions.add("core:show-about", showAbout);
|
||||||
|
RED.nodes.init();
|
||||||
|
RED.comms.connect();
|
||||||
|
|
||||||
|
$("#main-container").show();
|
||||||
|
$(".header-toolbar").show();
|
||||||
|
|
||||||
|
loadNodeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
|
||||||
|
document.title = document.title+" : "+window.location.hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
ace.require("ace/ext/language_tools");
|
||||||
|
|
||||||
|
RED.i18n.init(function() {
|
||||||
|
RED.settings.init(loadEditor);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})();
|