mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
8 Commits
0.18.7
...
runnable-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c256e27a83 | ||
|
|
3f41036919 | ||
|
|
95753ce5cd | ||
|
|
1906818c87 | ||
|
|
02765f8aad | ||
|
|
89f1dedf20 | ||
|
|
7a8906535e | ||
|
|
499d22daca |
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@@ -8,9 +8,7 @@ If your issue is:
|
||||
- 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`.
|
||||
please use the [mailing list](https://groups.google.com/forum/#!forum/node-red), [slack team](https://nodered.org/slack) or ask 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.
|
||||
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -16,7 +16,7 @@ Put an `x` in the boxes that apply
|
||||
<!--
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it **may well get rejected** if it hasn't been discussed on
|
||||
the [forum](https://discourse.nodered.org) or
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) or
|
||||
[slack team](https://nodered.org/slack) first.
|
||||
|
||||
-->
|
||||
|
||||
28
.travis.yml
28
.travis.yml
@@ -1,12 +1,20 @@
|
||||
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"
|
||||
env:
|
||||
- CXX="g++-4.8"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- gcc-4.8
|
||||
node_js:
|
||||
- "8"
|
||||
- "6"
|
||||
- "4"
|
||||
script:
|
||||
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
|
||||
before_script:
|
||||
- npm install -g istanbul
|
||||
- npm install coveralls
|
||||
|
||||
80
CHANGELOG.md
80
CHANGELOG.md
@@ -1,83 +1,3 @@
|
||||
#### 0.18.7: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Relax twitter node version ready for major version bump
|
||||
- Pass Date into the Function node sandbox to fix instanceof tests
|
||||
- let TCP in node report remote ip and port when in single packet mode
|
||||
- typo fix in node help (#1735)
|
||||
|
||||
Other Fixes
|
||||
- Tidy up default grunt task and fixup test break due to reorder Fixes #1738
|
||||
- Bump jsonata version
|
||||
|
||||
#### 0.18.6: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Handle a node having wires in the editor on ports it no longer has Fixes #1724
|
||||
- Add missing ACE snippet files
|
||||
- Fix wireClippedNodes is not defined Fixes #1726
|
||||
- Split node html to isolate bad nodes when loading
|
||||
- Avoid unnecessary use of .html() where .text() will do
|
||||
|
||||
- Add editorTheme.projects.enabled to default settings.js"
|
||||
|
||||
#### 0.18.5: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Add clone project to welcome screen
|
||||
- Handle cloning a project without package.json
|
||||
- Keep remote branch state in sync between editor and runtime
|
||||
|
||||
New Features
|
||||
|
||||
- Add type checks to switch node options (#1714)
|
||||
- add output property select to HTML parse node (#1701)
|
||||
- Add Prevent Following Redirect to HTTP Request node (#615) (#1684)
|
||||
- Add debug and trace functions to function node (#1654)
|
||||
- Enable user defined icon for subflow
|
||||
- Add MQTT disconnect message and rework broker node UI (#1719)
|
||||
- Japanese message catalogue updates (#1723)
|
||||
- Show node load errors in the Palette Manager view
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Highlight subflow node when log msg comes from inside Fixes #1698
|
||||
- Ensure node wires array is not longer than outputs value Fixes #1678
|
||||
- Allow importing an unknown config node to be undone Fixes #1681
|
||||
- Ensure keyboard shortcuts get saved in runtime settings Fixes #1696
|
||||
- Don't mark a subflow changed when actually modified nothing (#1665)
|
||||
|
||||
Node Fixes
|
||||
|
||||
- bind to correct port when doing udp broadcast/multicast (#1686)
|
||||
- Provide full error stack in Function node log message (#1700)
|
||||
- Fix http request doc type Fixes #1690
|
||||
- Make debug slightly larger to pass WCAG AA rating
|
||||
- Make core nodes labels more consistent, to close #1673
|
||||
- Allow template node to be updated more than once Fixes #1671
|
||||
- Fix the problem that output labels of switch node sometimes disappear (#1664)
|
||||
- Chinese translations for core nodes (#1607)
|
||||
|
||||
Runtime Fixes
|
||||
|
||||
- Handle and display for invalid flow credentials when project is disabled #1689 (#1694)
|
||||
- node-red-pi: fix behavior with old bash version (#1713)
|
||||
- Fix ENOENT error on first start when no user dir (#1711)
|
||||
- Handle null error object in Flow.handleError Fixes #1721
|
||||
- update settings comments to describe how to setup for ipv6 (#1675)
|
||||
- Remove credential props after diffing flow to prevent future false positives Fixes #1359
|
||||
- Log error if settings unavailable when saving user settings Fixes #1645
|
||||
- Keep backup of .config.json
|
||||
- Add warning if using \_credentialSecret from .config.json
|
||||
- Filter req.user in /settings to prevent potentially leaking info
|
||||
|
||||
#### 0.18.4: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
@@ -30,13 +30,13 @@ At a minimum, please include:
|
||||
|
||||
## Feature requests
|
||||
|
||||
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
|
||||
## Pull-Requests
|
||||
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it may well get rejected if you haven't discussed it on
|
||||
the [forum](https://discourse.nodered.org) first.
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
|
||||
|
||||
All contributors need to sign the JS Foundation's Contributor License Agreement.
|
||||
It is an online process and quick to do. You can read the details of the agreement
|
||||
|
||||
@@ -55,7 +55,7 @@ module.exports = function(grunt) {
|
||||
reportFormats: ['lcov','html'],
|
||||
print: 'both'
|
||||
},
|
||||
all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
@@ -474,7 +474,7 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','jshint:editor','mocha_istanbul:all']);
|
||||
['build','test-core','test-editor','test-nodes']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
|
||||
@@ -22,7 +22,8 @@ started.
|
||||
|
||||
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
|
||||
[mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
|
||||
## Developers
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ done
|
||||
# Find the real location of this script
|
||||
CURRENT_PATH=`pwd`
|
||||
SCRIPT_PATH="${BASH_SOURCE[0]}";
|
||||
while [ -h "${SCRIPT_PATH}" ]; do
|
||||
while([ -h "${SCRIPT_PATH}" ]); do
|
||||
cd "`dirname "${SCRIPT_PATH}"`"
|
||||
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
|
||||
done
|
||||
|
||||
@@ -15,25 +15,6 @@
|
||||
**/
|
||||
(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: {
|
||||
@@ -74,11 +55,7 @@
|
||||
cache: false,
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
|
||||
configs.forEach(function(data) {
|
||||
appendNodeConfig(data);
|
||||
});
|
||||
|
||||
$("body").append(data);
|
||||
$("body").i18n();
|
||||
$("#palette > .palette-spinner").hide();
|
||||
$(".palette-scroll").removeClass("hide");
|
||||
@@ -202,25 +179,13 @@
|
||||
]
|
||||
}
|
||||
} 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: "Setup credentials",
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showCredentialsPrompt();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
} else {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Close",
|
||||
text: "Setup credentials",
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showCredentialsPrompt();
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -237,18 +202,6 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
} else if (msg.error === "missing_package_file") {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Create default package file",
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.createDefaultPackageFile();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
} else if (msg.error === "project_empty") {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
@@ -319,7 +272,7 @@
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadCatalog(id, function() {
|
||||
$.get('nodes/'+id, function(data) {
|
||||
appendNodeConfig(data);
|
||||
$("body").append(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -347,7 +300,7 @@
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
$.get('nodes/'+msg.id, function(data) {
|
||||
appendNodeConfig(data);
|
||||
$("body").append(data);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
});
|
||||
|
||||
@@ -491,9 +491,7 @@ RED.nodes = (function() {
|
||||
for (var j=0;j<wires.length;j++) {
|
||||
var w = wires[j];
|
||||
if (w.target.type != "subflow") {
|
||||
if (w.sourcePort < node.wires.length) {
|
||||
node.wires[w.sourcePort].push(w.target.id);
|
||||
}
|
||||
node.wires[w.sourcePort].push(w.target.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,7 +753,7 @@ RED.nodes = (function() {
|
||||
if (!isInitialLoad && unknownTypes.length > 0) {
|
||||
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
||||
var type = "type"+(unknownTypes.length > 1?"s":"");
|
||||
RED.notify("<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,"error",false,10000);
|
||||
RED.notify("<strong>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</strong>"+typeList,"error",false,10000);
|
||||
}
|
||||
|
||||
var activeWorkspace = RED.workspaces.active();
|
||||
@@ -1014,13 +1012,6 @@ RED.nodes = (function() {
|
||||
set: registry.getNodeSet("node-red/unknown")
|
||||
};
|
||||
node.users = [];
|
||||
// This is a config node, so delete the default
|
||||
// non-config node properties
|
||||
delete node.x;
|
||||
delete node.y;
|
||||
delete node.wires;
|
||||
delete node.inputLabels;
|
||||
delete node.outputLabels;
|
||||
}
|
||||
var orig = {};
|
||||
for (var p in n) {
|
||||
@@ -1033,31 +1024,10 @@ RED.nodes = (function() {
|
||||
node.type = "unknown";
|
||||
}
|
||||
if (node._def.category != "config") {
|
||||
if (n.hasOwnProperty('inputs')) {
|
||||
node.inputs = n.inputs;
|
||||
node._config.inputs = JSON.stringify(n.inputs);
|
||||
} else {
|
||||
node.inputs = node._def.inputs;
|
||||
}
|
||||
if (n.hasOwnProperty('outputs')) {
|
||||
node.outputs = n.outputs;
|
||||
node._config.outputs = JSON.stringify(n.outputs);
|
||||
} else {
|
||||
node.outputs = node._def.outputs;
|
||||
}
|
||||
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
|
||||
if (!node._def.defaults.hasOwnProperty("outputs") || !isNaN(parseInt(n.outputs))) {
|
||||
// If 'wires' is longer than outputs, clip wires
|
||||
console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
|
||||
node.wires = node.wires.slice(0,node.outputs);
|
||||
} else {
|
||||
// The node declares outputs in its defaults, but has not got a valid value
|
||||
// Defer to the length of the wires array
|
||||
node.outputs = node.wires.length;
|
||||
}
|
||||
}
|
||||
node.inputs = n.inputs||node._def.inputs;
|
||||
node.outputs = n.outputs||node._def.outputs;
|
||||
for (d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
node[d] = n[d];
|
||||
node._config[d] = JSON.stringify(n[d]);
|
||||
}
|
||||
@@ -1077,9 +1047,7 @@ RED.nodes = (function() {
|
||||
addNode(node);
|
||||
RED.editor.validateNode(node);
|
||||
node_map[n.id] = node;
|
||||
// If an 'unknown' config node, it will not have been caught by the
|
||||
// proper config node handling, so needs adding to new_nodes here
|
||||
if (node.type === "unknown" || node._def.category !== "config") {
|
||||
if (node._def.category != "config") {
|
||||
new_nodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ RED.diff = (function() {
|
||||
var tabForLabel = (object.newTab || object.tab).n;
|
||||
var titleSpan = $('<span>',{class:"node-diff-tab-title-meta"}).appendTo(originalCell);
|
||||
if (tabForLabel.type === 'tab') {
|
||||
titleSpan.text(tabForLabel.label||tabForLabel.id);
|
||||
titleSpan.html(tabForLabel.label||tabForLabel.id);
|
||||
} else if (tab.type === 'subflow') {
|
||||
titleSpan.text((tabForLabel.name||tabForLabel.id));
|
||||
titleSpan.html((tabForLabel.name||tabForLabel.id));
|
||||
} else {
|
||||
titleSpan.text(RED._("diff.globalNodes"));
|
||||
titleSpan.html(RED._("diff.globalNodes"));
|
||||
}
|
||||
var flowStats = {
|
||||
local: {
|
||||
@@ -131,7 +131,7 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv);
|
||||
$('<span>').text(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
|
||||
$('<span>').html(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
|
||||
|
||||
row.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -206,7 +206,7 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
var localStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(localCell);
|
||||
$('<span class="node-diff-status"></span>').text(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
|
||||
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
|
||||
|
||||
if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.deletedCount > 0) {
|
||||
$('<span class="node-diff-status"> [ </span>').appendTo(localStats);
|
||||
@@ -245,7 +245,7 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
var remoteStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(remoteCell);
|
||||
$('<span class="node-diff-status"></span>').text(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
|
||||
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
|
||||
if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.deletedCount > 0) {
|
||||
$('<span class="node-diff-status"> [ </span>').appendTo(remoteStats);
|
||||
if (flowStats.conflicts > 0) {
|
||||
@@ -464,7 +464,7 @@ RED.diff = (function() {
|
||||
wires.forEach(function(p,i) {
|
||||
var port = $("<li>").appendTo(list);
|
||||
if (p && p.length > 0) {
|
||||
$("<span>").text(i+1).appendTo(port);
|
||||
$("<span>").html(i+1).appendTo(port);
|
||||
var links = $("<ul>").appendTo(port);
|
||||
p.forEach(function(d) {
|
||||
c++;
|
||||
@@ -474,15 +474,15 @@ RED.diff = (function() {
|
||||
var def = RED.nodes.getType(node.type)||{};
|
||||
createNode(node,def).appendTo(entry);
|
||||
} else {
|
||||
entry.text(d);
|
||||
entry.html(d);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
port.text('none');
|
||||
port.html('none');
|
||||
}
|
||||
})
|
||||
if (c === 0) {
|
||||
result.text("none");
|
||||
result.html("none");
|
||||
} else {
|
||||
list.appendTo(result);
|
||||
}
|
||||
@@ -507,7 +507,7 @@ RED.diff = (function() {
|
||||
createNodeIcon(node,def).appendTo(nodeTitleDiv);
|
||||
var contentDiv = $('<div>',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
|
||||
var nodeLabel = node.label || node.name || node.id;
|
||||
$('<span>',{class:"node-diff-node-label"}).text(nodeLabel).appendTo(contentDiv);
|
||||
$('<span>',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv);
|
||||
return nodeTitleDiv;
|
||||
}
|
||||
function createNodeDiffRow(node,stats,CurrentDiff) {
|
||||
@@ -739,7 +739,7 @@ RED.diff = (function() {
|
||||
var status;
|
||||
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).text("id").appendTo(row);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).html("id").appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
localCell.addClass("node-diff-node-unchanged");
|
||||
@@ -782,7 +782,7 @@ RED.diff = (function() {
|
||||
conflict = true;
|
||||
}
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).text("position").appendTo(row);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).html("position").appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
|
||||
@@ -850,7 +850,7 @@ RED.diff = (function() {
|
||||
conflict = true;
|
||||
}
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).text("wires").appendTo(row);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).html("wires").appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
if (!conflict) {
|
||||
@@ -917,7 +917,7 @@ RED.diff = (function() {
|
||||
}
|
||||
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).text(d).appendTo(row);
|
||||
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).html(d).appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
if (!conflict) {
|
||||
|
||||
@@ -660,7 +660,7 @@ RED.editor = (function() {
|
||||
return A.i-B.i;
|
||||
})
|
||||
rows.forEach(function(r,i) {
|
||||
r.r.find("label").text((i+1)+".");
|
||||
r.r.find("label").html((i+1)+".");
|
||||
r.r.appendTo(outputsDiv);
|
||||
})
|
||||
if (rows.length === 0) {
|
||||
@@ -696,12 +696,12 @@ RED.editor = (function() {
|
||||
function buildLabelRow(type, index, value, placeHolder) {
|
||||
var result = $('<div>',{class:"node-label-form-row"});
|
||||
if (type === undefined) {
|
||||
$('<span>').text(RED._("editor.noDefaultLabel")).appendTo(result);
|
||||
$('<span>').html(RED._("editor.noDefaultLabel")).appendTo(result);
|
||||
result.addClass("node-label-form-none");
|
||||
} else {
|
||||
result.addClass("");
|
||||
var id = "node-label-form-"+type+"-"+index;
|
||||
$('<label>',{for:id}).text((index+1)+".").appendTo(result);
|
||||
$('<label>',{for:id}).html((index+1)+".").appendTo(result);
|
||||
var input = $('<input>',{type:"text",id:id, placeholder: placeHolder}).val(value).appendTo(result);
|
||||
var clear = $('<button class="editor-button editor-button-small"><i class="fa fa-times"></i></button>').appendTo(result);
|
||||
clear.click(function(evt) {
|
||||
@@ -1366,7 +1366,7 @@ RED.editor = (function() {
|
||||
|
||||
dialogForm.i18n();
|
||||
if (node_def.hasUsers !== false) {
|
||||
$("#node-config-dialog-user-count").find("span").text(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show();
|
||||
$("#node-config-dialog-user-count").find("span").html(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show();
|
||||
}
|
||||
done();
|
||||
});
|
||||
@@ -1796,7 +1796,7 @@ RED.editor = (function() {
|
||||
userCount++;
|
||||
}
|
||||
});
|
||||
$("#subflow-dialog-user-count").text(RED._("subflow.subflowInstances", {count:userCount})).show();
|
||||
$("#subflow-dialog-user-count").html(RED._("subflow.subflowInstances", {count:userCount})).show();
|
||||
|
||||
buildLabelForm(portLabels.content,subflow);
|
||||
validateIcon(subflow);
|
||||
@@ -1853,7 +1853,7 @@ RED.editor = (function() {
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
$("#node-input-expression-help").text("");
|
||||
$("#node-input-expression-help").html("");
|
||||
onComplete(expressionEditor.getValue());
|
||||
RED.tray.close();
|
||||
}
|
||||
|
||||
@@ -389,7 +389,6 @@ RED.keyboard = (function() {
|
||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||
var userKeymap = currentEditorSettings.keymap || {};
|
||||
userKeymap[object.id] = null;
|
||||
currentEditorSettings.keymap = userKeymap;
|
||||
RED.settings.set('editor',currentEditorSettings);
|
||||
|
||||
var obj = {
|
||||
@@ -443,7 +442,6 @@ RED.keyboard = (function() {
|
||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||
var userKeymap = currentEditorSettings.keymap || {};
|
||||
userKeymap[object.id] = RED.keyboard.getShortcut(object.id);
|
||||
currentEditorSettings.keymap = userKeymap;
|
||||
RED.settings.set('editor',currentEditorSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ RED.notifications = (function() {
|
||||
if (options.buttons) {
|
||||
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(n)
|
||||
options.buttons.forEach(function(buttonDef) {
|
||||
var b = $('<button>').text(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
|
||||
var b = $('<button>').html(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
|
||||
if (buttonDef.id) {
|
||||
b.attr('id',buttonDef.id);
|
||||
}
|
||||
@@ -171,7 +171,7 @@ RED.notifications = (function() {
|
||||
if (options.buttons) {
|
||||
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(nn)
|
||||
options.buttons.forEach(function(buttonDef) {
|
||||
var b = $('<button>').text(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
|
||||
var b = $('<button>').html(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
|
||||
if (buttonDef.id) {
|
||||
b.attr('id',buttonDef.id);
|
||||
}
|
||||
|
||||
@@ -208,8 +208,6 @@ RED.palette.editor = (function() {
|
||||
if (nodeEntry) {
|
||||
var activeTypeCount = 0;
|
||||
var typeCount = 0;
|
||||
var errorCount = 0;
|
||||
nodeEntry.errorList.empty();
|
||||
nodeEntries[module].totalUseCount = 0;
|
||||
nodeEntries[module].setUseCount = {};
|
||||
|
||||
@@ -218,10 +216,7 @@ RED.palette.editor = (function() {
|
||||
var inUseCount = 0;
|
||||
var set = moduleInfo.sets[setName];
|
||||
var setElements = nodeEntry.sets[setName];
|
||||
if (set.err) {
|
||||
errorCount++;
|
||||
$("<li>").text(set.err).appendTo(nodeEntry.errorList);
|
||||
}
|
||||
|
||||
if (set.enabled) {
|
||||
activeTypeCount += set.types.length;
|
||||
}
|
||||
@@ -247,31 +242,24 @@ RED.palette.editor = (function() {
|
||||
nodeEntries[module].totalUseCount += inUseCount;
|
||||
|
||||
if (inUseCount > 0) {
|
||||
setElements.enableButton.text(RED._('palette.editor.inuse'));
|
||||
setElements.enableButton.html(RED._('palette.editor.inuse'));
|
||||
setElements.enableButton.addClass('disabled');
|
||||
} else {
|
||||
setElements.enableButton.removeClass('disabled');
|
||||
if (set.enabled) {
|
||||
setElements.enableButton.text(RED._('palette.editor.disable'));
|
||||
setElements.enableButton.html(RED._('palette.editor.disable'));
|
||||
} else {
|
||||
setElements.enableButton.text(RED._('palette.editor.enable'));
|
||||
setElements.enableButton.html(RED._('palette.editor.enable'));
|
||||
}
|
||||
}
|
||||
setElements.setRow.toggleClass("palette-module-set-disabled",!set.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount === 0) {
|
||||
nodeEntry.errorRow.hide()
|
||||
} else {
|
||||
nodeEntry.errorRow.show();
|
||||
}
|
||||
|
||||
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
|
||||
nodeEntry.setCount.text(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||
nodeEntry.setCount.html(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||
|
||||
if (nodeEntries[module].totalUseCount > 0) {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.inuse'));
|
||||
nodeEntry.enableButton.html(RED._('palette.editor.inuse'));
|
||||
nodeEntry.enableButton.addClass('disabled');
|
||||
nodeEntry.removeButton.hide();
|
||||
} else {
|
||||
@@ -280,20 +268,20 @@ RED.palette.editor = (function() {
|
||||
nodeEntry.removeButton.css('display', 'inline-block');
|
||||
}
|
||||
if (activeTypeCount === 0) {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
|
||||
nodeEntry.enableButton.html(RED._('palette.editor.enableall'));
|
||||
} else {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.disableall'));
|
||||
nodeEntry.enableButton.html(RED._('palette.editor.disableall'));
|
||||
}
|
||||
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
||||
}
|
||||
}
|
||||
if (moduleInfo.pending_version) {
|
||||
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
|
||||
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').show();
|
||||
nodeEntry.updateButton.html(RED._('palette.editor.updated')).addClass('disabled').show();
|
||||
} else if (loadedIndex.hasOwnProperty(module)) {
|
||||
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) === 1) {
|
||||
nodeEntry.updateButton.show();
|
||||
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
||||
nodeEntry.updateButton.html(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
||||
} else {
|
||||
nodeEntry.updateButton.hide();
|
||||
}
|
||||
@@ -367,7 +355,7 @@ RED.palette.editor = (function() {
|
||||
loadedIndex = {};
|
||||
packageList.editableList('empty');
|
||||
|
||||
$(".palette-module-shade-status").text(RED._('palette.editor.loading'));
|
||||
$(".palette-module-shade-status").html(RED._('palette.editor.loading'));
|
||||
var catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json'];
|
||||
catalogueLoadStatus = [];
|
||||
catalogueLoadErrors = false;
|
||||
@@ -473,7 +461,7 @@ RED.palette.editor = (function() {
|
||||
if (filteredList[i].info.id === ns.module) {
|
||||
var installButton = filteredList[i].elements.installButton;
|
||||
installButton.addClass('disabled');
|
||||
installButton.text(RED._('palette.editor.installed'));
|
||||
installButton.html(RED._('palette.editor.installed'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -489,7 +477,7 @@ RED.palette.editor = (function() {
|
||||
if (filteredList[i].info.id === ns.module) {
|
||||
var installButton = filteredList[i].elements.installButton;
|
||||
installButton.removeClass('disabled');
|
||||
installButton.text(RED._('palette.editor.install'));
|
||||
installButton.html(RED._('palette.editor.install'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -595,18 +583,15 @@ RED.palette.editor = (function() {
|
||||
if (entry) {
|
||||
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
|
||||
var titleRow = $('<div class="palette-module-meta palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
|
||||
$('<span>').text(entry.name).appendTo(titleRow);
|
||||
$('<span>').html(entry.name).appendTo(titleRow);
|
||||
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
|
||||
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
|
||||
|
||||
var errorRow = $('<div class="palette-module-meta palette-module-errors"><i class="fa fa-warning"></i></div>').hide().appendTo(headerRow);
|
||||
var errorList = $('<ul class="palette-module-error-list"></ul>').appendTo(errorRow);
|
||||
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
|
||||
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
|
||||
var setButton = $('<a href="#" class="editor-button editor-button-small palette-module-set-button"><i class="fa fa-angle-right palette-module-node-chevron"></i> </a>').appendTo(buttonRow);
|
||||
var setCount = $('<span>').appendTo(setButton);
|
||||
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
|
||||
|
||||
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.update')).appendTo(buttonGroup);
|
||||
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.update')).appendTo(buttonGroup);
|
||||
updateButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
|
||||
updateButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -617,7 +602,7 @@ RED.palette.editor = (function() {
|
||||
})
|
||||
|
||||
|
||||
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.remove')).appendTo(buttonGroup);
|
||||
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.remove')).appendTo(buttonGroup);
|
||||
removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
|
||||
removeButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -626,7 +611,7 @@ RED.palette.editor = (function() {
|
||||
if (!entry.local) {
|
||||
removeButton.hide();
|
||||
}
|
||||
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.disableall')).appendTo(buttonGroup);
|
||||
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.disableall')).appendTo(buttonGroup);
|
||||
|
||||
var contentRow = $('<div>',{class:"palette-module-content"}).appendTo(container);
|
||||
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
|
||||
@@ -635,8 +620,6 @@ RED.palette.editor = (function() {
|
||||
updateButton: updateButton,
|
||||
removeButton: removeButton,
|
||||
enableButton: enableButton,
|
||||
errorRow: errorRow,
|
||||
errorList: errorList,
|
||||
setCount: setCount,
|
||||
container: container,
|
||||
shade: shade,
|
||||
@@ -666,8 +649,9 @@ RED.palette.editor = (function() {
|
||||
set.types.forEach(function(t) {
|
||||
var typeDiv = $('<div>',{class:"palette-module-type"}).appendTo(setRow);
|
||||
typeSwatches[t] = $('<span>',{class:"palette-module-type-swatch"}).appendTo(typeDiv);
|
||||
$('<span>',{class:"palette-module-type-node"}).text(t).appendTo(typeDiv);
|
||||
$('<span>',{class:"palette-module-type-node"}).html(t).appendTo(typeDiv);
|
||||
})
|
||||
|
||||
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').appendTo(buttonGroup);
|
||||
enableButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -705,7 +689,7 @@ RED.palette.editor = (function() {
|
||||
})
|
||||
refreshNodeModule(entry.name);
|
||||
} else {
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -745,7 +729,7 @@ RED.palette.editor = (function() {
|
||||
});
|
||||
|
||||
|
||||
$('<span>').text(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
||||
$('<span>').html(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
||||
var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar);
|
||||
var sortAZ = $('<a href="#" class="sidebar-header-button-toggle selected" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup);
|
||||
var sortRecent = $('<a href="#" class="sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup);
|
||||
@@ -787,13 +771,13 @@ RED.palette.editor = (function() {
|
||||
scrollOnAdd: false,
|
||||
addItem: function(container,i,object) {
|
||||
if (object.count) {
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
|
||||
return
|
||||
}
|
||||
if (object.more) {
|
||||
container.addClass('palette-module-more');
|
||||
var moreRow = $('<div>',{class:"palette-module-header palette-module"}).appendTo(container);
|
||||
var moreLink = $('<a href="#"></a>').text(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
|
||||
var moreLink = $('<a href="#"></a>').html(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
|
||||
moreLink.click(function(e) {
|
||||
e.preventDefault();
|
||||
packageList.editableList('removeItem',object);
|
||||
@@ -810,17 +794,17 @@ RED.palette.editor = (function() {
|
||||
var entry = object.info;
|
||||
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
|
||||
var titleRow = $('<div class="palette-module-meta"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
|
||||
$('<span>',{class:"palette-module-name"}).text(entry.name||entry.id).appendTo(titleRow);
|
||||
$('<span>',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow);
|
||||
$('<a target="_blank" class="palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
|
||||
var descRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||
$('<div>',{class:"palette-module-description"}).text(entry.description).appendTo(descRow);
|
||||
$('<div>',{class:"palette-module-description"}).html(entry.description).appendTo(descRow);
|
||||
|
||||
var metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||
$('<span class="palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
|
||||
$('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
|
||||
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
|
||||
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
|
||||
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.install')).appendTo(buttonGroup);
|
||||
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup);
|
||||
installButton.click(function(e) {
|
||||
e.preventDefault();
|
||||
if (!$(this).hasClass('disabled')) {
|
||||
@@ -829,14 +813,14 @@ RED.palette.editor = (function() {
|
||||
})
|
||||
if (nodeEntries.hasOwnProperty(entry.id)) {
|
||||
installButton.addClass('disabled');
|
||||
installButton.text(RED._('palette.editor.installed'));
|
||||
installButton.html(RED._('palette.editor.installed'));
|
||||
}
|
||||
|
||||
object.elements = {
|
||||
installButton:installButton
|
||||
}
|
||||
} else {
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -352,6 +352,7 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
},{dependencies:dependencies});
|
||||
}
|
||||
|
||||
function editDependencies(activeProject,depsJSON,container,depsList) {
|
||||
var json = depsJSON||JSON.stringify(activeProject.dependencies||{},"",4);
|
||||
if (json === "{}") {
|
||||
@@ -380,6 +381,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
function createDependenciesPane(activeProject) {
|
||||
var pane = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>');
|
||||
var nrDepButton;
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>')
|
||||
.appendTo(pane)
|
||||
@@ -387,6 +389,16 @@ RED.projects.settings = (function() {
|
||||
evt.preventDefault();
|
||||
editDependencies(activeProject,null,pane,depsList)
|
||||
});
|
||||
|
||||
nrDepButton = $('<button class="editor-button editor-button-small" style="margin-top:10px;">add Node-RED core</button>')
|
||||
.appendTo(pane)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
activeProject.dependencies["node-red"] = "~"+RED.settings.version;
|
||||
updateProjectDependencies(activeProject,depsList);
|
||||
$(this).hide();
|
||||
});
|
||||
if (activeProject.dependencies.hasOwnProperty("node-red")) { nrDepButton.hide(); }
|
||||
}
|
||||
var depsList = $("<ol>",{style:"position: absolute;top: 60px;bottom: 20px;left: 20px;right: 20px;"}).appendTo(pane);
|
||||
depsList.editableList({
|
||||
@@ -444,9 +456,9 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
var icon = $('<i class="fa '+iconClass+'"></i>').appendTo(titleRow);
|
||||
entry.icon = icon;
|
||||
$('<span>').text(entry.id).appendTo(titleRow);
|
||||
$('<span>').html(entry.id).appendTo(titleRow);
|
||||
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
|
||||
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
|
||||
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
|
||||
metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||
var buttons = $('<div class="palette-module-button-group"></div>').appendTo(metaRow);
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
@@ -473,6 +485,7 @@ RED.projects.settings = (function() {
|
||||
evt.preventDefault();
|
||||
var deps = $.extend(true, {}, activeProject.dependencies);
|
||||
delete deps[entry.id];
|
||||
if (entry.id === "node-red") { nrDepButton.show(); }
|
||||
saveDependencies(depsList,row,deps,function(err) {
|
||||
if (!err) {
|
||||
row.fadeOut(200,function() {
|
||||
@@ -519,7 +532,6 @@ RED.projects.settings = (function() {
|
||||
|
||||
updateProjectDependencies(activeProject,depsList);
|
||||
return pane;
|
||||
|
||||
}
|
||||
|
||||
function showProjectFileListing(row,activeProject,current,filter,done) {
|
||||
@@ -1255,14 +1267,6 @@ RED.projects.settings = (function() {
|
||||
text: 'Delete remote',
|
||||
click: function() {
|
||||
notification.close();
|
||||
|
||||
if (activeProject.git.branches.remote && activeProject.git.branches.remote.indexOf(entry.name+"/") === 0) {
|
||||
delete activeProject.git.branches.remote;
|
||||
}
|
||||
if (activeProject.git.branches.remoteAlt && activeProject.git.branches.remoteAlt.indexOf(entry.name+"/") === 0) {
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
|
||||
var url = "projects/"+activeProject.name+"/remotes/"+entry.name;
|
||||
var options = {
|
||||
url: url,
|
||||
@@ -1284,7 +1288,6 @@ RED.projects.settings = (function() {
|
||||
activeProject.git.remotes[name] = remote;
|
||||
});
|
||||
}
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
RED.sidebar.versionControl.refresh();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -80,26 +80,6 @@ RED.projects = (function() {
|
||||
$('<p>').text("To get started you can create your first project or clone an existing project from a git repository.").appendTo(body);
|
||||
$('<p>').text("If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.").appendTo(body);
|
||||
|
||||
var row = $('<div style="text-align: center"></div>').appendTo(body);
|
||||
var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>Create Project</button>').appendTo(row);
|
||||
var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>Clone Repository</button>').appendTo(row);
|
||||
|
||||
createAsEmpty.click(function(e) {
|
||||
e.preventDefault();
|
||||
createProjectOptions = {
|
||||
action: "create"
|
||||
}
|
||||
show('git-config');
|
||||
})
|
||||
|
||||
createAsClone.click(function(e) {
|
||||
e.preventDefault();
|
||||
createProjectOptions = {
|
||||
action: "clone"
|
||||
}
|
||||
show('git-config');
|
||||
})
|
||||
|
||||
return container;
|
||||
},
|
||||
buttons: [
|
||||
@@ -110,6 +90,13 @@ RED.projects = (function() {
|
||||
createProjectOptions = {};
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Create your first project", // TODO: nls
|
||||
class: "primary",
|
||||
click: function() {
|
||||
show('git-config');
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -183,11 +170,7 @@ RED.projects = (function() {
|
||||
currentGitSettings.user.name = gitUsernameInput.val();
|
||||
currentGitSettings.user.email = gitEmailInput.val();
|
||||
RED.settings.set('git', currentGitSettings);
|
||||
if (createProjectOptions.action === "create") {
|
||||
show('project-details');
|
||||
} else if (createProjectOptions.action === "clone") {
|
||||
show('clone-project');
|
||||
}
|
||||
show('project-details');
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -320,366 +303,6 @@ RED.projects = (function() {
|
||||
}
|
||||
};
|
||||
})(),
|
||||
'clone-project': (function() {
|
||||
var projectNameInput;
|
||||
var projectSummaryInput;
|
||||
var projectFlowFileInput;
|
||||
var projectSecretInput;
|
||||
var projectSecretSelect;
|
||||
var copyProject;
|
||||
var projectRepoInput;
|
||||
var projectCloneSecret;
|
||||
var emptyProjectCredentialInput;
|
||||
var projectRepoUserInput;
|
||||
var projectRepoPasswordInput;
|
||||
var projectNameSublabel;
|
||||
var projectRepoSSHKeySelect;
|
||||
var projectRepoPassphrase;
|
||||
var projectRepoRemoteName
|
||||
var projectRepoBranch;
|
||||
var selectedProject;
|
||||
|
||||
return {
|
||||
content: function(options) {
|
||||
var container = $('<div class="projects-dialog-screen-start"></div>');
|
||||
migrateProjectHeader.appendTo(container);
|
||||
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
||||
$('<p>').text("Clone a project").appendTo(body);
|
||||
$('<p>').text("If you already have a git repository containing a project, you can clone it to get started.").appendTo(body);
|
||||
|
||||
var projectList = null;
|
||||
var pendingFormValidation = false;
|
||||
$.getJSON("projects", function(data) {
|
||||
projectList = {};
|
||||
data.projects.forEach(function(p) {
|
||||
projectList[p] = true;
|
||||
if (pendingFormValidation) {
|
||||
pendingFormValidation = false;
|
||||
validateForm();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var validateForm = function() {
|
||||
var projectName = projectNameInput.val();
|
||||
var valid = true;
|
||||
if (projectNameInputChanged) {
|
||||
if (projectList === null) {
|
||||
pendingFormValidation = true;
|
||||
return;
|
||||
}
|
||||
projectNameStatus.empty();
|
||||
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName) || projectList[projectName]) {
|
||||
projectNameInput.addClass("input-error");
|
||||
$('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>').appendTo(projectNameStatus);
|
||||
projectNameValid = false;
|
||||
valid = false;
|
||||
if (projectList[projectName]) {
|
||||
projectNameSublabel.text("Project already exists");
|
||||
} else {
|
||||
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
|
||||
}
|
||||
} else {
|
||||
projectNameInput.removeClass("input-error");
|
||||
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
|
||||
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
|
||||
projectNameValid = true;
|
||||
}
|
||||
projectNameLastChecked = projectName;
|
||||
}
|
||||
valid = projectNameValid;
|
||||
|
||||
var repo = projectRepoInput.val();
|
||||
|
||||
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
|
||||
var validRepo = repo.length > 0 && !/\s/.test(repo);
|
||||
if (/^https?:\/\/[^/]+@/i.test(repo)) {
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("Do not include the username/password in the url");
|
||||
validRepo = false;
|
||||
}
|
||||
if (!validRepo) {
|
||||
if (projectRepoChanged) {
|
||||
projectRepoInput.addClass("input-error");
|
||||
}
|
||||
valid = false;
|
||||
} else {
|
||||
projectRepoInput.removeClass("input-error");
|
||||
}
|
||||
if (/^https?:\/\//.test(repo)) {
|
||||
$(".projects-dialog-screen-create-row-creds").show();
|
||||
$(".projects-dialog-screen-create-row-sshkey").hide();
|
||||
} else if (/^(?:ssh|[\S]+?@[\S]+?):(?:\/\/)?/.test(repo)) {
|
||||
$(".projects-dialog-screen-create-row-creds").hide();
|
||||
$(".projects-dialog-screen-create-row-sshkey").show();
|
||||
// if ( !getSelectedSSHKey(projectRepoSSHKeySelect) ) {
|
||||
// valid = false;
|
||||
// }
|
||||
} else {
|
||||
$(".projects-dialog-screen-create-row-creds").hide();
|
||||
$(".projects-dialog-screen-create-row-sshkey").hide();
|
||||
}
|
||||
|
||||
$("#projects-dialog-clone-project").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
|
||||
}
|
||||
|
||||
var row;
|
||||
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(body);
|
||||
$('<label for="projects-dialog-screen-create-project-name">Project name</label>').appendTo(row);
|
||||
|
||||
var subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||
projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').appendTo(subrow);
|
||||
var projectNameStatus = $('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||
|
||||
var projectNameInputChanged = false;
|
||||
var projectNameLastChecked = "";
|
||||
var projectNameValid;
|
||||
var checkProjectName;
|
||||
var autoInsertedName = "";
|
||||
|
||||
|
||||
projectNameInput.on("change keyup paste",function() {
|
||||
projectNameInputChanged = (projectNameInput.val() !== projectNameLastChecked);
|
||||
if (checkProjectName) {
|
||||
clearTimeout(checkProjectName);
|
||||
} else if (projectNameInputChanged) {
|
||||
projectNameStatus.empty();
|
||||
$('<img src="red/images/spin.svg"/>').appendTo(projectNameStatus);
|
||||
if (projectNameInput.val() === '') {
|
||||
validateForm();
|
||||
return;
|
||||
}
|
||||
}
|
||||
checkProjectName = setTimeout(function() {
|
||||
validateForm();
|
||||
checkProjectName = null;
|
||||
},300)
|
||||
});
|
||||
projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
|
||||
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body);
|
||||
$('<label for="projects-dialog-screen-create-project-repo">Git repository URL</label>').appendTo(row);
|
||||
projectRepoInput = $('<input id="projects-dialog-screen-create-project-repo" type="text" placeholder="https://git.example.com/path/my-project.git"></input>').appendTo(row);
|
||||
$('<label id="projects-dialog-screen-create-project-repo-label" class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row);
|
||||
var projectRepoChanged = false;
|
||||
var lastProjectRepo = "";
|
||||
projectRepoInput.on("change keyup paste",function() {
|
||||
projectRepoChanged = true;
|
||||
var repo = $(this).val();
|
||||
if (lastProjectRepo !== repo) {
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
|
||||
}
|
||||
lastProjectRepo = repo;
|
||||
|
||||
var m = /\/([^/]+?)(?:\.git)?$/.exec(repo);
|
||||
if (m) {
|
||||
var projectName = projectNameInput.val();
|
||||
if (projectName === "" || projectName === autoInsertedName) {
|
||||
autoInsertedName = m[1];
|
||||
projectNameInput.val(autoInsertedName);
|
||||
projectNameInput.change();
|
||||
}
|
||||
}
|
||||
validateForm();
|
||||
});
|
||||
|
||||
var cloneAuthRows = $('<div class="projects-dialog-screen-create-row"></div>').appendTo(body);
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row-auth-error"></div>').hide().appendTo(cloneAuthRows);
|
||||
$('<div><i class="fa fa-warning"></i> Authentication failed</div>').appendTo(row);
|
||||
|
||||
// Repo credentials - username/password ----------------
|
||||
row = $('<div class="hide form-row projects-dialog-screen-create-row-creds"></div>').hide().appendTo(cloneAuthRows);
|
||||
|
||||
var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="projects-dialog-screen-create-project-repo-user">Username</label>').appendTo(subrow);
|
||||
projectRepoUserInput = $('<input id="projects-dialog-screen-create-project-repo-user" type="text"></input>').appendTo(subrow);
|
||||
|
||||
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="projects-dialog-screen-create-project-repo-pass">Password</label>').appendTo(subrow);
|
||||
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||
// -----------------------------------------------------
|
||||
|
||||
// Repo credentials - key/passphrase -------------------
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(cloneAuthRows);
|
||||
subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH Key</label>').appendTo(subrow);
|
||||
projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow);
|
||||
|
||||
$.getJSON("settings/user/keys", function(data) {
|
||||
var count = 0;
|
||||
data.keys.forEach(function(key) {
|
||||
projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name));
|
||||
count++;
|
||||
});
|
||||
if (count === 0) {
|
||||
projectRepoSSHKeySelect.addClass("input-error");
|
||||
projectRepoSSHKeySelect.attr("disabled",true);
|
||||
sshwarningRow.show();
|
||||
} else {
|
||||
projectRepoSSHKeySelect.removeClass("input-error");
|
||||
projectRepoSSHKeySelect.attr("disabled",false);
|
||||
sshwarningRow.hide();
|
||||
}
|
||||
});
|
||||
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||
$('<label for="projects-dialog-screen-create-project-repo-passphrase">Passphrase</label>').appendTo(subrow);
|
||||
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
|
||||
|
||||
subrow = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
|
||||
var sshwarningRow = $('<div class="projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
|
||||
$('<div class="form-row"><i class="fa fa-warning"></i> Before you can clone a repository over ssh you must add an SSH key to access it.</div>').appendTo(sshwarningRow);
|
||||
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
|
||||
$('<button class="editor-button">Add an ssh key</button>').appendTo(subrow).click(function(e) {
|
||||
e.preventDefault();
|
||||
$('#projects-dialog-cancel').click();
|
||||
RED.userSettings.show('gitconfig');
|
||||
setTimeout(function() {
|
||||
$("#user-settings-gitconfig-add-key").click();
|
||||
},500);
|
||||
});
|
||||
// -----------------------------------------------------
|
||||
|
||||
|
||||
// Secret - clone
|
||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body);
|
||||
$('<label>Credentials encryption key</label>').appendTo(row);
|
||||
projectSecretInput = $('<input type="password"></input>').appendTo(row);
|
||||
|
||||
|
||||
|
||||
return container;
|
||||
},
|
||||
buttons: function(options) {
|
||||
return [
|
||||
{
|
||||
text: "Back",
|
||||
click: function() {
|
||||
show('git-config');
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "projects-dialog-clone-project",
|
||||
disabled: true,
|
||||
text: "Clone project", // TODO: nls
|
||||
class: "primary disabled",
|
||||
click: function() {
|
||||
var projectType = $(".projects-dialog-screen-create-type.selected").data('type');
|
||||
var projectData = {
|
||||
name: projectNameInput.val(),
|
||||
}
|
||||
projectData.credentialSecret = projectSecretInput.val();
|
||||
var repoUrl = projectRepoInput.val();
|
||||
var metaData = {};
|
||||
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repoUrl)) {
|
||||
var selected = projectRepoSSHKeySelect.val();//false;//getSelectedSSHKey(projectRepoSSHKeySelect);
|
||||
if ( selected ) {
|
||||
projectData.git = {
|
||||
remotes: {
|
||||
'origin': {
|
||||
url: repoUrl,
|
||||
keyFile: selected,
|
||||
passphrase: projectRepoPassphrase.val()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
console.log("Error! Can't get selected SSH key path.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
projectData.git = {
|
||||
remotes: {
|
||||
'origin': {
|
||||
url: repoUrl,
|
||||
username: projectRepoUserInput.val(),
|
||||
password: projectRepoPasswordInput.val()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$(".projects-dialog-screen-create-row-auth-error").hide();
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
|
||||
|
||||
projectRepoUserInput.removeClass("input-error");
|
||||
projectRepoPasswordInput.removeClass("input-error");
|
||||
projectRepoSSHKeySelect.removeClass("input-error");
|
||||
projectRepoPassphrase.removeClass("input-error");
|
||||
|
||||
RED.deploy.setDeployInflight(true);
|
||||
RED.projects.settings.switchProject(projectData.name);
|
||||
|
||||
sendRequest({
|
||||
url: "projects",
|
||||
type: "POST",
|
||||
handleAuthFail: false,
|
||||
responses: {
|
||||
200: function(data) {
|
||||
dialog.dialog( "close" );
|
||||
},
|
||||
400: {
|
||||
'project_exists': function(error) {
|
||||
console.log("already exists");
|
||||
},
|
||||
'git_error': function(error) {
|
||||
console.log("git error",error);
|
||||
},
|
||||
'git_connection_failed': function(error) {
|
||||
projectRepoInput.addClass("input-error");
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("Connection failed");
|
||||
},
|
||||
'git_not_a_repository': function(error) {
|
||||
projectRepoInput.addClass("input-error");
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("Not a git repository");
|
||||
},
|
||||
'git_repository_not_found': function(error) {
|
||||
projectRepoInput.addClass("input-error");
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("Repository not found");
|
||||
},
|
||||
'git_auth_failed': function(error) {
|
||||
$(".projects-dialog-screen-create-row-auth-error").show();
|
||||
|
||||
projectRepoUserInput.addClass("input-error");
|
||||
projectRepoPasswordInput.addClass("input-error");
|
||||
// getRepoAuthDetails(req);
|
||||
projectRepoSSHKeySelect.addClass("input-error");
|
||||
projectRepoPassphrase.addClass("input-error");
|
||||
},
|
||||
'missing_flow_file': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'project_empty': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'credentials_load_failed': function(error) {
|
||||
// This is handled via a runtime notification.
|
||||
dialog.dialog("close");
|
||||
},
|
||||
'*': function(error) {
|
||||
reportUnexpectedError(error);
|
||||
$( dialog ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
}
|
||||
},projectData).then(function() {
|
||||
RED.events.emit("project:change", {name:name});
|
||||
}).always(function() {
|
||||
setTimeout(function() {
|
||||
RED.deploy.setDeployInflight(false);
|
||||
},500);
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})(),
|
||||
'default-files': (function() {
|
||||
var projectFlowFileInput;
|
||||
var projectCredentialFileInput;
|
||||
@@ -1504,7 +1127,6 @@ RED.projects = (function() {
|
||||
}
|
||||
|
||||
$(".projects-dialog-screen-create-row-auth-error").hide();
|
||||
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
|
||||
|
||||
projectRepoUserInput.removeClass("input-error");
|
||||
projectRepoPasswordInput.removeClass("input-error");
|
||||
@@ -2251,43 +1873,6 @@ RED.projects = (function() {
|
||||
createProjectOptions = {};
|
||||
show('default-files',{existingProject: true});
|
||||
}
|
||||
function createDefaultPackageFile() {
|
||||
RED.deploy.setDeployInflight(true);
|
||||
RED.projects.settings.switchProject(activeProject.name);
|
||||
|
||||
var method = "PUT";
|
||||
var url = "projects/"+activeProject.name;
|
||||
var createProjectOptions = {
|
||||
initialise: true
|
||||
};
|
||||
sendRequest({
|
||||
url: url,
|
||||
type: method,
|
||||
requireCleanWorkspace: true,
|
||||
handleAuthFail: false,
|
||||
responses: {
|
||||
200: function(data) { },
|
||||
400: {
|
||||
'git_error': function(error) {
|
||||
console.log("git error",error);
|
||||
},
|
||||
'missing_flow_file': function(error) {
|
||||
// This is a natural next error - but let the runtime event
|
||||
// trigger the dialog rather than double-report it.
|
||||
$( dialog ).dialog( "close" );
|
||||
},
|
||||
'*': function(error) {
|
||||
reportUnexpectedError(error);
|
||||
$( dialog ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
}
|
||||
},createProjectOptions).always(function() {
|
||||
setTimeout(function() {
|
||||
RED.deploy.setDeployInflight(false);
|
||||
},500);
|
||||
})
|
||||
}
|
||||
|
||||
function refresh(done) {
|
||||
$.getJSON("projects",function(data) {
|
||||
@@ -2367,7 +1952,6 @@ RED.projects = (function() {
|
||||
RED.projects.settings.show('deps');
|
||||
},
|
||||
createDefaultFileSet: createDefaultFileSet,
|
||||
createDefaultPackageFile: createDefaultPackageFile,
|
||||
// showSidebar: showSidebar,
|
||||
refresh: refresh,
|
||||
editProject: function() {
|
||||
|
||||
@@ -592,10 +592,7 @@ RED.sidebar.versionControl = (function() {
|
||||
closeBranchBox();
|
||||
localCommitListShade.show();
|
||||
$(this).addClass('selected');
|
||||
var activeProject = RED.projects.getActiveProject();
|
||||
$("#sidebar-version-control-repo-toolbar-set-upstream-row").toggle(!!activeProject.git.branches.remoteAlt);
|
||||
remoteBox.show();
|
||||
|
||||
setTimeout(function() {
|
||||
remoteBox.css("height","265px");
|
||||
},100);
|
||||
@@ -871,8 +868,7 @@ RED.sidebar.versionControl = (function() {
|
||||
if (activeProject.git.branches.remoteAlt) {
|
||||
url+="/"+activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
var setUpstream = $("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked');
|
||||
if (setUpstream) {
|
||||
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
|
||||
url+="?u=true"
|
||||
}
|
||||
utils.sendRequest({
|
||||
@@ -884,10 +880,6 @@ RED.sidebar.versionControl = (function() {
|
||||
// done(error,null);
|
||||
},
|
||||
200: function(data) {
|
||||
if (setUpstream && activeProject.git.branches.remoteAlt) {
|
||||
activeProject.git.branches.remote = activeProject.git.branches.remoteAlt;
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
refresh(true);
|
||||
closeRemoteBox();
|
||||
},
|
||||
@@ -936,10 +928,6 @@ RED.sidebar.versionControl = (function() {
|
||||
// done(error,null);
|
||||
},
|
||||
200: function(data) {
|
||||
if (options.setUpstream && activeProject.git.branches.remoteAlt) {
|
||||
activeProject.git.branches.remote = activeProject.git.branches.remoteAlt;
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
refresh(true);
|
||||
closeRemoteBox();
|
||||
},
|
||||
|
||||
@@ -174,7 +174,7 @@ RED.search = (function() {
|
||||
addItem: function(container,i,object) {
|
||||
var node = object.node;
|
||||
if (node === undefined) {
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||
|
||||
} else {
|
||||
var def = node._def;
|
||||
@@ -200,12 +200,12 @@ RED.search = (function() {
|
||||
} else {
|
||||
workspace = "flow:"+workspace.label;
|
||||
}
|
||||
$('<div>',{class:"red-ui-search-result-node-flow"}).text(workspace).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-flow"}).html(workspace).appendTo(contentDiv);
|
||||
}
|
||||
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).text(object.label || node.id).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-type"}).text(node.type).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-id"}).text(node.id).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).html(object.label || node.id).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
|
||||
|
||||
div.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -139,7 +139,7 @@ RED.subflow = (function() {
|
||||
RED.view.select();
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
$("#workspace-subflow-output .spinner-value").text(subflow.out.length);
|
||||
$("#workspace-subflow-output .spinner-value").html(subflow.out.length);
|
||||
}
|
||||
|
||||
function removeSubflowOutput(removedSubflowOutputs) {
|
||||
@@ -216,7 +216,7 @@ RED.subflow = (function() {
|
||||
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
|
||||
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
|
||||
|
||||
$("#workspace-subflow-output .spinner-value").text(activeSubflow.out.length);
|
||||
$("#workspace-subflow-output .spinner-value").html(activeSubflow.out.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ RED.sidebar.info = (function() {
|
||||
$(propRow.children()[1]).text(node.label||node.name||"");
|
||||
if (node.type === "tab") {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
|
||||
$(propRow.children()[1]).html((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
|
||||
}
|
||||
} else {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
|
||||
@@ -175,12 +175,10 @@ RED.sidebar.info = (function() {
|
||||
|
||||
|
||||
if (node.type !== "subflow" && node.name) {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
$('<span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
|
||||
$('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody);
|
||||
}
|
||||
if (!m) {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td></td></tr>").appendTo(tableBody);
|
||||
$(propRow.children()[1]).text(node.type);
|
||||
$('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td>"+node.type+"</td></tr>").appendTo(tableBody);
|
||||
}
|
||||
|
||||
if (!m && node.type != "subflow" && node.type != "comment") {
|
||||
@@ -208,7 +206,7 @@ RED.sidebar.info = (function() {
|
||||
nodeDiv.css({'backgroundColor':colour, "cursor":"pointer"});
|
||||
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
|
||||
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
|
||||
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).text(configLabel).appendTo(container);
|
||||
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).html(configLabel).appendTo(container);
|
||||
|
||||
nodeDiv.on('dblclick',function() {
|
||||
RED.editor.editConfig("", configNode.type, configNode.id);
|
||||
@@ -238,19 +236,19 @@ RED.sidebar.info = (function() {
|
||||
|
||||
var infoText = "";
|
||||
if (!subflowNode && node.type !== "comment" && node.type !== "tab") {
|
||||
infoSection.title.text(RED._("sidebar.info.nodeHelp"));
|
||||
infoSection.title.html(RED._("sidebar.info.nodeHelp"));
|
||||
var helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>');
|
||||
infoText = helpText;
|
||||
} else if (node.type === "tab") {
|
||||
infoSection.title.text(RED._("sidebar.info.flowDesc"));
|
||||
infoSection.title.html(RED._("sidebar.info.flowDesc"));
|
||||
infoText = marked(node.info||"")||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>');
|
||||
}
|
||||
|
||||
if (subflowNode) {
|
||||
infoText = infoText + (marked(subflowNode.info||"")||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>'));
|
||||
infoSection.title.text(RED._("sidebar.info.subflowDesc"));
|
||||
infoSection.title.html(RED._("sidebar.info.subflowDesc"));
|
||||
} else if (node._def && node._def.info) {
|
||||
infoSection.title.text(RED._("sidebar.info.nodeHelp"));
|
||||
infoSection.title.html(RED._("sidebar.info.nodeHelp"));
|
||||
var info = node._def.info;
|
||||
var textInfo = (typeof info === "function" ? info.call(node) : info);
|
||||
// TODO: help
|
||||
|
||||
@@ -52,7 +52,7 @@ RED.tray = (function() {
|
||||
b.attr('id',button.id);
|
||||
}
|
||||
if (button.text) {
|
||||
b.text(button.text);
|
||||
b.html(button.text);
|
||||
}
|
||||
if (button.click) {
|
||||
b.click((function(action) {
|
||||
|
||||
@@ -147,7 +147,7 @@ RED.typeSearch = (function() {
|
||||
var label = object.label;
|
||||
object.index += "|"+label.toLowerCase();
|
||||
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).text(label).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).html(label).appendTo(contentDiv);
|
||||
|
||||
div.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -26,14 +26,14 @@ RED.utils = (function() {
|
||||
function buildMessageSummaryValue(value) {
|
||||
var result;
|
||||
if (Array.isArray(value)) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('array['+value.length+']');
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
|
||||
} else if (value === null) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-null">null</span>');
|
||||
} else if (typeof value === 'object') {
|
||||
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('buffer['+value.length+']');
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.length+']');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('array['+value.length+']');
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
|
||||
} else {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta">object</span>');
|
||||
}
|
||||
@@ -304,7 +304,7 @@ RED.utils = (function() {
|
||||
element.addClass('collapsed');
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
makeExpandable(header, function() {
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text(typeHint||'string').appendTo(header);
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header);
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
|
||||
$('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row);
|
||||
},function(state) {if (ontoggle) { ontoggle(path,state);}}, checkExpanded(strippedKey,expandPaths));
|
||||
@@ -358,7 +358,7 @@ RED.utils = (function() {
|
||||
element.addClass('debug-message-buffer-raw');
|
||||
}
|
||||
if (key) {
|
||||
headerHead = $('<span class="debug-message-type-meta"></span>').text(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
|
||||
headerHead = $('<span class="debug-message-type-meta"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
|
||||
} else {
|
||||
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
|
||||
$('<span>[ </span>').appendTo(headerHead);
|
||||
@@ -381,7 +381,7 @@ RED.utils = (function() {
|
||||
|
||||
makeExpandable(header,function() {
|
||||
if (!key) {
|
||||
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text(typeHint||(type+'['+originalLength+']')).appendTo(header);
|
||||
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(header);
|
||||
}
|
||||
if (type === 'buffer') {
|
||||
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
|
||||
@@ -394,7 +394,7 @@ RED.utils = (function() {
|
||||
}
|
||||
$('<pre class="debug-message-type-string"></pre>').text(stringEncoding).appendTo(sr);
|
||||
var bufferOpts = $('<span class="debug-message-buffer-opts"></span>').appendTo(headerHead);
|
||||
var switchFormat = $('<a href="#"></a>').addClass('selected').text('raw').appendTo(bufferOpts).click(function(e) {
|
||||
var switchFormat = $('<a href="#"></a>').addClass('selected').html('raw').appendTo(bufferOpts).click(function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
formatBuffer(element,$(this),sourceId,path,true);
|
||||
@@ -471,7 +471,7 @@ RED.utils = (function() {
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
makeExpandable(header, function() {
|
||||
if (!key) {
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text('object').appendTo(header);
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html('object').appendTo(header);
|
||||
}
|
||||
for (i=0;i<keys.length;i++) {
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
|
||||
@@ -507,7 +507,7 @@ RED.utils = (function() {
|
||||
checkExpanded(strippedKey,expandPaths));
|
||||
}
|
||||
if (key) {
|
||||
$('<span class="debug-message-type-meta"></span>').text('object').appendTo(entryObj);
|
||||
$('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj);
|
||||
} else {
|
||||
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
|
||||
$('<span>{ </span>').appendTo(headerHead);
|
||||
|
||||
@@ -172,12 +172,12 @@ RED.workspaces = (function() {
|
||||
i.addClass('fa-toggle-on');
|
||||
i.removeClass('fa-toggle-off');
|
||||
$("#node-input-disabled").prop("checked",false);
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
|
||||
} else {
|
||||
i.addClass('fa-toggle-off');
|
||||
i.removeClass('fa-toggle-on');
|
||||
$("#node-input-disabled").prop("checked",true);
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.disabled"));
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
|
||||
}
|
||||
})
|
||||
|
||||
@@ -185,13 +185,13 @@ RED.workspaces = (function() {
|
||||
$("#node-input-disabled").prop("checked",workspace.disabled);
|
||||
if (workspace.disabled) {
|
||||
dialogForm.find("#node-input-disabled-btn i").removeClass('fa-toggle-on').addClass('fa-toggle-off');
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.disabled"));
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
|
||||
} else {
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
|
||||
}
|
||||
} else {
|
||||
workspace.disabled = false;
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
|
||||
}
|
||||
|
||||
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
||||
|
||||
@@ -49,12 +49,7 @@
|
||||
.palette-module-version {
|
||||
color: #aaa;
|
||||
}
|
||||
.palette-module-errors .fa-warning {
|
||||
opacity: 0.5;
|
||||
}
|
||||
ul.palette-module-error-list li {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -227,20 +222,6 @@
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
.palette-module-meta .fa-warning {
|
||||
color: #AD1625;
|
||||
}
|
||||
ul.palette-module-error-list {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
li {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
.palette-module-shade {
|
||||
@include shade;
|
||||
text-align: center;
|
||||
|
||||
@@ -139,17 +139,16 @@
|
||||
}
|
||||
}
|
||||
button.editor-button {
|
||||
width: calc(50% - 80px);
|
||||
width: calc(50% - 40px);
|
||||
margin: 20px;
|
||||
height: auto;
|
||||
height: 175px;
|
||||
line-height: 2em;
|
||||
padding: 10px;
|
||||
border-color: #aaa;
|
||||
font-size: 1.5em !important;
|
||||
i {
|
||||
color: #aaa;
|
||||
color: #ccc;
|
||||
}
|
||||
&:hover i {
|
||||
color: #999;
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
.button-group {
|
||||
@@ -161,6 +160,7 @@
|
||||
button.projects-dialog-screen-create-type {
|
||||
height: auto;
|
||||
padding: 10px;
|
||||
|
||||
}
|
||||
.button-group {
|
||||
text-align: center;
|
||||
|
||||
1
editor/vendor/ace/snippets/json.js
vendored
1
editor/vendor/ace/snippets/json.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"})
|
||||
1
editor/vendor/ace/snippets/sql.js
vendored
1
editor/vendor/ace/snippets/sql.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/sql",["require","exports","module"],function(e,t,n){"use strict";t.snippetText="snippet tbl\n create table ${1:table} (\n ${2:columns}\n );\nsnippet col\n ${1:name} ${2:type} ${3:default ''} ${4:not null}\nsnippet ccol\n ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\nsnippet ncol\n ${1:name} number ${3:default 0} ${4:not null}\nsnippet dcol\n ${1:name} date ${3:default sysdate} ${4:not null}\nsnippet ind\n create index ${3:$1_$2} on ${1:table}(${2:column});\nsnippet uind\n create unique index ${1:name} on ${2:table}(${3:column});\nsnippet tblcom\n comment on table ${1:table} is '${2:comment}';\nsnippet colcom\n comment on column ${1:table}.${2:column} is '${3:comment}';\nsnippet addcol\n alter table ${1:table} add (${2:column} ${3:type});\nsnippet seq\n create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\nsnippet s*\n select * from ${1:table}\n",t.scope="sql"})
|
||||
1
editor/vendor/ace/snippets/swift.js
vendored
1
editor/vendor/ace/snippets/swift.js
vendored
@@ -1 +0,0 @@
|
||||
ace.define("ace/snippets/swift",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="swift"})
|
||||
@@ -181,7 +181,7 @@
|
||||
this.handleDebugMessage = function(t,o) {
|
||||
var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
|
||||
if (sourceNode) {
|
||||
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name,type:sourceNode.type,_alias:o._alias};
|
||||
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name};
|
||||
}
|
||||
RED.debug.handleDebugMessage(o);
|
||||
if (subWindow) {
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
outputs:1,
|
||||
icon: "function.png",
|
||||
label: function() {
|
||||
return this.name||this._("function.function");
|
||||
return this.name;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
|
||||
@@ -80,7 +80,6 @@ module.exports = function(RED) {
|
||||
console:console,
|
||||
util:util,
|
||||
Buffer:Buffer,
|
||||
Date: Date,
|
||||
RED: {
|
||||
util: RED.util
|
||||
},
|
||||
@@ -205,14 +204,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
var context = vm.createContext(sandbox);
|
||||
try {
|
||||
this.script = vm.createScript(functionText, {
|
||||
filename: 'Function node:'+this.id+(this.name?' ['+this.name+']':''), // filename for stack traces
|
||||
displayErrors: true
|
||||
// Using the following options causes node 4/6 to not include the line number
|
||||
// in the stack output. So don't use them.
|
||||
// lineOffset: -11, // line number offset to be used for stack traces
|
||||
// columnOffset: 0, // column number offset to be used for stack traces
|
||||
});
|
||||
this.script = vm.createScript(functionText);
|
||||
this.on("input", function(msg) {
|
||||
try {
|
||||
var start = process.hrtime();
|
||||
@@ -227,13 +219,6 @@ module.exports = function(RED) {
|
||||
this.status({fill:"yellow",shape:"dot",text:""+converted});
|
||||
}
|
||||
} catch(err) {
|
||||
//remove unwanted part
|
||||
var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/);
|
||||
err.stack = err.stack.slice(0, index).split('\n').slice(0,-1).join('\n');
|
||||
var stack = err.stack.split(/\r?\n/);
|
||||
|
||||
//store the error in msg to be used in flows
|
||||
msg.error = err;
|
||||
|
||||
var line = 0;
|
||||
var errorMessage;
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
category: 'function',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
field: {value:"payload", validate:RED.validators.typedInput("fieldType")},
|
||||
field: {value:"payload", validate: RED.validators.typedInput("fieldType")},
|
||||
fieldType: {value:"msg"},
|
||||
format: {value:"handlebars"},
|
||||
syntax: {value:"mustache"},
|
||||
@@ -106,10 +106,6 @@
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var that = this;
|
||||
if (!this.field) {
|
||||
this.field = 'payload';
|
||||
$("#node-input-field").val("payload");
|
||||
}
|
||||
if (!this.fieldType) {
|
||||
this.fieldType = 'msg';
|
||||
}
|
||||
|
||||
@@ -403,19 +403,12 @@ RED.debug = (function() {
|
||||
$(msg).addClass('debug-message-hover');
|
||||
if (o._source) {
|
||||
config.messageMouseEnter(o._source.id);
|
||||
if (o._source._alias) {
|
||||
config.messageMouseEnter(o._source._alias);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
msg.onmouseleave = function() {
|
||||
$(msg).removeClass('debug-message-hover');
|
||||
if (o._source) {
|
||||
config.messageMouseLeave(o._source.id);
|
||||
if (o._source._alias) {
|
||||
config.messageMouseLeave(o._source._alias);
|
||||
}
|
||||
}
|
||||
};
|
||||
var name = sanitize(((o.name?o.name:o.id)||"").toString());
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<dt>payload <span class="property-type">string | buffer</span></dt>
|
||||
<dd>a string unless detected as a binary buffer.</dd>
|
||||
<dt>topic <span class="property-type">string</span></dt>
|
||||
<dd>the MQTT topic, uses / as a hierarchy separator.</dd>
|
||||
<dd>the MQTT topic, uses / as a heirarchy separator.</dd>
|
||||
<dt>qos <span class="property-type">number</span> </dt>
|
||||
<dd>0, fire and forget - 1, at least once - 2, once and once only.</dd>
|
||||
<dt>retain <span class="property-type">boolean</span></dt>
|
||||
@@ -212,84 +212,48 @@
|
||||
<input type="password" id="node-config-input-password">
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-messages" style="display:none">
|
||||
<div id="mqtt-broker-section-birth">
|
||||
<div class="palette-header">
|
||||
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.birth-message"></span>
|
||||
</div>
|
||||
<div class="section-content" style="padding:10px 0 0 10px">
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
|
||||
<select id="node-config-input-birthRetain" style="width:75px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-birthQos" style="width:75px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-birth" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
|
||||
</div>
|
||||
<div id="mqtt-broker-section-close">
|
||||
<div class="palette-header">
|
||||
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.close-message"></span>
|
||||
</div>
|
||||
<div class="section-content" style="padding:10px 0 0 10px">
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-closeTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closeTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.close-topic">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
|
||||
<select id="node-config-input-closeRetain" style="width:75px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-closePayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closePayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-closeQos" style="width:75px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-birthQos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-config-input-birthRetain" style="width:125px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="mqtt-broker-section-will">
|
||||
<div class="palette-header">
|
||||
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.will-message"></span>
|
||||
</div>
|
||||
<div class="section-content" style="padding:10px 0 0 10px">
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.will-topic">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
|
||||
<select id="node-config-input-willRetain" style="width:75px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-willQos" style="width:75px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-config-input-birthPayload" data-i18n="[placeholder]common.label.payload">
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-will" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-config-input-willTopic" data-i18n="[placeholder]mqtt.placeholder.will-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-willQos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-config-input-willRetain" style="width:125px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-config-input-willPayload" data-i18n="[placeholder]common.label.payload">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -305,9 +269,6 @@
|
||||
<h4>Birth Message</h4>
|
||||
<p>This is a message that will be published on the configured topic whenever the
|
||||
connection is established.</p>
|
||||
<h4>Close Message</h4>
|
||||
<p>This is a message that will be published on the configured topic before the
|
||||
connection is closed normally, either by re-deploying the node, or by shutting down.</p>
|
||||
<h4>Will Message</h4>
|
||||
<p>This is a message that will be published by the broker in the event the node
|
||||
unexpectedly loses its connection.</p>
|
||||
@@ -339,18 +300,14 @@
|
||||
compatmode: { value: true},
|
||||
keepalive: {value:60,validate:RED.validators.number()},
|
||||
cleansession: {value: true},
|
||||
birthTopic: {value:""},
|
||||
birthQos: {value:"0"},
|
||||
birthRetain: {value:false},
|
||||
birthPayload: {value:""},
|
||||
closeTopic: {value:""},
|
||||
closeQos: {value:"0"},
|
||||
closeRetain: {value:false},
|
||||
closePayload: {value:""},
|
||||
willTopic: {value:""},
|
||||
willQos: {value:"0"},
|
||||
willRetain: {value:false},
|
||||
willPayload: {value:""}
|
||||
willPayload: {value:""},
|
||||
birthTopic: {value:""},
|
||||
birthQos: {value:"0"},
|
||||
birthRetain: {value:false},
|
||||
birthPayload: {value:""}
|
||||
},
|
||||
credentials: {
|
||||
user: {type:"text"},
|
||||
@@ -386,39 +343,14 @@
|
||||
id: "mqtt-broker-tab-security",
|
||||
label: this._("mqtt.tabs-label.security")
|
||||
});
|
||||
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-messages",
|
||||
label: this._("mqtt.tabs-label.messages")
|
||||
id: "mqtt-broker-tab-birth",
|
||||
label: this._("mqtt.tabs-label.birth")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-will",
|
||||
label: this._("mqtt.tabs-label.will")
|
||||
});
|
||||
|
||||
function setUpSection(sectionId, isExpanded) {
|
||||
var birthMessageSection = $(sectionId);
|
||||
var paletteHeader = birthMessageSection.find('.palette-header');
|
||||
var twistie = paletteHeader.find('i');
|
||||
var sectionContent = birthMessageSection.find('.section-content');
|
||||
|
||||
function toggleSection(expanded) {
|
||||
twistie.toggleClass('expanded', expanded);
|
||||
sectionContent.toggle(expanded);
|
||||
}
|
||||
paletteHeader.click(function(e) {
|
||||
e.preventDefault();
|
||||
var isExpanded = twistie.hasClass('expanded');
|
||||
toggleSection(!isExpanded);
|
||||
});
|
||||
toggleSection(isExpanded);
|
||||
}
|
||||
|
||||
// show first section if none are set so the user gets the idea
|
||||
var showBirthSection = this.birthTopic !== ""
|
||||
|| this.willTopic === ""
|
||||
&& this.birthTopic === ""
|
||||
&& this.closeTopic == "";
|
||||
setUpSection('#mqtt-broker-section-birth', showBirthSection);
|
||||
setUpSection('#mqtt-broker-section-close', this.closeTopic !== "");
|
||||
setUpSection('#mqtt-broker-section-will', this.willTopic !== "");
|
||||
|
||||
setTimeout(function() { tabs.resize(); },0);
|
||||
if (typeof this.cleansession === 'undefined') {
|
||||
this.cleansession = true;
|
||||
@@ -436,18 +368,14 @@
|
||||
this.keepalive = 15;
|
||||
$("#node-config-input-keepalive").val(this.keepalive);
|
||||
}
|
||||
if (typeof this.birthQos === 'undefined') {
|
||||
this.birthQos = "0";
|
||||
$("#node-config-input-birthQos").val("0");
|
||||
}
|
||||
if (typeof this.closeQos === 'undefined') {
|
||||
this.willQos = "0";
|
||||
$("#node-config-input-willQos").val("0");
|
||||
}
|
||||
if (typeof this.willQos === 'undefined') {
|
||||
this.willQos = "0";
|
||||
$("#node-config-input-willQos").val("0");
|
||||
}
|
||||
if (typeof this.birthQos === 'undefined') {
|
||||
this.birthQos = "0";
|
||||
$("#node-config-input-birthQos").val("0");
|
||||
}
|
||||
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-config-input-usetls").is(':checked')) {
|
||||
|
||||
@@ -60,15 +60,6 @@ module.exports = function(RED) {
|
||||
};
|
||||
}
|
||||
|
||||
if (n.closeTopic) {
|
||||
this.closeMessage = {
|
||||
topic: n.closeTopic,
|
||||
payload: n.closePayload || "",
|
||||
qos: Number(n.closeQos||0),
|
||||
retain: n.closeRetain=="true"|| n.closeRetain===true
|
||||
};
|
||||
}
|
||||
|
||||
if (this.credentials) {
|
||||
this.username = this.credentials.user;
|
||||
this.password = this.credentials.password;
|
||||
@@ -323,10 +314,6 @@ module.exports = function(RED) {
|
||||
this.on('close', function(done) {
|
||||
this.closing = true;
|
||||
if (this.connected) {
|
||||
// Send close message
|
||||
if (node.closeMessage) {
|
||||
node.publish(node.closeMessage);
|
||||
}
|
||||
this.client.once('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -86,10 +86,10 @@
|
||||
<dt class="optional">payload</dt>
|
||||
<dd>Sent as the body of the request.</dd>
|
||||
<dt class="optional">rejectUnauthorized</dt>
|
||||
<dd>If set to <code>false</code>, allows requests to be made to https sites that use
|
||||
<dd>If set to <code>true</code>, allows requests to be made to https sites that use
|
||||
self signed certificates.</dd>
|
||||
<dt class="optional">followRedirects</dt>
|
||||
<dd>If set to <code>false</code> prevent following Redirect (HTTP 301).<code>true</code> by default</dd>
|
||||
<dd>If set to <code>false</code> prevent following Redirect (HTTP 301).<code>true</code> by default</dd>
|
||||
</dl>
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -130,8 +130,6 @@ module.exports = function(RED) {
|
||||
socket.setKeepAlive(true,120000);
|
||||
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
|
||||
var id = (1+Math.random()*4294967295).toString(16);
|
||||
var fromi;
|
||||
var fromp;
|
||||
connectionPool[id] = socket;
|
||||
count++;
|
||||
node.status({text:RED._("tcpin.status.connections",{count:count})});
|
||||
@@ -157,21 +155,18 @@ module.exports = function(RED) {
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if ((typeof data) === "string") {
|
||||
buffer = buffer+data;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||
}
|
||||
fromi = socket.remoteAddress;
|
||||
fromp = socket.remotePort;
|
||||
}
|
||||
});
|
||||
socket.on('end', function() {
|
||||
if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) {
|
||||
if (buffer.length > 0) {
|
||||
var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp};
|
||||
var msg = {topic:node.topic, payload:buffer, ip:socket.remoteAddress, port:socket.remotePort};
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
<div class="form-row node-input-iface">
|
||||
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
|
||||
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.placeholder.interfaceprompt">
|
||||
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.label.interfaceprompt">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var os = require('os');
|
||||
var dgram = require('dgram');
|
||||
var udpInputPortsInUse = {};
|
||||
|
||||
@@ -31,29 +30,6 @@ module.exports = function(RED) {
|
||||
this.ipv = n.ipv || "udp4";
|
||||
var node = this;
|
||||
|
||||
if (node.iface && node.iface.indexOf(".") === -1) {
|
||||
try {
|
||||
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
|
||||
node.iface = null;
|
||||
}
|
||||
}
|
||||
|
||||
var opts = {type:node.ipv, reuseAddr:true};
|
||||
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
||||
var server;
|
||||
@@ -63,7 +39,7 @@ module.exports = function(RED) {
|
||||
udpInputPortsInUse[this.port] = server;
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("udp.errors.alreadyused",{port:node.port}));
|
||||
node.warn(RED._("udp.errors.alreadyused",node.port));
|
||||
server = udpInputPortsInUse[this.port]; // re-use existing
|
||||
}
|
||||
|
||||
@@ -145,38 +121,12 @@ module.exports = function(RED) {
|
||||
this.ipv = n.ipv || "udp4";
|
||||
var node = this;
|
||||
|
||||
if (node.iface && node.iface.indexOf(".") === -1) {
|
||||
try {
|
||||
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
|
||||
node.iface = null;
|
||||
}
|
||||
}
|
||||
|
||||
var opts = {type:node.ipv, reuseAddr:true};
|
||||
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
||||
|
||||
var sock;
|
||||
var p = this.port;
|
||||
if (node.multicast != "false") { p = this.outport||"0"; }
|
||||
if (udpInputPortsInUse[p]) {
|
||||
sock = udpInputPortsInUse[p];
|
||||
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
if (udpInputPortsInUse[this.outport || this.port]) {
|
||||
sock = udpInputPortsInUse[this.outport || this.port];
|
||||
}
|
||||
else {
|
||||
sock = dgram.createSocket(opts); // default to udp4
|
||||
@@ -186,35 +136,36 @@ module.exports = function(RED) {
|
||||
// prevent it going to the global error handler and shutting node-red
|
||||
// down.
|
||||
});
|
||||
udpInputPortsInUse[p] = sock;
|
||||
udpInputPortsInUse[this.outport || this.port] = sock;
|
||||
}
|
||||
|
||||
if (node.multicast != "false") {
|
||||
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
if (node.multicast == "multi") {
|
||||
try {
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||
node.log(RED._("udp.status.mc-ready",{iface:node.iface,outport:node.outport,host:node.addr,port:node.port}));
|
||||
} catch (e) {
|
||||
if (e.errno == "EINVAL") {
|
||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||
} else if (e.errno == "ENODEV") {
|
||||
node.error(RED._("udp.errors.interface"));
|
||||
} else {
|
||||
node.error(RED._("udp.errors.error",{error:e.errno}));
|
||||
}
|
||||
if (node.multicast != "false") {
|
||||
if (node.outport === "") { node.outport = node.port; }
|
||||
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
if (node.multicast == "multi") {
|
||||
try {
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||
node.log(RED._("udp.status.mc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
} catch (e) {
|
||||
if (e.errno == "EINVAL") {
|
||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||
} else if (e.errno == "ENODEV") {
|
||||
node.error(RED._("udp.errors.interface"));
|
||||
} else {
|
||||
node.error(RED._("udp.errors.error",{error:e.errno}));
|
||||
}
|
||||
} else {
|
||||
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
}
|
||||
});
|
||||
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
|
||||
sock.bind(node.outport);
|
||||
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
} else {
|
||||
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
|
||||
}
|
||||
} else {
|
||||
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
}
|
||||
});
|
||||
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
|
||||
sock.bind(node.outport);
|
||||
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
} else {
|
||||
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
|
||||
}
|
||||
|
||||
node.on("input", function(msg) {
|
||||
@@ -247,8 +198,8 @@ module.exports = function(RED) {
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
if (udpInputPortsInUse.hasOwnProperty(p)) {
|
||||
delete udpInputPortsInUse[p];
|
||||
if (udpInputPortsInUse.hasOwnProperty(node.outport || node.port)) {
|
||||
delete udpInputPortsInUse[node.outport || node.port];
|
||||
}
|
||||
try {
|
||||
sock.close();
|
||||
|
||||
@@ -186,7 +186,6 @@
|
||||
"oldrc": "Use old style output (compatibility mode)"
|
||||
},
|
||||
"function": {
|
||||
"function": "",
|
||||
"label": {
|
||||
"function": "Function",
|
||||
"outputs": "Outputs"
|
||||
@@ -323,7 +322,6 @@
|
||||
"broker": "Server",
|
||||
"example": "e.g. localhost",
|
||||
"qos": "QoS",
|
||||
"retain": "Retain",
|
||||
"clientid": "Client ID",
|
||||
"port": "Port",
|
||||
"keepalive": "Keep alive time (s)",
|
||||
@@ -333,22 +331,17 @@
|
||||
"verify-server-cert":"Verify server certificate",
|
||||
"compatmode": "Use legacy MQTT 3.1 support"
|
||||
},
|
||||
"sections-label":{
|
||||
"birth-message": "Message sent on connection (birth message)",
|
||||
"will-message":"Message sent on an unexpected disconnection (will message)",
|
||||
"close-message":"Message sent before disconnecting (close message)"
|
||||
},
|
||||
"tabs-label": {
|
||||
"connection": "Connection",
|
||||
"security": "Security",
|
||||
"messages": "Messages"
|
||||
"will": "Will Message",
|
||||
"birth": "Birth Message"
|
||||
},
|
||||
"placeholder": {
|
||||
"clientid": "Leave blank for auto generated",
|
||||
"clientid-nonclean":"Must be set for non-clean sessions",
|
||||
"will-topic": "Leave blank to disable will message",
|
||||
"birth-topic": "Leave blank to disable birth message",
|
||||
"close-topic": "Leave blank to disable close message"
|
||||
"birth-topic": "Leave blank to disable birth message"
|
||||
},
|
||||
"state": {
|
||||
"connected": "Connected to broker: __broker__",
|
||||
@@ -501,15 +494,15 @@
|
||||
"using": "using",
|
||||
"output": "Output",
|
||||
"group": "Group",
|
||||
"interface": "Local IF",
|
||||
"interface": "Local IP",
|
||||
"interfaceprompt": "(optional) local ip address to bind to",
|
||||
"send": "Send a",
|
||||
"toport": "to port",
|
||||
"address": "Address",
|
||||
"decode-base64": "Decode Base64 encoded payload?"
|
||||
},
|
||||
"placeholder": {
|
||||
"interface": "(optional) local interface or address to bind to",
|
||||
"interfaceprompt": "(optional) local interface or address to bind to",
|
||||
"interface": "(optional) ip address of eth0",
|
||||
"address": "destination ip"
|
||||
},
|
||||
"udpmsgs": "udp messages",
|
||||
@@ -537,11 +530,10 @@
|
||||
"mc-group": "udp multicast group __group__",
|
||||
"listener-stopped": "udp listener stopped",
|
||||
"output-stopped": "udp output stopped",
|
||||
"mc-ready": "udp multicast ready: __iface__:__outport__ -> __host__:__port__",
|
||||
"mc-ready": "udp multicast ready: __outport__ -> __host__:__port__",
|
||||
"bc-ready": "udp broadcast ready: __outport__ -> __host__:__port__",
|
||||
"ready": "udp ready: __outport__ -> __host__:__port__",
|
||||
"ready-nolocal": "udp ready: __host__:__port__",
|
||||
"re-use": "udp re-use socket: __outport__ -> __host__:__port__"
|
||||
"ready-nolocal": "udp ready: __host__:__port__"
|
||||
},
|
||||
"errors": {
|
||||
"access-error": "UDP access error, you may need root access for ports below 1024",
|
||||
@@ -551,8 +543,7 @@
|
||||
"ip-notset": "udp: ip address not set",
|
||||
"port-notset": "udp: port not set",
|
||||
"port-invalid": "udp: port number not valid",
|
||||
"alreadyused": "udp: port __port__ already in use",
|
||||
"ifnotfound": "udp: interface __iface__ not found"
|
||||
"alreadyused": "udp: port already in use"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
@@ -574,7 +565,6 @@
|
||||
"false":"is false",
|
||||
"null":"is null",
|
||||
"nnull":"is not null",
|
||||
"istype":"is of type",
|
||||
"head":"head",
|
||||
"tail":"tail",
|
||||
"index":"index between",
|
||||
@@ -680,8 +670,7 @@
|
||||
"html": {
|
||||
"label": {
|
||||
"select": "Selector",
|
||||
"output": "Output",
|
||||
"in": "in"
|
||||
"output": "Output"
|
||||
},
|
||||
"output": {
|
||||
"html": "the html content of the elements",
|
||||
|
||||
@@ -327,22 +327,17 @@
|
||||
"verify-server-cert": "サーバの証明書を確認",
|
||||
"compatmode": "旧MQTT 3.1のサポート"
|
||||
},
|
||||
"sections-label":{
|
||||
"birth-message": "接続時の送信メッセージ(Birthメッセージ)",
|
||||
"will-message":"予期しない切断時の送信メッセージ(Willメッセージ)",
|
||||
"close-message":"切断前の送信メッセージ(Closeメッセージ)"
|
||||
},
|
||||
"tabs-label": {
|
||||
"connection": "接続",
|
||||
"security": "セキュリティ",
|
||||
"messages": "メッセージ"
|
||||
"will": "Willメッセージ",
|
||||
"birth": "Birthメッセージ"
|
||||
},
|
||||
"placeholder": {
|
||||
"clientid": "IDを自動生成する場合は、無記入にしてください",
|
||||
"clientid-nonclean": "新規ではないセッションを設定してください",
|
||||
"will-topic": "Willメッセージを無効化する場合は、無記入にしてください",
|
||||
"birth-topic": "Birthメッセージを無効化する場合は、無記入にしてください",
|
||||
"close-topic": "Closeメッセージを無効化する場合は、無記入にしてください"
|
||||
"birth-topic": "Birthメッセージを無効化する場合は、無記入にしてください"
|
||||
},
|
||||
"state": {
|
||||
"connected": "ブローカへ接続しました: __broker__",
|
||||
@@ -493,14 +488,14 @@
|
||||
"output": "出力",
|
||||
"group": "グループ",
|
||||
"interface": "ローカルIP",
|
||||
"interfaceprompt": "(任意) 使用するローカルIPアドレス",
|
||||
"send": "送信",
|
||||
"toport": "ポート",
|
||||
"address": "アドレス",
|
||||
"decode-base64": "Base64形式のペイロードを復号"
|
||||
},
|
||||
"placeholder": {
|
||||
"interface": "(任意) 使用するローカルインターフェイスもしくはアドレス",
|
||||
"interfaceprompt": "(任意) 使用するローカルインターフェイスもしくはアドレス",
|
||||
"interface": "(任意) eth0のIPアドレス",
|
||||
"address": "宛先IPアドレス"
|
||||
},
|
||||
"udpmsgs": "UDPメッセージ",
|
||||
@@ -528,11 +523,10 @@
|
||||
"mc-group": "udpノードがグループ __group__ へマルチキャストしました",
|
||||
"listener-stopped": "udpノードが待ち受けを停止しました",
|
||||
"output-stopped": "udpノードが出力を停止しました",
|
||||
"mc-ready": "udpノードはマルチキャストの準備ができています: __iface__:__outport__ -> __host__:__port__",
|
||||
"mc-ready": "udpノードはマルチキャストの準備ができています: __outport__ -> __host__:__port__",
|
||||
"bc-ready": "udpノードはブロードキャストの準備ができています: __outport__ -> __host__:__port__",
|
||||
"ready": "udpノードは準備ができています: __outport__ -> __host__:__port__",
|
||||
"ready-nolocal": "udpノードは準備ができています: __host__:__port__",
|
||||
"re-use": "udp再利用ソケット: __outport__ -> __host__:__port__"
|
||||
"ready-nolocal": "udpノードは準備ができています: __host__:__port__"
|
||||
},
|
||||
"errors": {
|
||||
"access-error": "UDP接続エラー 管理者権限で1024未満のポート番号にアクセスできる必要があります",
|
||||
@@ -542,8 +536,6 @@
|
||||
"ip-notset": "udp: IPアドレスが設定されていません",
|
||||
"port-notset": "udp: ポートが設定されていません",
|
||||
"port-invalid": "udp: ポート番号が不正です",
|
||||
"alreadyused": "udp: 既に__port__番ポートが使用されています",
|
||||
"ifnotfound": "udp: インターフェイス __iface__ がありません",
|
||||
"alreadyused": "udp: 既にポートが使用されています"
|
||||
}
|
||||
},
|
||||
@@ -669,8 +661,7 @@
|
||||
"html": {
|
||||
"label": {
|
||||
"select": "抽出する要素",
|
||||
"output": "出力",
|
||||
"in": "対象:"
|
||||
"output": "出力"
|
||||
},
|
||||
"output": {
|
||||
"html": "要素内のHTML",
|
||||
@@ -770,9 +761,7 @@
|
||||
"status": {
|
||||
"stopped": "停止",
|
||||
"closed": "切断",
|
||||
"not-running": "停止中",
|
||||
"not-available": "利用不可",
|
||||
"na": "N/A : __value__"
|
||||
"not-running": "停止中"
|
||||
},
|
||||
"errors": {
|
||||
"ignorenode": "Raspberry Pi固有のノードを無視しました",
|
||||
|
||||
@@ -525,8 +525,7 @@
|
||||
"mc-ready": "udp 组播已准备好: __outport__ -> __host__:__port__",
|
||||
"bc-ready": "udp 广播已准备好: __outport__ -> __host__:__port__",
|
||||
"ready": "udp 已准备好: __outport__ -> __host__:__port__",
|
||||
"ready-nolocal": "udp 已准备好: __host__:__port__",
|
||||
"re-use": "udp 重用套接字: __outport__ -> __host__:__port__"
|
||||
"ready-nolocal": "udp 已准备好: __host__:__port__"
|
||||
},
|
||||
"errors": {
|
||||
"access-error": "UDP 访问错误, 你可能需要root权限才能接入1024以下的端口",
|
||||
|
||||
@@ -85,7 +85,6 @@
|
||||
{v:"false",t:"switch.rules.false",kind:'V'},
|
||||
{v:"null",t:"switch.rules.null",kind:'V'},
|
||||
{v:"nnull",t:"switch.rules.nnull",kind:'V'},
|
||||
{v:"istype",t:"switch.rules.istype",kind:'V'},
|
||||
{v:"head",t:"switch.rules.head",kind:'S'},
|
||||
{v:"index",t:"switch.rules.index",kind:'S'},
|
||||
{v:"tail",t:"switch.rules.tail",kind:'S'},
|
||||
@@ -141,7 +140,7 @@
|
||||
},
|
||||
icon: "switch.png",
|
||||
label: function() {
|
||||
return this.name||this._("switch.switch");
|
||||
return this.name||this._("swicth.switch");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
@@ -161,7 +160,6 @@
|
||||
var selectField = rule.find("select");
|
||||
var type = selectField.val()||"";
|
||||
var valueField = rule.find(".node-input-rule-value");
|
||||
var typeField = rule.find(".node-input-rule-type-value");
|
||||
var numField = rule.find(".node-input-rule-num-value");
|
||||
var expField = rule.find(".node-input-rule-exp-value");
|
||||
var btwnField1 = rule.find(".node-input-rule-btwn-value");
|
||||
@@ -182,8 +180,6 @@
|
||||
numField.typedInput("width",(newWidth-selectWidth-70));
|
||||
} else if (type === "jsonata_exp") {
|
||||
expField.typedInput("width",(newWidth-selectWidth-70));
|
||||
} else if (type === "istype") {
|
||||
typeField.typedInput("width",(newWidth-selectWidth-70));
|
||||
} else {
|
||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
||||
// valueField.hide();
|
||||
@@ -236,18 +232,6 @@
|
||||
var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
||||
var btwnAndLabel = $('<span/>',{class:"node-input-rule-btwn-label"}).text(" "+andLabel+" ").appendTo(row3);
|
||||
var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"margin-left:2px;"}).appendTo(row3).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
||||
var typeValueField = $('<input/>',{class:"node-input-rule-type-value",type:"text",style:"margin-left: 5px;"}).appendTo(row)
|
||||
.typedInput({default:'string',types:[
|
||||
{value:"string",label:"string",hasValue:false},
|
||||
{value:"number",label:"number",hasValue:false},
|
||||
{value:"boolean",label:"boolean",hasValue:false},
|
||||
{value:"array",label:"array",hasValue:false},
|
||||
{value:"buffer",label:"buffer",hasValue:false},
|
||||
{value:"object",label:"object",hasValue:false},
|
||||
{value:"json",label:"JSON string",hasValue:false},
|
||||
{value:"undefined",label:"undefined",hasValue:false},
|
||||
{value:"null",label:"null",hasValue:false}
|
||||
]});
|
||||
var finalspan = $('<span/>',{style:"float: right;margin-top: 6px;"}).appendTo(row);
|
||||
finalspan.append(' → <span class="node-input-rule-index">'+(i+1)+'</span> ');
|
||||
var caseSensitive = $('<input/>',{id:"node-input-rule-case-"+i,class:"node-input-rule-case",type:"checkbox",style:"width:auto;vertical-align:top"}).appendTo(row2);
|
||||
@@ -259,39 +243,26 @@
|
||||
valueField.typedInput('hide');
|
||||
expValueField.typedInput('hide');
|
||||
numValueField.typedInput('hide');
|
||||
typeValueField.typedInput('hide');
|
||||
btwnValueField.typedInput('show');
|
||||
} else if ((type === "head") || (type === "tail")) {
|
||||
btwnValueField.typedInput('hide');
|
||||
btwnValue2Field.typedInput('hide');
|
||||
expValueField.typedInput('hide');
|
||||
numValueField.typedInput('show');
|
||||
typeValueField.typedInput('hide');
|
||||
valueField.typedInput('hide');
|
||||
} else if (type === "jsonata_exp") {
|
||||
btwnValueField.typedInput('hide');
|
||||
btwnValue2Field.typedInput('hide');
|
||||
expValueField.typedInput('show');
|
||||
numValueField.typedInput('hide');
|
||||
typeValueField.typedInput('hide');
|
||||
valueField.typedInput('hide');
|
||||
} else {
|
||||
btwnValueField.typedInput('hide');
|
||||
expValueField.typedInput('hide');
|
||||
numValueField.typedInput('hide');
|
||||
typeValueField.typedInput('hide');
|
||||
valueField.typedInput('hide');
|
||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
||||
valueField.typedInput('hide');
|
||||
typeValueField.typedInput('hide');
|
||||
}
|
||||
else
|
||||
if (type === "istype") {
|
||||
valueField.typedInput('hide');
|
||||
typeValueField.typedInput('show');
|
||||
}
|
||||
else {
|
||||
typeValueField.typedInput('hide');
|
||||
} else {
|
||||
valueField.typedInput('show');
|
||||
}
|
||||
}
|
||||
@@ -316,9 +287,6 @@
|
||||
} else if ((rule.t === "head") || (rule.t === "tail")) {
|
||||
numValueField.typedInput('value',rule.v);
|
||||
numValueField.typedInput('type',rule.vt||'num');
|
||||
} else if (rule.t === "istype") {
|
||||
typeValueField.typedInput('value',rule.vt);
|
||||
typeValueField.typedInput('type',rule.vt);
|
||||
} else if (rule.t === "jsonata_exp") {
|
||||
expValueField.typedInput('value',rule.v);
|
||||
expValueField.typedInput('type',rule.vt||'jsonata');
|
||||
@@ -391,9 +359,6 @@
|
||||
} else if ((type === "head") || (type === "tail")) {
|
||||
r.v = rule.find(".node-input-rule-num-value").typedInput('value');
|
||||
r.vt = rule.find(".node-input-rule-num-value").typedInput('type');
|
||||
} else if (type === "istype") {
|
||||
r.v = rule.find(".node-input-rule-type-value").typedInput('type');
|
||||
r.vt = rule.find(".node-input-rule-type-value").typedInput('type');
|
||||
} else if (type === "jsonata_exp") {
|
||||
r.v = rule.find(".node-input-rule-exp-value").typedInput('value');
|
||||
r.vt = rule.find(".node-input-rule-exp-value").typedInput('type');
|
||||
|
||||
@@ -31,16 +31,6 @@ module.exports = function(RED) {
|
||||
'false': function(a) { return a === false; },
|
||||
'null': function(a) { return (typeof a == "undefined" || a === null); },
|
||||
'nnull': function(a) { return (typeof a != "undefined" && a !== null); },
|
||||
'istype': function(a, b) {
|
||||
if (b === "array") { return Array.isArray(a); }
|
||||
else if (b === "buffer") { return Buffer.isBuffer(a); }
|
||||
else if (b === "json") {
|
||||
try { JSON.parse(a); return true; } // or maybe ??? a !== null; }
|
||||
catch(e) { return false;}
|
||||
}
|
||||
else if (b === "null") { return a === null; }
|
||||
else { return typeof a === b && !Array.isArray(a) && !Buffer.isBuffer(a) && a !== null; }
|
||||
},
|
||||
'head': function(a, b, c, d, parts) {
|
||||
var count = Number(b);
|
||||
return (parts.index < count);
|
||||
@@ -302,10 +292,6 @@ module.exports = function(RED) {
|
||||
node.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||
return;
|
||||
}
|
||||
} else if (rule.vt === 'json') {
|
||||
v1 = "json";
|
||||
} else if (rule.vt === 'null') {
|
||||
v1 = "null";
|
||||
} else {
|
||||
try {
|
||||
v1 = RED.util.evaluateNodeProperty(rule.v,rule.vt,node,msg);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<script type="text/x-red" data-template-name="html">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%">
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tag"><i class="fa fa-filter"></i> <span data-i18n="html.label.select"></span></label>
|
||||
@@ -24,10 +24,6 @@
|
||||
<option value="multi" data-i18n="html.format.multi"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-outproperty"> </label>
|
||||
<span data-i18n="html.label.in" style="padding-left:8px; padding-right:2px; vertical-align:-1px;"></span> <input type="text" id="node-input-outproperty" style="width:64%">
|
||||
</div>
|
||||
<br/>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
@@ -63,7 +59,6 @@
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload"},
|
||||
outproperty: {value:"payload"},
|
||||
tag: {value:""},
|
||||
ret: {value:"html"},
|
||||
as: {value:"single"}
|
||||
@@ -79,7 +74,6 @@
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-property").typedInput({default:'msg',types:['msg']});
|
||||
$("#node-input-outproperty").typedInput({default:'msg',types:['msg']});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -21,7 +21,6 @@ module.exports = function(RED) {
|
||||
function CheerioNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.property = n.property||"payload";
|
||||
this.outproperty = n.outproperty||this.property||"payload";
|
||||
this.tag = n.tag;
|
||||
this.ret = n.ret || "html";
|
||||
this.as = n.as || "single";
|
||||
@@ -49,7 +48,7 @@ module.exports = function(RED) {
|
||||
/* istanbul ignore else */
|
||||
if (pay2) {
|
||||
var new_msg = RED.util.cloneMessage(msg);
|
||||
RED.util.setMessageProperty(new_msg,node.outproperty,pay2);
|
||||
RED.util.setMessageProperty(new_msg,node.property,pay2);
|
||||
new_msg.parts = {
|
||||
id: msg._msgid,
|
||||
index: index,
|
||||
@@ -69,7 +68,7 @@ module.exports = function(RED) {
|
||||
index++;
|
||||
});
|
||||
if (node.as === "single") { // Always return an array - even if blank
|
||||
RED.util.setMessageProperty(msg,node.outproperty,pay);
|
||||
RED.util.setMessageProperty(msg,node.property,pay);
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
223
package.json
223
package.json
@@ -1,117 +1,114 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.18.7",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"main": "red/red.js",
|
||||
"scripts": {
|
||||
"start": "node red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build"
|
||||
},
|
||||
"bin": {
|
||||
"node-red": "./red.js",
|
||||
"node-red-pi": "bin/node-red-pi"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
"name": "node-red",
|
||||
"version": "0.18.4",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
"main": "red/red.js",
|
||||
"scripts": {
|
||||
"start": "node red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build"
|
||||
},
|
||||
"bin": {
|
||||
"node-red": "./red.js",
|
||||
"node-red-pi": "bin/node-red-pi"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"editor",
|
||||
"messaging",
|
||||
"iot",
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"basic-auth": "2.0.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.2",
|
||||
"cheerio": "0.22.0",
|
||||
"clone": "2.1.1",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.3.0",
|
||||
"express": "4.16.2",
|
||||
"express-session": "1.15.6",
|
||||
"follow-redirects": "1.3.0",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"i18next": "1.10.6",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.10.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.0",
|
||||
"media-typer": "0.3.0",
|
||||
"memorystore": "1.6.0",
|
||||
"mqtt": "2.15.1",
|
||||
"multer": "1.3.0",
|
||||
"mustache": "2.3.0",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "0.1.*",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-twitter": "0.1.*",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.2",
|
||||
"semver": "5.4.1",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.3.6",
|
||||
"when": "3.7.8",
|
||||
"ws": "1.1.5",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chromedriver": "^2.33.2",
|
||||
"grunt": "~1.0.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.2.0",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.3.0",
|
||||
"grunt-contrib-watch": "~1.0.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"istanbul": "0.4.5",
|
||||
"mocha": "~3.4.2",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"supertest": "3.0.0",
|
||||
"wdio-chromedriver-service": "^0.1.1",
|
||||
"wdio-mocha-framework": "^0.5.11",
|
||||
"wdio-spec-reporter": "^0.1.3",
|
||||
"webdriverio": "^4.9.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"editor",
|
||||
"messaging",
|
||||
"iot",
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"basic-auth": "2.0.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"cheerio": "0.22.0",
|
||||
"clone": "2.1.1",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.3.0",
|
||||
"express": "4.16.3",
|
||||
"express-session": "1.15.6",
|
||||
"follow-redirects": "1.4.1",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"i18next": "1.10.6",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.11.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.4",
|
||||
"media-typer": "0.3.0",
|
||||
"memorystore": "1.6.0",
|
||||
"mqtt": "2.18.0",
|
||||
"multer": "1.3.0",
|
||||
"mustache": "2.3.0",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "0.1.*",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-twitter": "*",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.3",
|
||||
"semver": "5.5.0",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.3.25",
|
||||
"when": "3.7.8",
|
||||
"ws": "1.1.5",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "~1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chromedriver": "^2.33.2",
|
||||
"grunt": "~1.0.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.2.0",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.3.0",
|
||||
"grunt-contrib-watch": "~1.0.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"http-proxy": "^1.16.2",
|
||||
"istanbul": "0.4.5",
|
||||
"mocha": "^5.1.1",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.0.6",
|
||||
"supertest": "3.0.0",
|
||||
"wdio-chromedriver-service": "^0.1.1",
|
||||
"wdio-mocha-framework": "^0.5.11",
|
||||
"wdio-spec-reporter": "^0.1.3",
|
||||
"webdriverio": "^4.9.11",
|
||||
"node-red-node-test-helper": "^0.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
}
|
||||
|
||||
30
red.js
30
red.js
@@ -31,8 +31,10 @@ var app = express();
|
||||
|
||||
var settingsFile;
|
||||
var flowFile;
|
||||
var readonly;
|
||||
|
||||
var knownOpts = {
|
||||
"credentialSecret": String,
|
||||
"help": Boolean,
|
||||
"port": Number,
|
||||
"settings": [path],
|
||||
@@ -41,6 +43,7 @@ var knownOpts = {
|
||||
"verbose": Boolean
|
||||
};
|
||||
var shortHands = {
|
||||
"k":["--credentialSecret"],
|
||||
"?":["--help"],
|
||||
"p":["--port"],
|
||||
"s":["--settings"],
|
||||
@@ -59,9 +62,11 @@ var parsedArgs = nopt(knownOpts,shortHands,process.argv,2)
|
||||
if (parsedArgs.help) {
|
||||
console.log("Node-RED v"+RED.version());
|
||||
console.log("Usage: node-red [-v] [-?] [--settings settings.js] [--userDir DIR]");
|
||||
console.log(" [--port PORT] [--title TITLE] [flows.json]");
|
||||
console.log(" [--port PORT] [--credentialSecret SECRET_KEY]");
|
||||
console.log(" [--title TITLE] [flows.json]");
|
||||
console.log("");
|
||||
console.log("Options:");
|
||||
console.log(" -k, --credentialSecret SECRET_KEY key to unlock credentials file");
|
||||
console.log(" -p, --port PORT port to listen on");
|
||||
console.log(" -s, --settings FILE use specified settings file");
|
||||
console.log(" --title TITLE process window title");
|
||||
@@ -101,8 +106,15 @@ if (parsedArgs.settings) {
|
||||
var settingsStat = fs.statSync(defaultSettings);
|
||||
if (settingsStat.mtime.getTime() <= settingsStat.ctime.getTime()) {
|
||||
// Default settings file has not been modified - safe to copy
|
||||
fs.copySync(defaultSettings,userSettingsFile);
|
||||
settingsFile = userSettingsFile;
|
||||
try {
|
||||
fs.copySync(defaultSettings,userSettingsFile);
|
||||
settingsFile = userSettingsFile;
|
||||
}
|
||||
catch (err) {
|
||||
console.log("Can't copy settings file.");
|
||||
settingsFile = defaultSettings;
|
||||
readonly = true;
|
||||
}
|
||||
} else {
|
||||
// Use default settings.js as it has been modified
|
||||
settingsFile = defaultSettings;
|
||||
@@ -114,6 +126,10 @@ if (parsedArgs.settings) {
|
||||
try {
|
||||
var settings = require(settingsFile);
|
||||
settings.settingsFile = settingsFile;
|
||||
if (readonly === true) {
|
||||
console.log("Setting to read Only mode.");
|
||||
settings.readOnly = true;
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("Error loading settings file: "+settingsFile)
|
||||
if (err.code == 'MODULE_NOT_FOUND') {
|
||||
@@ -126,6 +142,10 @@ try {
|
||||
process.exit();
|
||||
}
|
||||
|
||||
if (parsedArgs.credentialSecret) {
|
||||
settings.credentialSecret = parsedArgs.credentialSecret;
|
||||
}
|
||||
|
||||
if (parsedArgs.verbose) {
|
||||
settings.verbose = true;
|
||||
}
|
||||
@@ -192,7 +212,7 @@ try {
|
||||
if (err.code == "unsupported_version") {
|
||||
console.log("Unsupported version of node.js:",process.version);
|
||||
console.log("Node-RED requires node.js v4 or later");
|
||||
} else if (err.code == "not_built") {
|
||||
} else if (err.code == "not_built") {
|
||||
console.log("Node-RED has not been built. See README.md for details");
|
||||
} else {
|
||||
console.log("Failed to start server:");
|
||||
@@ -276,7 +296,7 @@ function getListenPath() {
|
||||
}
|
||||
|
||||
var listenPath = 'http'+(settings.https?'s':'')+'://'+
|
||||
(settings.uiHost == '::'?'localhost':(settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost))+
|
||||
(settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost)+
|
||||
':'+port;
|
||||
if (settings.httpAdminRoot !== false) {
|
||||
listenPath += settings.httpAdminRoot;
|
||||
|
||||
@@ -86,10 +86,6 @@ function init(config) {
|
||||
} else {
|
||||
api.authenticate = authenticate;
|
||||
}
|
||||
} else {
|
||||
api.get = get;
|
||||
api.authenticate = authenticate;
|
||||
api.default = api.default;
|
||||
}
|
||||
if (config.default) {
|
||||
if (typeof config.default === "function") {
|
||||
|
||||
@@ -91,9 +91,7 @@
|
||||
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
||||
"credentials_load_failed_reset":"<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
||||
"missing_flow_file": "<p>Project flow file not found.</p><p>The project is not configured with a flow file.</p>",
|
||||
"missing_package_file": "<p>Project package file not found.</p><p>The project is missing a package.json file.</p>",
|
||||
"project_empty": "<p>The project is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>",
|
||||
"project_not_found": "<p>Project '__project__' not found.</p>",
|
||||
"git_merge_conflict": "<p>Automatic merging of changes failed.</p><p>Fix the unmerged conflicts then commit the results.</p>"
|
||||
@@ -106,8 +104,7 @@
|
||||
"lostConnectionTry": "Try now",
|
||||
"cannotAddSubflowToItself": "Cannot add subflow to itself",
|
||||
"cannotAddCircularReference": "Cannot add subflow - circular reference detected",
|
||||
"unsupportedVersion": "<p>Using an unsupported version of Node.js</p><p>You should upgrade to the latest Node.js LTS release</p>",
|
||||
"failedToAppendNode": "<p>Failed to load '__module__'</p><p>__error__</p>"
|
||||
"unsupportedVersion": "Using an unsupported version of Node.js<br/>You should upgrade to the latest Node.js LTS release"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
|
||||
@@ -28,16 +28,8 @@ module.exports = {
|
||||
runtimeSettings: function(req,res) {
|
||||
var safeSettings = {
|
||||
httpNodeRoot: settings.httpNodeRoot||"/",
|
||||
version: settings.version
|
||||
}
|
||||
if (req.user) {
|
||||
safeSettings.user = {}
|
||||
var props = ["anonymous","username","image","permissions"];
|
||||
props.forEach(prop => {
|
||||
if (req.user.hasOwnProperty(prop)) {
|
||||
safeSettings.user[prop] = req.user[prop];
|
||||
}
|
||||
})
|
||||
version: settings.version,
|
||||
user: req.user
|
||||
}
|
||||
|
||||
var themeSettings = theme.settings();
|
||||
@@ -96,19 +88,13 @@ module.exports = {
|
||||
}
|
||||
var currentSettings = settings.getUserSettings(username)||{};
|
||||
currentSettings = extend(currentSettings, req.body);
|
||||
try {
|
||||
settings.setUserSettings(username, currentSettings).then(function() {
|
||||
log.audit({event: "settings.update",username:username},req);
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()},req);
|
||||
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
|
||||
});
|
||||
} catch(err) {
|
||||
log.warn(log._("settings.user-not-available",{message:log._("settings.not-available")}));
|
||||
settings.setUserSettings(username, currentSettings).then(function() {
|
||||
log.audit({event: "settings.update",username:username},req);
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()},req);
|
||||
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"user-not-available": "Cannot save user settings: __message__",
|
||||
"not-available": "Settings not available",
|
||||
"property-read-only": "Property '__prop__' is read-only"
|
||||
},
|
||||
|
||||
@@ -225,12 +225,6 @@ function log_helper(self, level, msg) {
|
||||
type: self.type,
|
||||
msg: msg
|
||||
};
|
||||
if (self._alias) {
|
||||
o._alias = self._alias;
|
||||
}
|
||||
if (self.z) {
|
||||
o.z = self.z;
|
||||
}
|
||||
if (self.name) {
|
||||
o.name = self.name;
|
||||
}
|
||||
|
||||
@@ -236,8 +236,8 @@ function Flow(global,flow) {
|
||||
|
||||
this.handleError = function(node,logMessage,msg) {
|
||||
var count = 1;
|
||||
if (msg && msg.hasOwnProperty("error") && msg.error !== null) {
|
||||
if (msg.error.hasOwnProperty("source") && msg.error.source !== null) {
|
||||
if (msg && msg.hasOwnProperty("error")) {
|
||||
if (msg.error.hasOwnProperty("source")) {
|
||||
if (msg.error.source.id === node.id) {
|
||||
count = msg.error.source.count+1;
|
||||
if (count === 10) {
|
||||
|
||||
@@ -37,7 +37,6 @@ var activeFlowConfig = null;
|
||||
|
||||
var activeFlows = {};
|
||||
var started = false;
|
||||
var credentialsPendingReset = false;
|
||||
|
||||
var activeNodesToFlow = {};
|
||||
var subflowInstanceNodeMap = {};
|
||||
@@ -71,31 +70,21 @@ function init(runtime) {
|
||||
}
|
||||
|
||||
function loadFlows() {
|
||||
var config;
|
||||
return storage.getFlows().then(function(_config) {
|
||||
config = _config;
|
||||
return storage.getFlows().then(function(config) {
|
||||
log.debug("loaded flow revision: "+config.rev);
|
||||
return credentials.load(config.credentials).then(function() {
|
||||
events.emit("runtime-event",{id:"runtime-state",retain:true});
|
||||
return config;
|
||||
});
|
||||
}).catch(function(err) {
|
||||
if (err.code === "credentials_load_failed" && !storage.projects) {
|
||||
// project disabled, credential load failed
|
||||
credentialsPendingReset = true;
|
||||
log.warn(log._("nodes.flows.error",{message:err.toString()}));
|
||||
events.emit("runtime-event",{id:"runtime-state",payload:{type:"warning",error:err.code,text:"notification.warnings.credentials_load_failed_reset"},retain:true});
|
||||
return config;
|
||||
activeConfig = null;
|
||||
events.emit("runtime-event",{id:"runtime-state",payload:{type:"warning",error:err.code,project:err.project,text:"notification.warnings."+err.code},retain:true});
|
||||
if (err.code === "project_not_found") {
|
||||
log.warn(log._("storage.localfilesystem.projects.project-not-found",{project:err.project}));
|
||||
} else {
|
||||
activeConfig = null;
|
||||
events.emit("runtime-event",{id:"runtime-state",payload:{type:"warning",error:err.code,project:err.project,text:"notification.warnings."+err.code},retain:true});
|
||||
if (err.code === "project_not_found") {
|
||||
log.warn(log._("storage.localfilesystem.projects.project-not-found",{project:err.project}));
|
||||
} else {
|
||||
log.warn(log._("nodes.flows.error",{message:err.toString()}));
|
||||
}
|
||||
throw err;
|
||||
log.warn(log._("nodes.flows.error",{message:err.toString()}));
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
function load(forceStart) {
|
||||
@@ -127,15 +116,6 @@ function setFlows(_config,type,muteLog,forceStart) {
|
||||
config = clone(_config);
|
||||
newFlowConfig = flowUtil.parseConfig(clone(config));
|
||||
diff = flowUtil.diffConfigs(activeFlowConfig,newFlowConfig);
|
||||
|
||||
// Now the flows have been compared, remove any credentials from newFlowConfig
|
||||
// so they don't cause false-positive diffs the next time a flow is deployed
|
||||
for (var id in newFlowConfig.allNodes) {
|
||||
if (newFlowConfig.allNodes.hasOwnProperty(id)) {
|
||||
delete newFlowConfig.allNodes[id].credentials;
|
||||
}
|
||||
}
|
||||
|
||||
credentials.clean(config);
|
||||
var credsDirty = credentials.dirty();
|
||||
configSavePromise = credentials.export().then(function(creds) {
|
||||
@@ -337,12 +317,7 @@ function start(type,diff,muteLog) {
|
||||
}
|
||||
}
|
||||
events.emit("nodes-started");
|
||||
|
||||
if (credentialsPendingReset === true) {
|
||||
credentialsPendingReset = false;
|
||||
} else {
|
||||
events.emit("runtime-event",{id:"runtime-state",retain:true});
|
||||
}
|
||||
events.emit("runtime-event",{id:"runtime-state",retain:true});
|
||||
|
||||
if (!muteLog) {
|
||||
if (type !== "full") {
|
||||
|
||||
@@ -426,7 +426,6 @@ function getAllNodeConfigs(lang) {
|
||||
var id = nodeList[i];
|
||||
var config = moduleConfigs[getModule(id)].nodes[getNode(id)];
|
||||
if (config.enabled && !config.err) {
|
||||
result += "\n<!-- --- [red-module:"+id+"] --- -->\n";
|
||||
result += config.config;
|
||||
result += loader.getNodeHelp(config,lang||"en-US")||"";
|
||||
//script += config.script;
|
||||
@@ -449,7 +448,7 @@ function getNodeConfig(id,lang) {
|
||||
}
|
||||
config = config.nodes[getNode(id)];
|
||||
if (config) {
|
||||
var result = "<!-- --- [red-module:"+id+"] --- -->\n"+config.config;
|
||||
var result = config.config;
|
||||
result += loader.getNodeHelp(config,lang||"en-US")
|
||||
|
||||
//if (config.script) {
|
||||
|
||||
@@ -173,9 +173,6 @@ var persistentSettings = {
|
||||
return clone(userSettings[username]);
|
||||
},
|
||||
setUserSettings: function(username,settings) {
|
||||
if (globalSettings === null) {
|
||||
throw new Error(log._("settings.not-available"));
|
||||
}
|
||||
var current = userSettings[username];
|
||||
userSettings[username] = settings;
|
||||
try {
|
||||
|
||||
@@ -53,13 +53,15 @@ function getGitUser(user) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function Project(path) {
|
||||
this.path = path;
|
||||
this.name = fspath.basename(path);
|
||||
function Project(name) {
|
||||
this.name = name;
|
||||
this.path = fspath.join(projectsDir,name);
|
||||
this.paths = {};
|
||||
this.files = {};
|
||||
this.auth = {origin:{}};
|
||||
|
||||
this.missingFiles = [];
|
||||
|
||||
this.credentialSecret = null;
|
||||
}
|
||||
Project.prototype.load = function () {
|
||||
@@ -68,9 +70,7 @@ Project.prototype.load = function () {
|
||||
// console.log(globalProjectSettings)
|
||||
var projectSettings = {};
|
||||
if (globalProjectSettings) {
|
||||
if (globalProjectSettings.projects.hasOwnProperty(this.name)) {
|
||||
projectSettings = globalProjectSettings.projects[this.name] || {};
|
||||
}
|
||||
projectSettings = globalProjectSettings.projects[this.name]||{};
|
||||
}
|
||||
|
||||
this.credentialSecret = projectSettings.credentialSecret;
|
||||
@@ -81,7 +81,9 @@ Project.prototype.load = function () {
|
||||
|
||||
var promises = [];
|
||||
return checkProjectFiles(project).then(function(missingFiles) {
|
||||
project.missingFiles = missingFiles;
|
||||
if (missingFiles.length > 0) {
|
||||
project.missingFiles = missingFiles;
|
||||
}
|
||||
if (missingFiles.indexOf('package.json') === -1) {
|
||||
project.paths['package.json'] = fspath.join(project.path,"package.json");
|
||||
promises.push(fs.readFile(project.paths['package.json'],"utf8").then(function(content) {
|
||||
@@ -133,9 +135,9 @@ Project.prototype.load = function () {
|
||||
|
||||
Project.prototype.initialise = function(user,data) {
|
||||
var project = this;
|
||||
// if (!this.empty) {
|
||||
// throw new Error("Cannot initialise non-empty project");
|
||||
// }
|
||||
if (!this.empty) {
|
||||
throw new Error("Cannot initialise non-empty project");
|
||||
}
|
||||
var files = Object.keys(defaultFileSet);
|
||||
var promises = [];
|
||||
|
||||
@@ -146,25 +148,17 @@ Project.prototype.initialise = function(user,data) {
|
||||
promises.push(settings.set('projects',projects));
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty('files')) {
|
||||
if (data.files.hasOwnProperty('flow') && data.files.hasOwnProperty('credentials')) {
|
||||
project.files.flow = data.files.flow;
|
||||
project.files.credentials = data.files.credentials;
|
||||
var flowFilePath = fspath.join(project.path,project.files.flow);
|
||||
var credsFilePath = getCredentialsFilename(flowFilePath);
|
||||
promises.push(util.writeFile(flowFilePath,"[]"));
|
||||
promises.push(util.writeFile(credsFilePath,"{}"));
|
||||
files.push(project.files.flow);
|
||||
files.push(project.files.credentials);
|
||||
}
|
||||
}
|
||||
project.files.flow = data.files.flow;
|
||||
project.files.credentials = data.files.credentials;
|
||||
var flowFilePath = fspath.join(project.path,project.files.flow);
|
||||
var credsFilePath = getCredentialsFilename(flowFilePath);
|
||||
promises.push(util.writeFile(flowFilePath,"[]"));
|
||||
promises.push(util.writeFile(credsFilePath,"{}"));
|
||||
files.push(project.files.flow);
|
||||
files.push(project.files.credentials);
|
||||
for (var file in defaultFileSet) {
|
||||
if (defaultFileSet.hasOwnProperty(file)) {
|
||||
var path = fspath.join(project.path,file);
|
||||
if (!fs.existsSync(path)) {
|
||||
promises.push(util.writeFile(path,defaultFileSet[file](project)));
|
||||
}
|
||||
|
||||
promises.push(util.writeFile(fspath.join(project.path,file),defaultFileSet[file](project)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,10 +276,12 @@ Project.prototype.update = function (user, data) {
|
||||
saveREADME = true;
|
||||
this.description = data.description;
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty('dependencies')) {
|
||||
savePackage = true;
|
||||
this.package.dependencies = data.dependencies;
|
||||
}
|
||||
|
||||
if (data.hasOwnProperty('summary')) {
|
||||
savePackage = true;
|
||||
this.package.description = data.summary;
|
||||
@@ -338,6 +334,7 @@ Project.prototype.update = function (user, data) {
|
||||
if (data.files.hasOwnProperty('flow') && this.package['node-red'].settings.flowFile !== data.files.flow) {
|
||||
this.paths.flowFile = data.files.flow;
|
||||
this.package['node-red'].settings.flowFile = data.files.flow;
|
||||
this.package.scripts = {"start":"node-red -u . " + data.files.flow};
|
||||
savePackage = true;
|
||||
flowFilesChanged = true;
|
||||
}
|
||||
@@ -746,7 +743,7 @@ Project.prototype.getCredentialsFileBackup = function() {
|
||||
return getBackupFilename(this.getCredentialsFile());
|
||||
}
|
||||
|
||||
Project.prototype.export = function () {
|
||||
Project.prototype.toJSON = function () {
|
||||
|
||||
return {
|
||||
name: this.name,
|
||||
@@ -786,18 +783,28 @@ function getBackupFilename(filename) {
|
||||
return fspath.join(ffDir,"."+ffName+".backup");
|
||||
}
|
||||
|
||||
function checkProjectExists(projectPath) {
|
||||
function checkProjectExists(project) {
|
||||
var projectPath = fspath.join(projectsDir,project);
|
||||
return fs.pathExists(projectPath).then(function(exists) {
|
||||
if (!exists) {
|
||||
var e = new Error("Project not found");
|
||||
var e = new Error("Project not found: "+project);
|
||||
e.code = "project_not_found";
|
||||
var name = fspath.basename(projectPath);
|
||||
e.project = name;
|
||||
e.project = project;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createProjectDirectory(project) {
|
||||
var projectPath = fspath.join(projectsDir,project);
|
||||
return fs.ensureDir(projectPath);
|
||||
}
|
||||
|
||||
function deleteProjectDirectory(project) {
|
||||
var projectPath = fspath.join(projectsDir,project);
|
||||
return fs.remove(projectPath);
|
||||
}
|
||||
|
||||
function createDefaultProject(user, project) {
|
||||
var projectPath = fspath.join(projectsDir,project.name);
|
||||
// Create a basic skeleton of a project
|
||||
@@ -900,23 +907,17 @@ function createProject(user, metadata) {
|
||||
} else {
|
||||
username = user.username;
|
||||
}
|
||||
if (!metadata.path) {
|
||||
throw new Error("Project missing path property");
|
||||
}
|
||||
if (!metadata.name) {
|
||||
throw new Error("Project missing name property");
|
||||
}
|
||||
|
||||
var project = metadata.name;
|
||||
var projectPath = metadata.path;
|
||||
return new Promise(function(resolve,reject) {
|
||||
var projectPath = fspath.join(projectsDir,project);
|
||||
fs.stat(projectPath, function(err,stat) {
|
||||
if (!err) {
|
||||
var e = new Error("NLS: Project already exists");
|
||||
e.code = "project_exists";
|
||||
return reject(e);
|
||||
}
|
||||
fs.ensureDir(projectPath).then(function() {
|
||||
createProjectDirectory(project).then(function() {
|
||||
var projects = settings.get('projects');
|
||||
if (!projects) {
|
||||
projects = {
|
||||
@@ -953,7 +954,7 @@ function createProject(user, metadata) {
|
||||
return createDefaultProject(user, metadata);
|
||||
}
|
||||
}).then(function() {
|
||||
resolve(loadProject(projectPath))
|
||||
resolve(getProject(project))
|
||||
}).catch(function(err) {
|
||||
fs.remove(projectPath,function() {
|
||||
reject(err);
|
||||
@@ -963,21 +964,50 @@ function createProject(user, metadata) {
|
||||
})
|
||||
}
|
||||
|
||||
function deleteProject(user, projectPath) {
|
||||
return checkProjectExists(projectPath).then(function() {
|
||||
return fs.remove(projectPath).then(function() {
|
||||
var name = fspath.basename(projectPath);
|
||||
var projects = settings.get('projects');
|
||||
delete projects.projects[name];
|
||||
return settings.set('projects', projects);
|
||||
});
|
||||
function deleteProject(user, name) {
|
||||
return checkProjectExists(name).then(function() {
|
||||
if (currentProject && currentProject.name === name) {
|
||||
var e = new Error("NLS: Can't delete the active project");
|
||||
e.code = "cannot_delete_active_project";
|
||||
throw e;
|
||||
}
|
||||
else {
|
||||
return deleteProjectDirectory(name).then(function() {
|
||||
var projects = settings.get('projects');
|
||||
delete projects.projects[name];
|
||||
return settings.set('projects', projects);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadProject(projectPath) {
|
||||
return checkProjectExists(projectPath).then(function() {
|
||||
var project = new Project(projectPath);
|
||||
return project.load();
|
||||
var currentProject;
|
||||
|
||||
function getProject(name) {
|
||||
return checkProjectExists(name).then(function() {
|
||||
if (currentProject && currentProject.name === name) {
|
||||
return currentProject;
|
||||
}
|
||||
currentProject = new Project(name);
|
||||
return currentProject.load();
|
||||
});
|
||||
}
|
||||
|
||||
function listProjects() {
|
||||
return fs.readdir(projectsDir).then(function(fns) {
|
||||
var dirs = [];
|
||||
fns.sort(function(A,B) {
|
||||
return A.toLowerCase().localeCompare(B.toLowerCase());
|
||||
}).filter(function(fn) {
|
||||
var fullPath = fspath.join(projectsDir,fn);
|
||||
if (fn[0] != ".") {
|
||||
var stats = fs.lstatSync(fullPath);
|
||||
if (stats.isDirectory()) {
|
||||
dirs.push(fn);
|
||||
}
|
||||
}
|
||||
});
|
||||
return dirs;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -991,7 +1021,9 @@ function init(_settings, _runtime) {
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
load: loadProject,
|
||||
get: getProject,
|
||||
create: createProject,
|
||||
delete: deleteProject
|
||||
delete: deleteProject,
|
||||
list: listProjects
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ module.exports = {
|
||||
"node-red": {
|
||||
"settings": {
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {}
|
||||
};
|
||||
if (project.files) {
|
||||
if (project.files.flow) {
|
||||
@@ -43,5 +44,5 @@ module.exports = {
|
||||
|
||||
return content;
|
||||
},
|
||||
".gitignore": function() { return "*.backup" ;}
|
||||
".gitignore": function() { return "*.backup\n.config.json\n" ;}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@ function runGitCommand(args,cwd,env) {
|
||||
var err = new Error(stderr);
|
||||
err.stdout = stdout;
|
||||
err.stderr = stderr;
|
||||
if(/Connection refused/i.test(stderr)) {
|
||||
err.code = "git_connection_failed";
|
||||
} else if (/fatal: could not read/i.test(stderr)) {
|
||||
if (/fatal: could not read/i.test(stderr)) {
|
||||
// Username/Password
|
||||
err.code = "git_auth_failed";
|
||||
} else if(/HTTP Basic: Access denied/i.test(stderr)) {
|
||||
@@ -60,6 +58,8 @@ function runGitCommand(args,cwd,env) {
|
||||
} else if(/Host key verification failed/i.test(stderr)) {
|
||||
// TODO: handle host key verification errors separately
|
||||
err.code = "git_auth_failed";
|
||||
} else if(/Connection refused/i.test(stderr)) {
|
||||
err.code = "git_connection_failed";
|
||||
} else if (/commit your changes or stash/i.test(stderr)) {
|
||||
err.code = "git_local_overwrite";
|
||||
} else if (/CONFLICT/.test(err.stdout)) {
|
||||
|
||||
@@ -127,20 +127,10 @@ function init(_settings, _runtime) {
|
||||
activeProject = globalSettings.projects.activeProject;
|
||||
}
|
||||
if (settings.flowFile) {
|
||||
// if flowFile is a known project name - use it
|
||||
if (globalSettings.projects.projects.hasOwnProperty(settings.flowFile)) {
|
||||
activeProject = settings.flowFile;
|
||||
globalSettings.projects.activeProject = settings.flowFile;
|
||||
saveSettings = true;
|
||||
} else {
|
||||
// if it resolves to a dir - use it... but:
|
||||
// - where to get credsecret from?
|
||||
// - what if the name clashes with a known project?
|
||||
|
||||
// var stat = fs.statSync(settings.flowFile);
|
||||
// if (stat && stat.isDirectory()) {
|
||||
// activeProject = settings.flowFile;
|
||||
// }
|
||||
}
|
||||
}
|
||||
if (!activeProject) {
|
||||
@@ -158,24 +148,6 @@ function init(_settings, _runtime) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function listProjects() {
|
||||
return fs.readdir(projectsDir).then(function(fns) {
|
||||
var dirs = [];
|
||||
fns.sort(function(A,B) {
|
||||
return A.toLowerCase().localeCompare(B.toLowerCase());
|
||||
}).filter(function(fn) {
|
||||
var fullPath = fspath.join(projectsDir,fn);
|
||||
if (fn[0] != ".") {
|
||||
var stats = fs.lstatSync(fullPath);
|
||||
if (stats.isDirectory()) {
|
||||
dirs.push(fn);
|
||||
}
|
||||
}
|
||||
});
|
||||
return dirs;
|
||||
});
|
||||
}
|
||||
|
||||
function getUserGitSettings(user) {
|
||||
var userSettings = settings.getUserSettings(user)||{};
|
||||
return userSettings.git;
|
||||
@@ -188,11 +160,7 @@ function getBackupFilename(filename) {
|
||||
}
|
||||
|
||||
function loadProject(name) {
|
||||
var projectPath = name;
|
||||
if (projectPath.indexOf(fspath.sep) === -1) {
|
||||
projectPath = fspath.join(projectsDir,name);
|
||||
}
|
||||
return Projects.load(projectPath).then(function(project) {
|
||||
return Projects.get(name).then(function(project) {
|
||||
activeProject = project;
|
||||
flowsFullPath = project.getFlowFile();
|
||||
flowsFileBackup = project.getFlowFileBackup();
|
||||
@@ -202,20 +170,26 @@ function loadProject(name) {
|
||||
})
|
||||
}
|
||||
|
||||
function listProjects(user) {
|
||||
return Projects.list();
|
||||
}
|
||||
|
||||
function getProject(user, name) {
|
||||
checkActiveProject(name);
|
||||
//return when.resolve(activeProject.info);
|
||||
return Promise.resolve(activeProject.export());
|
||||
var username;
|
||||
if (!user) {
|
||||
username = "_";
|
||||
} else {
|
||||
username = user.username;
|
||||
}
|
||||
return Projects.get(name).then(function(project) {
|
||||
return project.toJSON();
|
||||
});
|
||||
}
|
||||
|
||||
function deleteProject(user, name) {
|
||||
if (activeProject && activeProject.name === name) {
|
||||
var e = new Error("NLS: Can't delete the active project");
|
||||
e.code = "cannot_delete_active_project";
|
||||
throw e;
|
||||
}
|
||||
var projectPath = fspath.join(projectsDir,name);
|
||||
return Projects.delete(user, projectPath);
|
||||
return Projects.delete(user, name);
|
||||
}
|
||||
|
||||
function checkActiveProject(project) {
|
||||
@@ -373,7 +347,6 @@ function createProject(user, metadata) {
|
||||
metadata.files.oldCredentials = credentialsFile;
|
||||
metadata.files.credentialSecret = currentEncryptionKey;
|
||||
}
|
||||
metadata.path = fspath.join(projectsDir,metadata.name);
|
||||
return Projects.create(user, metadata).then(function(p) {
|
||||
return setActiveProject(user, p.name);
|
||||
}).then(function() {
|
||||
@@ -506,12 +479,6 @@ function getFlows() {
|
||||
error.code = "project_empty";
|
||||
return when.reject(error);
|
||||
}
|
||||
if (activeProject.missingFiles && activeProject.missingFiles.indexOf('package.json') !== -1) {
|
||||
log.warn("Project missing package.json");
|
||||
error = new Error("Project missing package.json");
|
||||
error.code = "missing_package_file";
|
||||
return when.reject(error);
|
||||
}
|
||||
if (!activeProject.getFlowFile()) {
|
||||
log.warn("Project has no flow file");
|
||||
error = new Error("Project has no flow file");
|
||||
|
||||
@@ -80,26 +80,30 @@ module.exports = {
|
||||
*/
|
||||
writeFile: function(path,content,backupPath) {
|
||||
if (backupPath) {
|
||||
if (fs.existsSync(path)) {
|
||||
fs.renameSync(path,backupPath);
|
||||
}
|
||||
}
|
||||
return when.promise(function(resolve,reject) {
|
||||
var stream = fs.createWriteStream(path);
|
||||
stream.on('open',function(fd) {
|
||||
stream.write(content,'utf8',function() {
|
||||
fs.fsync(fd,function(err) {
|
||||
if (err) {
|
||||
log.warn(log._("storage.localfilesystem.fsync-fail",{path: path, message: err.toString()}));
|
||||
}
|
||||
stream.end(resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
stream.on('error',function(err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
try {
|
||||
// console.log(path);
|
||||
// console.log(backupPath);
|
||||
fs.renameSync(path,backupPath);
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
return when.promise(function(resolve,reject) {
|
||||
var stream = fs.createWriteStream(path);
|
||||
stream.on('open',function(fd) {
|
||||
stream.write(content,'utf8',function() {
|
||||
fs.fsync(fd,function(err) {
|
||||
if (err) {
|
||||
log.warn(log._("storage.localfilesystem.fsync-fail",{path: path, message: err.toString()}));
|
||||
}
|
||||
stream.end(resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
stream.on('error',function(err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFile: readFile,
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ module.exports = {
|
||||
uiPort: process.env.PORT || 1880,
|
||||
|
||||
// By default, the Node-RED UI accepts connections on all IPv4 interfaces.
|
||||
// To listen on all IPv6 addresses, set uiHost to "::",
|
||||
// The following property can be used to listen on a specific interface. For
|
||||
// example, the following would only allow connections from the local machine.
|
||||
//uiHost: "127.0.0.1",
|
||||
@@ -233,13 +232,5 @@ module.exports = {
|
||||
// Whether or not to include audit events in the log output
|
||||
audit: false
|
||||
}
|
||||
},
|
||||
|
||||
// Customising the editor
|
||||
editorTheme: {
|
||||
projects: {
|
||||
// To enable the Projects feature, set this value to true
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var sentimentNode = require("../../../../nodes/core/analysis/72-sentiment.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('sentiment Node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('sentiment Node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var injectNode = require("../../../../nodes/core/core/20-inject.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('inject node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('inject node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var catchNode = require("../../../../nodes/core/core/25-catch.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('catch Node', function() {
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var catchNode = require("../../../../nodes/core/core/25-status.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('status Node', function() {
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var debugNode = require("../../../../nodes/core/core/58-debug.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var WebSocket = require('ws');
|
||||
|
||||
describe('debug node', function() {
|
||||
@@ -25,10 +25,6 @@ describe('debug node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
setTimeout(function() {
|
||||
done();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var linkNode = require("../../../../nodes/core/core/60-link.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('link Node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('link Node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var sinon = require("sinon");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var execNode = require("../../../../nodes/core/core/75-exec.js");
|
||||
var osType = require("os").type();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var functionNode = require("../../../../nodes/core/core/80-function.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('function node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('function node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
@@ -242,7 +238,7 @@ describe('function node', function() {
|
||||
});
|
||||
|
||||
it('should handle and log script error', function(done) {
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"var a = 1;\nretunr"}];
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"retunr"}];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
@@ -256,7 +252,7 @@ describe('function node', function() {
|
||||
msg.should.have.property('level', helper.log().ERROR);
|
||||
msg.should.have.property('id', 'n1');
|
||||
msg.should.have.property('type', 'function');
|
||||
msg.should.have.property('msg', 'ReferenceError: retunr is not defined (line 2, col 1)');
|
||||
msg.should.have.property('msg', 'ReferenceError: retunr is not defined (line 1, col 1)');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
@@ -508,22 +504,6 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should use the same Date object from outside the sandbox', function(done) {
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.get('typeTest')(new Date());return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context().global.set("typeTest",function(d) { return d instanceof Date });
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('payload', true);
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Logger', function () {
|
||||
it('should log an Info Message', function (done) {
|
||||
var flow = [{id: "n1", type: "function", wires: [["n2"]], func: "node.log('test');"}];
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var templateNode = require("../../../../nodes/core/core/80-template.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('template node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('template node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
var should = require("should");
|
||||
|
||||
var delayNode = require("../../../../nodes/core/core/89-delay.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
var GRACE_PERCENTAGE=10;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var sinon = require("sinon");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var triggerNode = require("../../../../nodes/core/core/89-trigger.js");
|
||||
var RED = require("../../../../red/red.js");
|
||||
|
||||
@@ -304,11 +304,11 @@ describe('trigger node', function() {
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
RED.util.evaluateNodeProperty.restore();
|
||||
spy.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { RED.util.evaluateNodeProperty.restore(); done(err); }
|
||||
catch(err) { spy.restore(); done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
@@ -384,7 +384,6 @@ describe('trigger node', function() {
|
||||
});
|
||||
|
||||
it('should be able to extend the delay', function(done) {
|
||||
this.timeout(5000); // add extra time for flake
|
||||
var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
|
||||
function(arg1, arg2, arg3, arg4) { return arg1; }
|
||||
);
|
||||
@@ -419,7 +418,7 @@ describe('trigger node', function() {
|
||||
});
|
||||
|
||||
it('should be able to extend the delay (but with no 2nd output)', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:"100", wires:[["n2"]] },
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:"50", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -434,7 +433,7 @@ describe('trigger node', function() {
|
||||
else {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
//console.log(Date.now() - ss);
|
||||
(Date.now() - ss).should.be.greaterThan(140);
|
||||
(Date.now() - ss).should.be.greaterThan(70);
|
||||
done();
|
||||
}
|
||||
}
|
||||
@@ -447,7 +446,7 @@ describe('trigger node', function() {
|
||||
},20);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"World"});
|
||||
},150);
|
||||
},80);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var commentNode = require("../../../../nodes/core/core/90-comment.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('comment Node', function() {
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var unknown = require("../../../../nodes/core/core/98-unknown.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('unknown Node', function() {
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
var ws = require("ws");
|
||||
var when = require("when");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var websocketNode = require("../../../../nodes/core/io/22-websocket.js");
|
||||
|
||||
var sockets = [];
|
||||
@@ -61,10 +61,6 @@ describe('websocket Node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
closeAll();
|
||||
helper.unload();
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
var fs = require("fs-extra");
|
||||
var path = require("path");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var watchNode = require("../../../../nodes/core/io/23-watch.js");
|
||||
|
||||
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
var net = require("net");
|
||||
var should = require("should");
|
||||
var stoppable = require('stoppable');
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
var helper = require("../../helper.js");
|
||||
var tcpinNode = require("../../../../nodes/core/io/31-tcpin.js");
|
||||
|
||||
|
||||
@@ -28,13 +26,20 @@ describe('TCP in Node', function() {
|
||||
var server_port = 9300;
|
||||
var reply_data = undefined;
|
||||
|
||||
before(function(done) {
|
||||
done();
|
||||
});
|
||||
|
||||
after(function() {
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
afterEach(function() {
|
||||
stopServer();
|
||||
helper.unload();
|
||||
stopServer(done);
|
||||
});
|
||||
|
||||
function sendArray(sock, array) {
|
||||
@@ -47,20 +52,20 @@ describe('TCP in Node', function() {
|
||||
sock.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function startServer(done) {
|
||||
server_port += 1;
|
||||
server = stoppable(net.createServer(function(c) {
|
||||
server = net.createServer(function(c) {
|
||||
sendArray(c, reply_data);
|
||||
})).listen(server_port, "localhost", function(err) {
|
||||
}).listen(server_port, "localhost", function(err) {
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
|
||||
function stopServer(done) {
|
||||
server.stop(done);
|
||||
function stopServer() {
|
||||
server.close();
|
||||
}
|
||||
|
||||
|
||||
function send(wdata) {
|
||||
var opt = {port:port, host:"localhost"};
|
||||
var client = net.createConnection(opt, function() {
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
var net = require("net");
|
||||
var should = require("should");
|
||||
var stoppable = require('stoppable');
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var tcpinNode = require("../../../../nodes/core/io/31-tcpin.js");
|
||||
|
||||
|
||||
@@ -27,7 +26,7 @@ describe('TCP Request Node', function() {
|
||||
|
||||
function startServer(done) {
|
||||
port += 1;
|
||||
server = stoppable(net.createServer(function(c) {
|
||||
server = net.createServer(function(c) {
|
||||
c.on('data', function(data) {
|
||||
var rdata = "ACK:"+data.toString();
|
||||
c.write(rdata);
|
||||
@@ -35,7 +34,7 @@ describe('TCP Request Node', function() {
|
||||
c.on('error', function(err) {
|
||||
startServer(done);
|
||||
});
|
||||
})).listen(port, "127.0.0.1", function(err) {
|
||||
}).listen(port, "127.0.0.1", function(err) {
|
||||
done();
|
||||
});
|
||||
}
|
||||
@@ -44,8 +43,8 @@ describe('TCP Request Node', function() {
|
||||
startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
server.stop(done);
|
||||
after(function() {
|
||||
server.close();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@@ -71,7 +70,7 @@ describe('TCP Request Node', function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
it('should send & recv data', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var dgram = require("dgram");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var udpNode = require("../../../../nodes/core/io/32-udp.js");
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ describe('UDP in Node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
after(function() {
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var dgram = require("dgram");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var udpNode = require("../../../../nodes/core/io/32-udp.js");
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ describe('UDP out Node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
after(function() {
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@@ -39,7 +38,7 @@ describe('UDP out Node', function() {
|
||||
var sock = dgram.createSocket('udp4');
|
||||
sock.on('message', function(msg, rinfo) {
|
||||
msg.should.deepEqual(data);
|
||||
sock.close(done);
|
||||
done();
|
||||
});
|
||||
sock.bind(port, '127.0.0.1');
|
||||
port++;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
var should = require("should");
|
||||
|
||||
var switchNode = require("../../../../nodes/core/logic/10-switch.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var RED = require("../../../../red/red.js");
|
||||
|
||||
describe('switch Node', function() {
|
||||
@@ -28,8 +28,8 @@ describe('switch Node', function() {
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload();
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
helper.stopServer(done);
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
});
|
||||
|
||||
it('should be loaded with some defaults', function(done) {
|
||||
@@ -103,7 +103,7 @@ describe('switch Node', function() {
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
if (shouldReceive === true) {
|
||||
should.equal(msg.payload,sendPayload);
|
||||
msg.payload.should.equal(sendPayload);
|
||||
done();
|
||||
} else {
|
||||
should.fail(null, null, "We should never get an input!");
|
||||
@@ -168,6 +168,8 @@ describe('switch Node', function() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
it('should check if payload equals given value', function(done) {
|
||||
genericSwitchTest("eq", "Hello", true, true, "Hello", done);
|
||||
});
|
||||
@@ -256,43 +258,6 @@ describe('switch Node', function() {
|
||||
genericSwitchTest("regex", "[abc]+", true, true, "abbabac", done);
|
||||
});
|
||||
|
||||
it('should check if payload if of type string ', function(done) {
|
||||
genericSwitchTest("istype", "string", true, true, "Hello", done);
|
||||
});
|
||||
it('should check if payload if of type number ', function(done) {
|
||||
genericSwitchTest("istype", "number", true, true, 999, done);
|
||||
});
|
||||
it('should check if payload if of type number 0', function(done) {
|
||||
genericSwitchTest("istype", "number", true, true, 0, done);
|
||||
});
|
||||
it('should check if payload if of type boolean true', function(done) {
|
||||
genericSwitchTest("istype", "boolean", true, true, true, done);
|
||||
});
|
||||
it('should check if payload if of type boolean false', function(done) {
|
||||
genericSwitchTest("istype", "boolean", true, true, true, done);
|
||||
});
|
||||
it('should check if payload if of type array ', function(done) {
|
||||
genericSwitchTest("istype", "array", true, true, [1,2,3,"a","b"], done);
|
||||
});
|
||||
it('should check if payload if of type buffer ', function(done) {
|
||||
genericSwitchTest("istype", "buffer", true, true, Buffer.from("Hello"), done);
|
||||
});
|
||||
it('should check if payload if of type object ', function(done) {
|
||||
genericSwitchTest("istype", "object", true, true, {a:1,b:"b",c:true}, done);
|
||||
});
|
||||
it('should check if payload if of type JSON string ', function(done) {
|
||||
genericSwitchTest("istype", "json", true, true, JSON.stringify({a:1,b:"b",c:true}), done);
|
||||
});
|
||||
it('should check if payload if of type JSON string (and fail if not) ', function(done) {
|
||||
genericSwitchTest("istype", "json", true, false, "Hello", done);
|
||||
});
|
||||
it('should check if payload if of type null', function(done) {
|
||||
genericSwitchTest("istype", "null", true, true, null, done);
|
||||
});
|
||||
it('should check if payload if of type undefined', function(done) {
|
||||
genericSwitchTest("istype", "undefined", true, true, undefined, done);
|
||||
});
|
||||
|
||||
it('should match regex with ignore-case flag set true', function(done) {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"regex","v":"onetwothree","case":true}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
@@ -468,6 +433,7 @@ describe('switch Node', function() {
|
||||
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"nnull"}],checkall:false,outputs:1,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
|
||||
helper.load(switchNode, flow, function() {
|
||||
var switchNode1 = helper.getNode("switchNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
@@ -821,4 +787,5 @@ describe('switch Node', function() {
|
||||
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
var should = require("should");
|
||||
|
||||
var changeNode = require("../../../../nodes/core/logic/15-change.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('change Node', function() {
|
||||
|
||||
@@ -578,6 +578,7 @@ describe('change Node', function() {
|
||||
});
|
||||
|
||||
it('reports invalid regex', function(done) {
|
||||
var sinon = require('sinon');
|
||||
var flow = [{"id":"changeNode1","type":"change","action":"change","property":"payload","from":"\\+**+","to":"NUMBER","reg":true,"name":"changeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(changeNode, flow, function() {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
var should = require("should");
|
||||
|
||||
var rangeNode = require("../../../../nodes/core/logic/16-range.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('range Node', function() {
|
||||
|
||||
@@ -135,13 +135,11 @@ describe('range Node', function() {
|
||||
var sinon = require('sinon');
|
||||
sinon.stub(rangeNode1, 'log', function(log) {
|
||||
if (log.indexOf("notnumber") > -1) {
|
||||
rangeNode1.log.restore();
|
||||
done();
|
||||
} else {
|
||||
try {
|
||||
should.fail(null, null, "Non-number inputs should be reported!");
|
||||
} catch (err) {
|
||||
rangeNode1.log.restore();
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
var should = require("should");
|
||||
var splitNode = require("../../../../nodes/core/logic/17-split.js");
|
||||
var joinNode = require("../../../../nodes/core/logic/17-split.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var RED = require("../../../../red/red.js");
|
||||
|
||||
describe('SPLIT node', function() {
|
||||
@@ -26,10 +26,6 @@ describe('SPLIT node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
@@ -272,10 +268,6 @@ describe('JOIN node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var sortNode = require("../../../../nodes/core/logic/18-sort.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var RED = require("../../../../red/red.js");
|
||||
|
||||
describe('SORT node', function() {
|
||||
@@ -25,10 +25,6 @@ describe('SORT node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var batchNode = require("../../../../nodes/core/logic/19-batch.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
var RED = require("../../../../red/red.js");
|
||||
|
||||
describe('BATCH node', function() {
|
||||
@@ -26,10 +26,6 @@ describe('BATCH node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var csvNode = require("../../../../nodes/core/parsers/70-CSV.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('CSV node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('CSV node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var sinon = require("sinon");
|
||||
var path = require("path");
|
||||
var fs = require('fs-extra');
|
||||
|
||||
var htmlNode = require("../../../../nodes/core/parsers/70-HTML.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('html node', function() {
|
||||
|
||||
@@ -30,10 +31,6 @@ describe('html node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
fs.existsSync(file).should.be.true();
|
||||
});
|
||||
@@ -69,7 +66,7 @@ describe('html node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve header contents if asked to by msg.select - alternative in property', function(done) {
|
||||
it('should retrieve header contents if asked to by msg.select - alternative property', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",property:"foo",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
@@ -79,7 +76,7 @@ describe('html node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.foo[0].should.equal('This is a test page for node 70-HTML');
|
||||
should.equal(msg.foo, 'This is a test page for node 70-HTML');
|
||||
done();
|
||||
});
|
||||
n1.receive({foo:data,topic:"bar",select:"h1"});
|
||||
@@ -87,24 +84,6 @@ describe('html node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve header contents if asked to by msg.select - alternative in and out properties', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",property:"foo",outproperty:"bar",tag:"h1",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.bar[0].should.equal('This is a test page for node 70-HTML');
|
||||
done();
|
||||
});
|
||||
n1.receive({foo:data,topic:"bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit an empty array if no matching elements', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],func:"return msg;"},
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var jsonNode = require("../../../../nodes/core/parsers/70-JSON.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('JSON node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('JSON node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var xmlNode = require("../../../../nodes/core/parsers/70-XML.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('XML node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('XML node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
var should = require("should");
|
||||
var yamlNode = require("../../../../nodes/core/parsers/70-YAML.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('YAML node', function() {
|
||||
|
||||
@@ -24,10 +24,6 @@ describe('YAML node', function() {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ var os = require('os');
|
||||
var fs = require('fs-extra');
|
||||
var sinon = require('sinon');
|
||||
var tailNode = require("../../../../nodes/core/storage/28-tail.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('tail Node', function() {
|
||||
|
||||
@@ -130,20 +130,15 @@ describe('tail Node', function() {
|
||||
});
|
||||
}
|
||||
|
||||
it('should throw an error if run on Windows', function() {
|
||||
it('should throw an error if run on Windows', function(done) {
|
||||
// Stub os platform so we can make it look like windows
|
||||
var os = require('os');
|
||||
var spy = sinon.stub(os, 'platform', function(arg) { return("windows"); });
|
||||
|
||||
/*jshint immed: false */
|
||||
try {
|
||||
(function() { tailNode("1234"); }).should.throw();
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
os.platform.restore();
|
||||
}
|
||||
(function() { tailNode("1234"); }).should.throw();
|
||||
os.platform.restore();
|
||||
done();
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
@@ -20,7 +20,7 @@ var fs = require('fs-extra');
|
||||
var os = require('os');
|
||||
var sinon = require("sinon");
|
||||
var fileNode = require("../../../../nodes/core/storage/50-file.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var helper = require("../../helper.js");
|
||||
|
||||
describe('file Nodes', function() {
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('file Nodes', function() {
|
||||
|
||||
var resourcesDir = path.join(__dirname,"..","..","..","resources");
|
||||
var fileToTest = path.join(resourcesDir,"50-file-test-file.txt");
|
||||
var wait = 250;
|
||||
var wait = 150;
|
||||
|
||||
beforeEach(function(done) {
|
||||
//fs.writeFileSync(fileToTest, "File message line 1\File message line 2\n");
|
||||
|
||||
168
test/nodes/helper.js
Normal file
168
test/nodes/helper.js
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var sinon = require("sinon");
|
||||
var when = require("when");
|
||||
var request = require('supertest');
|
||||
var express = require("express");
|
||||
var nock;
|
||||
if (!process.version.match(/^v0\.[0-9]\./)) {
|
||||
// only set nock for node >= 0.10
|
||||
try {
|
||||
nock = require('nock');
|
||||
} catch (err) {
|
||||
// nevermind, will skip nock tests
|
||||
nock = null;
|
||||
}
|
||||
}
|
||||
var RED = require("../../red/red.js");
|
||||
var redNodes = require("../../red/runtime/nodes");
|
||||
var flows = require("../../red/runtime/nodes/flows");
|
||||
var credentials = require("../../red/runtime/nodes/credentials");
|
||||
var comms = require("../../red/api/editor/comms.js");
|
||||
var log = require("../../red/runtime/log.js");
|
||||
var context = require("../../red/runtime/nodes/context.js");
|
||||
var events = require("../../red/runtime/events.js");
|
||||
|
||||
var http = require('http');
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
var address = '127.0.0.1';
|
||||
var listenPort = 0; // use ephemeral port
|
||||
var port;
|
||||
var url;
|
||||
var logSpy;
|
||||
var server;
|
||||
|
||||
function helperNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: function(testNode, testFlows, testCredentials, cb) {
|
||||
var i;
|
||||
|
||||
logSpy = sinon.spy(log,"log");
|
||||
logSpy.FATAL = log.FATAL;
|
||||
logSpy.ERROR = log.ERROR;
|
||||
logSpy.WARN = log.WARN;
|
||||
logSpy.INFO = log.INFO;
|
||||
logSpy.DEBUG = log.DEBUG;
|
||||
logSpy.TRACE = log.TRACE;
|
||||
logSpy.METRIC = log.METRIC;
|
||||
|
||||
if (typeof testCredentials === 'function') {
|
||||
cb = testCredentials;
|
||||
testCredentials = {};
|
||||
}
|
||||
|
||||
var storage = {
|
||||
getFlows: function() {
|
||||
return when.resolve({flows:testFlows,credentials:testCredentials});
|
||||
}
|
||||
};
|
||||
|
||||
var settings = {
|
||||
available: function() { return false; }
|
||||
};
|
||||
|
||||
var red = {};
|
||||
for (i in RED) {
|
||||
if (RED.hasOwnProperty(i) && !/^(init|start|stop)$/.test(i)) {
|
||||
var propDescriptor = Object.getOwnPropertyDescriptor(RED,i);
|
||||
Object.defineProperty(red,i,propDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
red["_"] = function(messageId) {
|
||||
return messageId;
|
||||
};
|
||||
|
||||
redNodes.init({events:events,settings:settings, storage:storage,log:log,});
|
||||
RED.nodes.registerType("helper", helperNode);
|
||||
if (Array.isArray(testNode)) {
|
||||
for (i = 0; i < testNode.length; i++) {
|
||||
testNode[i](red);
|
||||
}
|
||||
} else {
|
||||
testNode(red);
|
||||
}
|
||||
flows.load().then(function() {
|
||||
flows.startFlows();
|
||||
should.deepEqual(testFlows, flows.getFlows().flows);
|
||||
cb();
|
||||
});
|
||||
},
|
||||
|
||||
unload: function() {
|
||||
// TODO: any other state to remove between tests?
|
||||
redNodes.clearRegistry();
|
||||
logSpy.restore();
|
||||
context.clean({allNodes:[]});
|
||||
return flows.stopFlows();
|
||||
},
|
||||
|
||||
getNode: function(id) {
|
||||
return flows.get(id);
|
||||
},
|
||||
|
||||
credentials: credentials,
|
||||
|
||||
clearFlows: function() {
|
||||
return flows.stopFlows();
|
||||
},
|
||||
|
||||
request: function() {
|
||||
return request(RED.httpAdmin);
|
||||
},
|
||||
|
||||
startServer: function(done) {
|
||||
server = http.createServer(function(req,res) { app(req,res); });
|
||||
RED.init(server, {
|
||||
SKIP_BUILD_CHECK: true,
|
||||
logging:{console:{level:'off'}}
|
||||
});
|
||||
server.listen(listenPort, address);
|
||||
server.on('listening', function() {
|
||||
port = server.address().port;
|
||||
url = 'http://' + address + ':' + port;
|
||||
comms.start();
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
//TODO consider saving TCP handshake/server reinit on start/stop/start sequences
|
||||
stopServer: function(done) {
|
||||
if (server) {
|
||||
try {
|
||||
server.on('close', function() {
|
||||
comms.stop();
|
||||
});
|
||||
server.close(done);
|
||||
} catch(e) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
url: function() { return url; },
|
||||
|
||||
nock: nock,
|
||||
|
||||
log: function() { return logSpy;}
|
||||
};
|
||||
@@ -813,6 +813,7 @@ describe("api/admin/nodes", function() {
|
||||
|
||||
describe('get icons', function() {
|
||||
it('returns icon list', function(done) {
|
||||
debugger;
|
||||
initNodes({
|
||||
nodes:{
|
||||
getNodeIcons: function() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user