mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
92 Commits
fix-plugin
...
4133-mqtt-
Author | SHA1 | Date | |
---|---|---|---|
|
a790136164 | ||
|
32a49a1ef1 | ||
|
4b88775183 | ||
|
29db82625f | ||
|
2b6c9e3439 | ||
|
9ea4853c89 | ||
|
3b5e21761b | ||
|
2d76bf29cf | ||
|
c21f7abe4e | ||
|
8c191263c0 | ||
|
2679ff277c | ||
|
9e3f148273 | ||
|
7e9042e9f7 | ||
|
67c5a248ad | ||
|
e8ddee24a9 | ||
|
be4eab65f6 | ||
|
c0650cc0f5 | ||
|
02c7d014cb | ||
|
67dd7e30fa | ||
|
e9a08af73b | ||
|
08b1ef2766 | ||
|
667d8673d4 | ||
|
d44ea9d558 | ||
|
86dfe86813 | ||
|
246409970d | ||
|
841f1849c8 | ||
|
00e7e4d43c | ||
|
ee43a845aa | ||
|
a7cc66af93 | ||
|
f8701cfed0 | ||
|
6b205bf303 | ||
|
6fbcec8b98 | ||
|
c30e57c31d | ||
|
df3dc36874 | ||
|
7b71d8d212 | ||
|
2eaae4b83f | ||
|
3c66af9506 | ||
|
e5d579c1bb | ||
|
ee811ca89b | ||
|
8e4933041d | ||
|
1f3559e14f | ||
|
f1fa1bbe4e | ||
|
5eb46c570d | ||
|
24178beafc | ||
|
e30df544db | ||
|
6044871438 | ||
|
e612bb6a38 | ||
|
81ea67d6da | ||
|
06e35baeaa | ||
|
c9d72d7a1d | ||
|
62e9572070 | ||
|
fea68c8acc | ||
|
929f0e90ac | ||
|
81331e68d2 | ||
|
4fda59a585 | ||
|
ede3ac4282 | ||
|
16f8b78b39 | ||
|
892d21fb77 | ||
|
adfc5b3e98 | ||
|
f3d7016ab2 | ||
|
8382665bbb | ||
|
e799cfc16a | ||
|
055d0081e1 | ||
|
1824108d09 | ||
|
149e8ce9b0 | ||
|
f4661eec75 | ||
|
0f7a1a42e4 | ||
|
5bda221f9d | ||
|
fd42becbdc | ||
|
7dca148349 | ||
|
ffff8aeb91 | ||
|
ae92ea9476 | ||
|
c7017ee84b | ||
|
0346294c59 | ||
|
8d240ca797 | ||
|
7dbbafec1b | ||
|
c49330f9d1 | ||
|
10324d8260 | ||
|
8f27dae7ea | ||
|
7c306a8430 | ||
|
74794fea09 | ||
|
4d202a7a37 | ||
|
e0d71abdc6 | ||
|
550eb6ee2f | ||
|
f737162697 | ||
|
ce57ba80eb | ||
|
c18018f017 | ||
|
95a7980ada | ||
|
281e9d1357 | ||
|
742f05f59d | ||
|
79db4f8aa1 | ||
|
f4d7b71984 |
14
.github/workflows/tests.yml
vendored
14
.github/workflows/tests.yml
vendored
@@ -19,9 +19,9 @@ jobs:
|
||||
matrix:
|
||||
node-version: [14, 16]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
@@ -29,8 +29,8 @@ jobs:
|
||||
- name: Run tests
|
||||
run: |
|
||||
npm run test
|
||||
- name: Publish to coveralls.io
|
||||
if: ${{ matrix.node-version == 14 }}
|
||||
uses: coverallsapp/github-action@v1.1.2
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
# - name: Publish to coveralls.io
|
||||
# if: ${{ matrix.node-version == 14 }}
|
||||
# uses: coverallsapp/github-action@v1.1.2
|
||||
# with:
|
||||
# github-token: ${{ github.token }}
|
||||
|
@@ -2,8 +2,7 @@
|
||||
|
||||
http://nodered.org
|
||||
|
||||
[](https://travis-ci.org/node-red/node-red)
|
||||
[](https://coveralls.io/r/node-red/node-red?branch=master)
|
||||
[](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
|
||||
|
||||
Low-code programming for event-driven applications.
|
||||
|
||||
|
@@ -491,6 +491,7 @@
|
||||
"unassigned": "Unassigned",
|
||||
"global": "global",
|
||||
"workspace": "workspace",
|
||||
"editor": "edit dialog",
|
||||
"selectAll": "Select all",
|
||||
"selectNone": "Select none",
|
||||
"selectAllConnected": "Select connected",
|
||||
@@ -683,6 +684,8 @@
|
||||
"empty": "empty",
|
||||
"globalConfig": "Global Configuration Nodes",
|
||||
"triggerAction": "Trigger action",
|
||||
"showFlow": "Show",
|
||||
"hideFlow": "Hide",
|
||||
"find": "Find in workspace"
|
||||
},
|
||||
"help": {
|
||||
|
@@ -491,6 +491,7 @@
|
||||
"unassigned": "未割当",
|
||||
"global": "グローバル",
|
||||
"workspace": "ワークスペース",
|
||||
"editor": "編集ダイアログ",
|
||||
"selectAll": "全てのノードを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"selectAllConnected": "接続されたノードを選択",
|
||||
@@ -683,6 +684,8 @@
|
||||
"empty": "空",
|
||||
"globalConfig": "グローバル設定ノード",
|
||||
"triggerAction": "アクションを実行",
|
||||
"showFlow": "表示",
|
||||
"hideFlow": "非表示",
|
||||
"find": "ワークスペース内を検索"
|
||||
},
|
||||
"help": {
|
||||
|
@@ -2095,16 +2095,27 @@ RED.nodes = (function() {
|
||||
} else if (n.type.substring(0,7) === "subflow") {
|
||||
var parentId = n.type.split(":")[1];
|
||||
var subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
parentId = subflow.id;
|
||||
node.type = "subflow:"+parentId;
|
||||
node._def = registry.getNodeType(node.type);
|
||||
delete node.i;
|
||||
if (!subflow){
|
||||
node._def = {
|
||||
color:"#fee",
|
||||
defaults: {},
|
||||
label: "unknown: "+n.type,
|
||||
labelStyle: "red-ui-flow-node-label-italic",
|
||||
outputs: n.outputs|| (n.wires && n.wires.length) || 0,
|
||||
set: registry.getNodeSet("node-red/unknown")
|
||||
}
|
||||
} else {
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
parentId = subflow.id;
|
||||
node.type = "subflow:"+parentId;
|
||||
node._def = registry.getNodeType(node.type);
|
||||
delete node.i;
|
||||
}
|
||||
node.name = n.name;
|
||||
node.outputs = subflow.out.length;
|
||||
node.inputs = subflow.in.length;
|
||||
node.env = n.env;
|
||||
}
|
||||
node.name = n.name;
|
||||
node.outputs = subflow.out.length;
|
||||
node.inputs = subflow.in.length;
|
||||
node.env = n.env;
|
||||
} else if (n.type === 'junction') {
|
||||
node._def = {defaults:{}}
|
||||
node._config.x = node.x
|
||||
|
@@ -321,6 +321,8 @@ var RED = (function() {
|
||||
loader.end()
|
||||
RED.notify($("<p>").text(message));
|
||||
RED.sidebar.info.refresh()
|
||||
RED.menu.setDisabled('menu-item-projects-open',false);
|
||||
RED.menu.setDisabled('menu-item-projects-settings',false);
|
||||
});
|
||||
});
|
||||
return;
|
||||
|
@@ -47,7 +47,7 @@ RED.actionList = (function() {
|
||||
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
|
||||
searchInput = $('<input type="text" data-i18n="[placeholder]keyboard.filterActions">').appendTo(searchDiv).searchBox({
|
||||
change: function() {
|
||||
filterTerm = $(this).val().trim();
|
||||
filterTerm = $(this).val().trim().toLowerCase();
|
||||
filterTerms = filterTerm.split(" ");
|
||||
searchResults.editableList('filter');
|
||||
searchResults.find("li.selected").removeClass("selected");
|
||||
|
@@ -37,13 +37,13 @@ RED.clipboard = (function() {
|
||||
// IE11 workaround
|
||||
// IE does not support data uri scheme for downloading data
|
||||
var blob = new Blob([data], {
|
||||
type: "data:text/plain;charset=utf-8"
|
||||
type: "data:application/json;charset=utf-8"
|
||||
});
|
||||
navigator.msSaveBlob(blob, file);
|
||||
}
|
||||
else {
|
||||
var element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(data));
|
||||
element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(data));
|
||||
element.setAttribute('download', file);
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
|
@@ -45,11 +45,13 @@ RED.editor = (function() {
|
||||
var hasChanged;
|
||||
if (node.type.indexOf("subflow:")===0) {
|
||||
subflow = RED.nodes.subflow(node.type.substring(8));
|
||||
isValid = subflow.valid;
|
||||
hasChanged = subflow.changed;
|
||||
if (isValid === undefined) {
|
||||
isValid = validateNode(subflow);
|
||||
if (subflow){
|
||||
isValid = subflow.valid;
|
||||
hasChanged = subflow.changed;
|
||||
if (isValid === undefined) {
|
||||
isValid = validateNode(subflow);
|
||||
hasChanged = subflow.changed;
|
||||
}
|
||||
}
|
||||
validationErrors = validateNodeProperties(node, node._def.defaults, node);
|
||||
node.valid = isValid && validationErrors.length === 0;
|
||||
|
@@ -491,7 +491,11 @@ RED.keyboard = (function() {
|
||||
okButton.attr("disabled",!valid);
|
||||
});
|
||||
|
||||
var scopeSelect = $('<select><option value="*" data-i18n="keyboard.global"></option><option value="red-ui-workspace" data-i18n="keyboard.workspace"></option></select>').appendTo(scope);
|
||||
var scopeSelect = $('<select>'+
|
||||
'<option value="*" data-i18n="keyboard.global"></option>'+
|
||||
'<option value="red-ui-workspace" data-i18n="keyboard.workspace"></option>'+
|
||||
'<option value="red-ui-editor-stack" data-i18n="keyboard.editor"></option>'+
|
||||
'</select>').appendTo(scope);
|
||||
scopeSelect.i18n();
|
||||
if (object.scope === "workspace") {
|
||||
object.scope = "red-ui-workspace";
|
||||
|
@@ -747,14 +747,14 @@ RED.projects = (function() {
|
||||
var row = $('<div class="form-row"></div>').appendTo(body);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-file">'+RED._("projects.default-files.flow-file")+'</label>').appendTo(row);
|
||||
var subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || (RED.settings.files && RED.settings.files.flow)||"flow.json";
|
||||
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || (RED.settings.files && RED.settings.files.flow) || "flows.json";
|
||||
projectFlowFileInput = $('<input id="red-ui-projects-dialog-screen-create-project-file" type="text">').val(defaultFlowFile)
|
||||
.on("change keyup paste",validateForm)
|
||||
.appendTo(subrow);
|
||||
$('<div class="red-ui-projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||
$('<label class="red-ui-projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row);
|
||||
|
||||
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || (RED.settings.files && RED.settings.files.credentials)||"flow_cred.json";
|
||||
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || (RED.settings.files && RED.settings.files.credentials) || "flows_cred.json";
|
||||
row = $('<div class="form-row"></div>').appendTo(body);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-credfile">'+RED._("projects.default-files.credentials-file")+'</label>').appendTo(row);
|
||||
subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||
@@ -1257,7 +1257,7 @@ RED.projects = (function() {
|
||||
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-empty"></div>').appendTo(container);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-file">'+RED._("projects.create.flow-file")+'</label>').appendTo(row);
|
||||
subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||
projectFlowFileInput = $('<input id="red-ui-projects-dialog-screen-create-project-file" type="text">').val("flow.json")
|
||||
projectFlowFileInput = $('<input id="red-ui-projects-dialog-screen-create-project-file" type="text">').val("flows.json")
|
||||
.on("change keyup paste",validateForm)
|
||||
.appendTo(subrow);
|
||||
$('<div class="red-ui-projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||
|
@@ -663,24 +663,23 @@ RED.subflow = (function() {
|
||||
var candidateOutputs = [];
|
||||
var candidateInputNodes = {};
|
||||
|
||||
var boundingBox = [nodeList[0].x,
|
||||
nodeList[0].y,
|
||||
nodeList[0].x,
|
||||
nodeList[0].y];
|
||||
var boundingBox = [nodeList[0].x-(nodeList[0].w/2),
|
||||
nodeList[0].y-(nodeList[0].h/2),
|
||||
nodeList[0].x+(nodeList[0].w/2),
|
||||
nodeList[0].y+(nodeList[0].h/2)];
|
||||
|
||||
for (i=0;i<nodeList.length;i++) {
|
||||
n = nodeList[i];
|
||||
nodes[n.id] = {n:n,outputs:{}};
|
||||
boundingBox = [
|
||||
Math.min(boundingBox[0],n.x),
|
||||
Math.min(boundingBox[1],n.y),
|
||||
Math.max(boundingBox[2],n.x),
|
||||
Math.max(boundingBox[3],n.y)
|
||||
Math.min(boundingBox[0],n.x-(n.w/2)),
|
||||
Math.min(boundingBox[1],n.y-(n.h/2)),
|
||||
Math.max(boundingBox[2],n.x+(n.w/2)),
|
||||
Math.max(boundingBox[3],n.y+(n.h/2))
|
||||
]
|
||||
}
|
||||
var offsetX = snapToGrid(boundingBox[0] - 200);
|
||||
var offsetY = snapToGrid(boundingBox[1] - 80);
|
||||
|
||||
var offsetX = snapToGrid(boundingBox[0] - 140);
|
||||
var offsetY = snapToGrid(boundingBox[1] - 60);
|
||||
|
||||
var center = [
|
||||
snapToGrid((boundingBox[2]+boundingBox[0]) / 2),
|
||||
|
@@ -135,6 +135,10 @@ RED.sidebar.info.outliner = (function() {
|
||||
RED.workspaces.show(n.id, null, true);
|
||||
}
|
||||
});
|
||||
RED.popover.tooltip(toggleVisibleButton, function () {
|
||||
var isHidden = !div.hasClass("red-ui-info-outline-item-hidden");
|
||||
return RED._("sidebar.info." + (isHidden ? "hideFlow" : "showFlow"));
|
||||
});
|
||||
}
|
||||
if (n.type !== 'subflow') {
|
||||
var toggleButton = $('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
|
||||
@@ -613,6 +617,9 @@ RED.sidebar.info.outliner = (function() {
|
||||
objects[n.id].children = missingParents[n.id];
|
||||
delete missingParents[n.id]
|
||||
}
|
||||
if (objects[n.id].children.length === 0) {
|
||||
objects[n.id].children.push(getEmptyItem(n.id));
|
||||
}
|
||||
}
|
||||
var parent = n.g||n.z||"__global__";
|
||||
|
||||
|
@@ -586,11 +586,28 @@ RED.view = (function() {
|
||||
|
||||
var group = $(ui.helper).data("group");
|
||||
if (group) {
|
||||
var oldX = group.x;
|
||||
var oldY = group.y;
|
||||
RED.group.addToGroup(group, nn);
|
||||
var moveEvent = null;
|
||||
if ((group.x !== oldX) ||
|
||||
(group.y !== oldY)) {
|
||||
moveEvent = {
|
||||
t: "move",
|
||||
nodes: [{n: group,
|
||||
ox: oldX, oy: oldY,
|
||||
dx: group.x -oldX,
|
||||
dy: group.y -oldY}],
|
||||
dirty: true
|
||||
};
|
||||
}
|
||||
historyEvent = {
|
||||
t: 'multi',
|
||||
events: [historyEvent],
|
||||
|
||||
};
|
||||
if (moveEvent) {
|
||||
historyEvent.events.push(moveEvent)
|
||||
}
|
||||
historyEvent.events.push({
|
||||
t: "addToGroup",
|
||||
@@ -1350,19 +1367,35 @@ RED.view = (function() {
|
||||
RED.editor.validateNode(nn);
|
||||
|
||||
if (targetGroup) {
|
||||
var oldX = targetGroup.x;
|
||||
var oldY = targetGroup.y;
|
||||
RED.group.addToGroup(targetGroup, nn);
|
||||
var moveEvent = null;
|
||||
if ((targetGroup.x !== oldX) ||
|
||||
(targetGroup.y !== oldY)) {
|
||||
moveEvent = {
|
||||
t: "move",
|
||||
nodes: [{n: targetGroup,
|
||||
ox: oldX, oy: oldY,
|
||||
dx: targetGroup.x -oldX,
|
||||
dy: targetGroup.y -oldY}],
|
||||
dirty: true
|
||||
};
|
||||
}
|
||||
if (historyEvent.t !== "multi") {
|
||||
historyEvent = {
|
||||
t:'multi',
|
||||
events: [historyEvent]
|
||||
}
|
||||
};
|
||||
}
|
||||
historyEvent.events.push({
|
||||
t: "addToGroup",
|
||||
group: targetGroup,
|
||||
nodes: nn
|
||||
})
|
||||
|
||||
});
|
||||
if (moveEvent) {
|
||||
historyEvent.events.push(moveEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (spliceLink) {
|
||||
@@ -1698,6 +1731,7 @@ RED.view = (function() {
|
||||
|
||||
// Check link splice or group-add
|
||||
if (movingSet.length() === 1 && movingSet.get(0).n.type !== "group") {
|
||||
//}{//NIS
|
||||
node = movingSet.get(0);
|
||||
if (spliceActive) {
|
||||
if (!spliceTimer) {
|
||||
@@ -2057,11 +2091,25 @@ RED.view = (function() {
|
||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
if (movingSet.length() > 0) {
|
||||
var addedToGroup = null;
|
||||
var moveEvent = null;
|
||||
if (activeHoverGroup) {
|
||||
var oldX = activeHoverGroup.x;
|
||||
var oldY = activeHoverGroup.y;
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
var n = movingSet.get(j);
|
||||
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||
}
|
||||
if ((activeHoverGroup.x !== oldX) ||
|
||||
(activeHoverGroup.y !== oldY)) {
|
||||
moveEvent = {
|
||||
t: "move",
|
||||
nodes: [{n: activeHoverGroup,
|
||||
ox: oldX, oy: oldY,
|
||||
dx: activeHoverGroup.x -oldX,
|
||||
dy: activeHoverGroup.y -oldY}],
|
||||
dirty: true
|
||||
};
|
||||
}
|
||||
addedToGroup = activeHoverGroup;
|
||||
|
||||
activeHoverGroup.hovered = false;
|
||||
@@ -2107,6 +2155,12 @@ RED.view = (function() {
|
||||
historyEvent.addToGroup = addedToGroup;
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
if (moveEvent) {
|
||||
historyEvent = {
|
||||
t: "multi",
|
||||
events: [moveEvent, historyEvent]
|
||||
};
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
}
|
||||
@@ -2592,6 +2646,16 @@ RED.view = (function() {
|
||||
var result = RED.nodes.removeJunction(node)
|
||||
removedJunctions.push(node);
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
if (node.g) {
|
||||
var group = RED.nodes.group(node.g);
|
||||
if (selectedGroups.indexOf(group) === -1) {
|
||||
// Don't use RED.group.removeFromGroup as that emits
|
||||
// a change event on the node - but we're deleting it
|
||||
var index = group.nodes.indexOf(node);
|
||||
group.nodes.splice(index,1);
|
||||
RED.group.markDirty(group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node.direction === "out") {
|
||||
removedSubflowOutputs.push(node);
|
||||
@@ -3466,11 +3530,25 @@ RED.view = (function() {
|
||||
updateActiveNodes();
|
||||
}
|
||||
|
||||
var moveEvent = null;
|
||||
if (activeHoverGroup) {
|
||||
var oldX = activeHoverGroup.x;
|
||||
var oldY = activeHoverGroup.y;
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
var n = movingSet.get(j);
|
||||
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||
}
|
||||
if ((activeHoverGroup.x !== oldX) ||
|
||||
(activeHoverGroup.y !== oldY)) {
|
||||
moveEvent = {
|
||||
t: "move",
|
||||
nodes: [{n: activeHoverGroup,
|
||||
ox: oldX, oy: oldY,
|
||||
dx: activeHoverGroup.x -oldX,
|
||||
dy: activeHoverGroup.y -oldY}],
|
||||
dirty: true
|
||||
};
|
||||
}
|
||||
historyEvent.addedToGroup = activeHoverGroup;
|
||||
|
||||
activeHoverGroup.hovered = false;
|
||||
@@ -3479,7 +3557,6 @@ RED.view = (function() {
|
||||
activeGroup.selected = true;
|
||||
activeHoverGroup = null;
|
||||
}
|
||||
|
||||
if (mouse_mode == RED.state.DETACHED_DRAGGING) {
|
||||
var ns = [];
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
@@ -3490,7 +3567,15 @@ RED.view = (function() {
|
||||
n.n.moved = true;
|
||||
}
|
||||
}
|
||||
RED.history.replace({t:"multi",events:[historyEvent,{t:"move",nodes:ns}],dirty: historyEvent.dirty})
|
||||
var event = {t:"multi",events:[historyEvent,{t:"move",nodes:ns}],dirty: historyEvent.dirty};
|
||||
if (moveEvent) {
|
||||
event.events.push(moveEvent);
|
||||
}
|
||||
RED.history.replace(event)
|
||||
}
|
||||
else if(moveEvent) {
|
||||
var event = {t:"multi", events:[historyEvent, moveEvent], dirty: true};
|
||||
RED.history.replace(event);
|
||||
}
|
||||
|
||||
updateSelection();
|
||||
|
@@ -124,7 +124,7 @@
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding:0;
|
||||
|
||||
overflow-wrap: anywhere;
|
||||
li {
|
||||
display: inline-block;
|
||||
padding:0;
|
||||
|
@@ -32,7 +32,8 @@
|
||||
color: var(--red-ui-primary-text-color);
|
||||
border: 1px solid var(--red-ui-notification-border-default);
|
||||
border-left-width: 16px;
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
max-height: 80vh;
|
||||
.ui-dialog-buttonset {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
|
@@ -55,7 +55,7 @@
|
||||
.red-ui-palette-search {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--red-ui-secondary-background);
|
||||
background: var(--red-ui-form-input-background);
|
||||
text-align: center;
|
||||
height: 35px;
|
||||
padding: 3px;
|
||||
|
@@ -35,6 +35,7 @@
|
||||
padding: 8px;
|
||||
border-radius: 2px;
|
||||
background: var(--red-ui-popover-background);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.red-ui-popover:after, .red-ui-popover:before {
|
||||
border: solid transparent;
|
||||
|
@@ -41,6 +41,7 @@
|
||||
height: 50px;
|
||||
background: var(--red-ui-secondary-background);
|
||||
border: 2px solid var(--red-ui-primary-border-color);
|
||||
color: var(--red-ui-primary-text-color);
|
||||
text-align: center;
|
||||
line-height:50px;
|
||||
|
||||
@@ -51,7 +52,7 @@
|
||||
|
||||
.red-ui-editor-radial-menu-opt-disabled {
|
||||
border-color: var(--red-ui-tertiary-border-color);
|
||||
color: var(--red-ui-tertiary-border-color);
|
||||
color: var(--red-ui-secondary-text-color-disabled);
|
||||
}
|
||||
.red-ui-editor-radial-menu-opt-active {
|
||||
background: var(--red-ui-secondary-background-hover);
|
||||
|
@@ -108,6 +108,8 @@
|
||||
}
|
||||
.red-ui-search-result-node-label {
|
||||
color: var(--red-ui-secondary-text-color);
|
||||
width: 240px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
> span {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
border-bottom: 1px solid var(--red-ui-secondary-border-color);
|
||||
}
|
||||
|
@@ -95,45 +95,64 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
this.on("input", function(msg, send, done) {
|
||||
var errors = [];
|
||||
var props = this.props;
|
||||
const errors = [];
|
||||
let props = this.props;
|
||||
if (msg.__user_inject_props__ && Array.isArray(msg.__user_inject_props__)) {
|
||||
props = msg.__user_inject_props__;
|
||||
}
|
||||
delete msg.__user_inject_props__;
|
||||
props.forEach(p => {
|
||||
var property = p.p;
|
||||
var value = p.v ? p.v : '';
|
||||
var valueType = p.vt ? p.vt : 'str';
|
||||
props = [...props]
|
||||
function evaluateProperty(doneEvaluating) {
|
||||
if (props.length === 0) {
|
||||
doneEvaluating()
|
||||
return
|
||||
}
|
||||
const p = props.shift()
|
||||
const property = p.p;
|
||||
const value = p.v ? p.v : '';
|
||||
const valueType = p.vt ? p.vt : 'str';
|
||||
|
||||
if (!property) return;
|
||||
|
||||
if (valueType === "jsonata") {
|
||||
if (p.v) {
|
||||
try {
|
||||
var exp = RED.util.prepareJSONataExpression(p.v, node);
|
||||
var val = RED.util.evaluateJSONataExpression(exp, msg);
|
||||
RED.util.setMessageProperty(msg, property, val, true);
|
||||
if (property) {
|
||||
if (valueType === "jsonata") {
|
||||
if (p.v) {
|
||||
try {
|
||||
var exp = RED.util.prepareJSONataExpression(p.v, node);
|
||||
var val = RED.util.evaluateJSONataExpression(exp, msg);
|
||||
RED.util.setMessageProperty(msg, property, val, true);
|
||||
}
|
||||
catch (err) {
|
||||
errors.push(err.message);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
errors.push(err.message);
|
||||
evaluateProperty(doneEvaluating)
|
||||
} else {
|
||||
try {
|
||||
RED.util.evaluateNodeProperty(value, valueType, node, msg, (err, newValue) => {
|
||||
if (err) {
|
||||
errors.push(err.toString())
|
||||
} else {
|
||||
RED.util.setMessageProperty(msg,property,newValue,true);
|
||||
}
|
||||
evaluateProperty(doneEvaluating)
|
||||
})
|
||||
} catch (err) {
|
||||
errors.push(err.toString());
|
||||
evaluateProperty(doneEvaluating)
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
evaluateProperty(doneEvaluating)
|
||||
}
|
||||
try {
|
||||
RED.util.setMessageProperty(msg,property,RED.util.evaluateNodeProperty(value, valueType, this, msg),true);
|
||||
} catch (err) {
|
||||
errors.push(err.toString());
|
||||
}
|
||||
});
|
||||
|
||||
if (errors.length) {
|
||||
done(errors.join('; '));
|
||||
} else {
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
|
||||
evaluateProperty(() => {
|
||||
if (errors.length) {
|
||||
done(errors.join('; '));
|
||||
} else {
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,16 @@
|
||||
color:"#c0edc0",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
scope: {value:[], type:"*[]"},
|
||||
scope: {
|
||||
value: [],
|
||||
type: "*[]",
|
||||
validate: function (v, opt) {
|
||||
if (v.length > 0) {
|
||||
return true;
|
||||
}
|
||||
return RED._("node-red:complete.errors.scopeUndefined");
|
||||
}
|
||||
},
|
||||
uncaught: {value:false}
|
||||
},
|
||||
inputs:0,
|
||||
|
@@ -1,4 +1,3 @@
|
||||
|
||||
<script type="text/html" data-template-name="link in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
@@ -272,7 +271,17 @@
|
||||
color:"#ddd",//"#87D8CF",
|
||||
defaults: {
|
||||
name: { value: "" },
|
||||
links: { value: [], type:"link in[]" },
|
||||
links: {
|
||||
value: [],
|
||||
type: "link in[]",
|
||||
validate: function (v, opt) {
|
||||
if ((this.linkType === "static" && v.length > 0)
|
||||
|| this.linkType === "dynamic") {
|
||||
return true;
|
||||
}
|
||||
return RED._("node-red:link.errors.linkUndefined");
|
||||
}
|
||||
},
|
||||
linkType: { value:"static" },
|
||||
timeout: {
|
||||
value: "30",
|
||||
|
@@ -164,10 +164,10 @@ module.exports = function(RED) {
|
||||
if (returnNode && returnNode.returnLinkMessage) {
|
||||
returnNode.returnLinkMessage(messageEvent.id, msg);
|
||||
} else {
|
||||
node.warn(RED._("link.error.missingReturn"))
|
||||
node.warn(RED._("link.errors.missingReturn"));
|
||||
}
|
||||
} else {
|
||||
node.warn(RED._("link.error.missingReturn"))
|
||||
node.warn(RED._("link.errors.missingReturn"));
|
||||
}
|
||||
done();
|
||||
} else if (mode === "link") {
|
||||
|
@@ -17,6 +17,8 @@
|
||||
display: flex;
|
||||
background: var(--red-ui-tertiary-background);
|
||||
padding-right: 75px;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
#node-input-libs-container-row .red-ui-editableList-header > div {
|
||||
flex-grow: 1;
|
||||
|
@@ -35,7 +35,11 @@ module.exports = function(RED) {
|
||||
}
|
||||
else { node.previous = {}; }
|
||||
}
|
||||
var value = RED.util.getMessageProperty(msg,node.property);
|
||||
var value;
|
||||
try {
|
||||
value = RED.util.getMessageProperty(msg,node.property);
|
||||
}
|
||||
catch(e) { }
|
||||
if (value !== undefined) {
|
||||
var t = "_no_topic";
|
||||
if (node.septopics) { t = topic || t; }
|
||||
|
@@ -295,7 +295,7 @@ module.exports = function(RED) {
|
||||
/* mute error - it simply isnt JSON, just leave payload as a string */
|
||||
}
|
||||
}
|
||||
} //else {
|
||||
} //else {
|
||||
//leave as buffer
|
||||
//}
|
||||
}
|
||||
@@ -357,7 +357,7 @@ module.exports = function(RED) {
|
||||
return;
|
||||
}
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
@@ -697,7 +697,8 @@ module.exports = function(RED) {
|
||||
node.options.rejectUnauthorized = (node.verifyservercert == "true" || node.verifyservercert === true);
|
||||
}
|
||||
}
|
||||
|
||||
node.v5 = () => node.options && node.options.protocolVersion == 5
|
||||
node.subscriptionIdentifiersAvailable = () => node.v5() && node.serverProperties && node.serverProperties.subscriptionIdentifiersAvailable
|
||||
n.autoConnect = n.autoConnect === "false" || n.autoConnect === false ? false : true;
|
||||
node.setOptions(n, true);
|
||||
|
||||
@@ -718,9 +719,10 @@ module.exports = function(RED) {
|
||||
node.deregister = function(mqttNode, done, autoDisconnect) {
|
||||
delete node.users[mqttNode.id];
|
||||
if (autoDisconnect && !node.closing && node.connected && Object.keys(node.users).length === 0) {
|
||||
node.disconnect();
|
||||
node.disconnect(done);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
done();
|
||||
};
|
||||
node.canConnect = function() {
|
||||
return !node.connected && !node.connecting;
|
||||
@@ -854,7 +856,7 @@ module.exports = function(RED) {
|
||||
let waitEnd = (client, ms) => {
|
||||
return new Promise( (resolve, reject) => {
|
||||
node.closing = true;
|
||||
if(!client) {
|
||||
if(!client) {
|
||||
resolve();
|
||||
} else {
|
||||
const t = setTimeout(() => {
|
||||
@@ -919,7 +921,12 @@ module.exports = function(RED) {
|
||||
};
|
||||
node.subscriptions[topic][ref] = sub;
|
||||
if (node.connected) {
|
||||
const subIdsAvailable = node.subscriptionIdentifiersAvailable()
|
||||
node._clientOn('message',sub.handler);
|
||||
// if the broker doesn't support subscription identifiers (e.g. AWS core), then don't send them
|
||||
if (options.properties && options.properties.subscriptionIdentifier && subIdsAvailable !== true) {
|
||||
delete options.properties.subscriptionIdentifier
|
||||
}
|
||||
node.client.subscribe(topic, options);
|
||||
}
|
||||
};
|
||||
@@ -1033,7 +1040,7 @@ module.exports = function(RED) {
|
||||
|
||||
/**
|
||||
* Add event handlers to the MQTT.js client and track them so that
|
||||
* we do not remove any handlers that the MQTT client uses internally.
|
||||
* we do not remove any handlers that the MQTT client uses internally.
|
||||
* Use {@link node._clientRemoveListeners `node._clientRemoveListeners`} to remove handlers
|
||||
* @param {string} event The name of the event
|
||||
* @param {function} handler The handler for this event
|
||||
@@ -1041,11 +1048,11 @@ module.exports = function(RED) {
|
||||
node._clientOn = function(event, handler) {
|
||||
node.clientListeners.push({event, handler})
|
||||
node.client.on(event, handler)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove event handlers from the MQTT.js client & only the events
|
||||
* that we attached in {@link node._clientOn `node._clientOn`}.
|
||||
* Remove event handlers from the MQTT.js client & only the events
|
||||
* that we attached in {@link node._clientOn `node._clientOn`}.
|
||||
* * If `event` is omitted, then all events matching `handler` are removed
|
||||
* * If `handler` is omitted, then all events named `event` are removed
|
||||
* * If both parameters are omitted, then all events are removed
|
||||
|
@@ -251,7 +251,9 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
node.buffer = buff.slice(p,buff.length);
|
||||
node.pendingDones.push(done);
|
||||
if (node.buffer.length > 0) {
|
||||
node.pendingDones.push(done);
|
||||
}
|
||||
}
|
||||
if (node.buffer.length == 0) {
|
||||
done();
|
||||
|
@@ -117,7 +117,9 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (typeof data === "boolean") { data = data.toString(); }
|
||||
if (typeof data === "number") { data = data.toString(); }
|
||||
if ((node.appendNewline) && (!Buffer.isBuffer(data))) { data += os.EOL; }
|
||||
var aflg = true;
|
||||
if (msg.hasOwnProperty("parts") && msg.parts.type === "string" && (msg.parts.count === msg.parts.index + 1)) { aflg = false; }
|
||||
if ((node.appendNewline) && (!Buffer.isBuffer(data)) && aflg) { data += os.EOL; }
|
||||
var buf;
|
||||
if (node.encoding === "setbymsg") {
|
||||
buf = encode(data, msg.encoding || "none");
|
||||
@@ -314,7 +316,6 @@ module.exports = function(RED) {
|
||||
});
|
||||
filename = filename || "";
|
||||
var fullFilename = filename;
|
||||
var filePath = "";
|
||||
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
||||
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
||||
}
|
||||
|
@@ -18,5 +18,5 @@
|
||||
<p>A node you can use to add comments to your flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>The edit panel will accept Markdown syntax. The text will be rendered into
|
||||
this information side panel.</p>
|
||||
the information side panel.</p>
|
||||
</script>
|
||||
|
@@ -119,7 +119,10 @@
|
||||
}
|
||||
},
|
||||
"complete": {
|
||||
"completeNodes": "complete: __number__"
|
||||
"completeNodes": "complete: __number__",
|
||||
"errors": {
|
||||
"scopeUndefined": "scope undefined"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"output": "Output",
|
||||
@@ -181,8 +184,9 @@
|
||||
"staticLinkCall": "Fixed target",
|
||||
"dynamicLinkCall": "Dynamic target (msg.target)",
|
||||
"dynamicLinkLabel": "Dynamic",
|
||||
"error": {
|
||||
"missingReturn": "Missing return node information"
|
||||
"errors": {
|
||||
"missingReturn": "Missing return node information",
|
||||
"linkUndefined": "link undefined"
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
|
@@ -119,7 +119,10 @@
|
||||
}
|
||||
},
|
||||
"complete": {
|
||||
"completeNodes": "complete: __number__"
|
||||
"completeNodes": "complete: __number__",
|
||||
"errors": {
|
||||
"scopeUndefined": "スコープが未定義"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"output": "対象",
|
||||
@@ -181,8 +184,9 @@
|
||||
"staticLinkCall": "対象を固定で指定",
|
||||
"dynamicLinkCall": "対象を動的に指定 (msg.target)",
|
||||
"dynamicLinkLabel": "動的",
|
||||
"error": {
|
||||
"missingReturn": "返却するノードの情報が存在しません"
|
||||
"errors": {
|
||||
"missingReturn": "返却するノードの情報が存在しません",
|
||||
"linkUndefined": "リンクが未定義"
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
|
@@ -106,8 +106,8 @@ function getLocalNodeFiles(dir, skipValidNodeRedModules) {
|
||||
// when loading local files, if the path is a valid node-red module
|
||||
// dont include it (will be picked up in scanTreeForNodesModules)
|
||||
if(skipValidNodeRedModules && files.indexOf("package.json") >= 0) {
|
||||
const package = getPackageDetails(dir)
|
||||
if(package.isNodeRedModule) {
|
||||
const packageDetails = getPackageDetails(dir)
|
||||
if(packageDetails.isNodeRedModule) {
|
||||
return {files: [], icons: []};
|
||||
}
|
||||
}
|
||||
@@ -135,17 +135,17 @@ function getLocalNodeFiles(dir, skipValidNodeRedModules) {
|
||||
return {files: result, icons: icons}
|
||||
}
|
||||
|
||||
function scanDirForNodesModules(dir,moduleName,package) {
|
||||
function scanDirForNodesModules(dir,moduleName,packageDetails) {
|
||||
let results = [];
|
||||
let scopeName;
|
||||
let files
|
||||
try {
|
||||
let isNodeRedModule = false
|
||||
if(package) {
|
||||
dir = path.join(package.moduleDir,'..')
|
||||
files = [path.basename(package.moduleDir)]
|
||||
moduleName = (package.package ? package.package.name : null) || moduleName
|
||||
isNodeRedModule = package.isNodeRedModule
|
||||
if(packageDetails) {
|
||||
dir = path.join(packageDetails.moduleDir,'..')
|
||||
files = [path.basename(packageDetails.moduleDir)]
|
||||
moduleName = (packageDetails.package ? packageDetails.package.name : null) || moduleName
|
||||
isNodeRedModule = packageDetails.isNodeRedModule
|
||||
} else {
|
||||
files = fs.readdirSync(dir);
|
||||
if (moduleName) {
|
||||
@@ -159,8 +159,8 @@ function scanDirForNodesModules(dir,moduleName,package) {
|
||||
|
||||
// if we have found a package.json, this IS a node_module, lets see if it is a node-red node
|
||||
if (!isNodeRedModule && files.indexOf('package.json') > -1) {
|
||||
package = getPackageDetails(dir) // get package details
|
||||
if(package && package.isNodeRedModule) {
|
||||
packageDetails = getPackageDetails(dir) // get package details
|
||||
if(packageDetails && packageDetails.isNodeRedModule) {
|
||||
isNodeRedModule = true
|
||||
files = ['package.json'] // shortcut the file scan
|
||||
}
|
||||
@@ -179,8 +179,8 @@ function scanDirForNodesModules(dir,moduleName,package) {
|
||||
} else {
|
||||
if ((isNodeRedModule || (!moduleName || fn == moduleName)) && (isIncluded(fn) && !isExcluded(fn))) {
|
||||
try {
|
||||
const moduleDir = isNodeRedModule ? package.moduleDir : path.join(dir,fn);
|
||||
const pkg = package || getPackageDetails(moduleDir)
|
||||
const moduleDir = isNodeRedModule ? packageDetails.moduleDir : path.join(dir,fn);
|
||||
const pkg = packageDetails || getPackageDetails(moduleDir)
|
||||
if(pkg.error) {
|
||||
throw pkg.error
|
||||
}
|
||||
|
@@ -818,6 +818,16 @@ function handlePreRoute(flow, sendEvent, reportError) {
|
||||
})
|
||||
}
|
||||
|
||||
function deliverMessageToDestination(sendEvent) {
|
||||
if (sendEvent?.destination?.node) {
|
||||
try {
|
||||
sendEvent.destination.node.receive(sendEvent.msg);
|
||||
} catch(err) {
|
||||
Log.error(`Error delivering message to node:${sendEvent.destination.node._path} [${sendEvent.destination.node.type}]`)
|
||||
Log.error(err.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
function handlePreDeliver(flow,sendEvent, reportError) {
|
||||
// preDeliver - the local router has identified the node it is going to send to. At this point, the message has been cloned if needed.
|
||||
hooks.trigger("preDeliver",sendEvent,(err) => {
|
||||
@@ -827,15 +837,10 @@ function handlePreDeliver(flow,sendEvent, reportError) {
|
||||
} else if (err !== false) {
|
||||
if (asyncMessageDelivery) {
|
||||
setImmediate(function() {
|
||||
if (sendEvent.destination.node) {
|
||||
sendEvent.destination.node.receive(sendEvent.msg);
|
||||
}
|
||||
deliverMessageToDestination(sendEvent)
|
||||
})
|
||||
} else {
|
||||
if (sendEvent.destination.node) {
|
||||
sendEvent.destination.node.receive(sendEvent.msg);
|
||||
|
||||
}
|
||||
deliverMessageToDestination(sendEvent)
|
||||
}
|
||||
// postDeliver - the message has been dispatched to be delivered asynchronously (unless the sync delivery flag is set, in which case it would be continue as synchronous delivery)
|
||||
hooks.trigger("postDeliver", sendEvent, function(err) {
|
||||
|
@@ -641,6 +641,7 @@ function getFlow(id) {
|
||||
if (node.type === 'link out') {
|
||||
delete node.wires;
|
||||
}
|
||||
delete node.credentials;
|
||||
return node;
|
||||
})
|
||||
}
|
||||
@@ -648,7 +649,10 @@ function getFlow(id) {
|
||||
if (flow.configs) {
|
||||
var configIds = Object.keys(flow.configs);
|
||||
result.configs = configIds.map(function(configId) {
|
||||
return clone(flow.configs[configId]);
|
||||
const node = clone(flow.configs[configId]);
|
||||
delete node.credentials;
|
||||
return node
|
||||
|
||||
})
|
||||
if (result.configs.length === 0) {
|
||||
delete result.configs;
|
||||
@@ -660,12 +664,16 @@ function getFlow(id) {
|
||||
var subflow = clone(flow.subflows[subflowId]);
|
||||
var nodeIds = Object.keys(subflow.nodes);
|
||||
subflow.nodes = nodeIds.map(function(id) {
|
||||
return subflow.nodes[id];
|
||||
const node = clone(subflow.nodes[id])
|
||||
delete node.credentials
|
||||
return node
|
||||
});
|
||||
if (subflow.configs) {
|
||||
var configIds = Object.keys(subflow.configs);
|
||||
subflow.configs = configIds.map(function(id) {
|
||||
return subflow.configs[id];
|
||||
const node = clone(subflow.configs[id])
|
||||
delete node.credentials
|
||||
return node
|
||||
})
|
||||
}
|
||||
delete subflow.instances;
|
||||
|
@@ -199,7 +199,9 @@ function parseConfig(config) {
|
||||
if (subflowDetails) {
|
||||
var subflowType = subflowDetails[1]
|
||||
n.subflow = subflowType;
|
||||
flow.subflows[subflowType].instances.push(n)
|
||||
if (flow.subflows[subflowType]) {
|
||||
flow.subflows[subflowType].instances.push(n)
|
||||
}
|
||||
}
|
||||
if (container) {
|
||||
container.nodes[n.id] = n;
|
||||
|
@@ -18,7 +18,7 @@ var i18n = require("@node-red/util").i18n;
|
||||
|
||||
module.exports = {
|
||||
"package.json": function(project) {
|
||||
var package = {
|
||||
var packageDetails = {
|
||||
"name": project.name,
|
||||
"description": project.summary||i18n._("storage.localfilesystem.projects.summary"),
|
||||
"version": "0.0.1",
|
||||
@@ -30,11 +30,11 @@ module.exports = {
|
||||
};
|
||||
if (project.files) {
|
||||
if (project.files.flow) {
|
||||
package['node-red'].settings.flowFile = project.files.flow;
|
||||
package['node-red'].settings.credentialsFile = project.files.credentials;
|
||||
packageDetails['node-red'].settings.flowFile = project.files.flow;
|
||||
packageDetails['node-red'].settings.credentialsFile = project.files.credentials;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(package,"",4);
|
||||
return JSON.stringify(packageDetails,"",4);
|
||||
},
|
||||
"README.md": function(project) {
|
||||
var content = project.name+"\n"+("=".repeat(project.name.length))+"\n\n";
|
||||
|
@@ -421,7 +421,10 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
initRepo: function(cwd) {
|
||||
return runGitCommand(["init"],cwd);
|
||||
var args = ["init", "--initial-branch", "main"];
|
||||
return runGitCommand(args, cwd).catch(function () {
|
||||
return runGitCommand(["init"], cwd);
|
||||
});
|
||||
},
|
||||
setUpstream: function(cwd,remoteBranch) {
|
||||
var args = ["branch","--set-upstream-to",remoteBranch];
|
||||
|
@@ -20,6 +20,7 @@
|
||||
"errors-help": "詳細は -v を指定して実行してください",
|
||||
"missing-modules": "不足しているノードモジュール:",
|
||||
"node-version-mismatch": "ノードモジュールはこのバージョンではロードできません。必要なバージョン: __version__ ",
|
||||
"set-has-no-types": "セットに型がありません。 名前: '__name__', モジュール: '__module__', ファイル: '__file__'",
|
||||
"type-already-registered": "'__type__' はモジュール __module__ で登録済みです",
|
||||
"removing-modules": "設定からモジュールを削除します",
|
||||
"added-types": "追加したノード:",
|
||||
@@ -134,7 +135,8 @@
|
||||
"flow": {
|
||||
"unknown-type": "不明なノード: __type__",
|
||||
"missing-types": "欠落したノード",
|
||||
"error-loop": "メッセージの例外補足回数が最大値を超えました"
|
||||
"error-loop": "メッセージの例外補足回数が最大値を超えました",
|
||||
"non-message-returned": "ノードが __type__ 型のメッセージの送信を試みました"
|
||||
},
|
||||
"index": {
|
||||
"unrecognised-id": "不明なID: __id__",
|
||||
|
2
packages/node_modules/node-red/red.js
vendored
2
packages/node_modules/node-red/red.js
vendored
@@ -458,7 +458,7 @@ httpsPromise.then(function(startupHttps) {
|
||||
RED.start().then(function() {
|
||||
if (settings.httpAdminRoot !== false || settings.httpNodeRoot !== false || settings.httpStatic) {
|
||||
server.on('error', function(err) {
|
||||
if (err.errno === "EADDRINUSE") {
|
||||
if (err.code === "EADDRINUSE") {
|
||||
RED.log.error(RED.log._("server.unable-to-listen", {listenpath:getListenPath()}));
|
||||
RED.log.error(RED.log._("server.port-in-use"));
|
||||
} else {
|
||||
|
30
packages/node_modules/node-red/settings.js
vendored
30
packages/node_modules/node-red/settings.js
vendored
@@ -181,7 +181,7 @@ module.exports = {
|
||||
|
||||
/** Some nodes, such as HTTP In, can be used to listen for incoming http requests.
|
||||
* By default, these are served relative to '/'. The following property
|
||||
* can be used to specifiy a different root path. If set to false, this is
|
||||
* can be used to specify a different root path. If set to false, this is
|
||||
* disabled.
|
||||
*/
|
||||
//httpNodeRoot: '/red-nodes',
|
||||
@@ -219,17 +219,17 @@ module.exports = {
|
||||
/** When httpAdminRoot is used to move the UI to a different root path, the
|
||||
* following property can be used to identify a directory of static content
|
||||
* that should be served at http://localhost:1880/.
|
||||
* When httpStaticRoot is set differently to httpAdminRoot, there is no need
|
||||
* When httpStaticRoot is set differently to httpAdminRoot, there is no need
|
||||
* to move httpAdminRoot
|
||||
*/
|
||||
//httpStatic: '/home/nol/node-red-static/', //single static source
|
||||
/* OR multiple static sources can be created using an array of objects... */
|
||||
//httpStatic: [
|
||||
// {path: '/home/nol/pics/', root: "/img/"},
|
||||
// {path: '/home/nol/reports/', root: "/doc/"},
|
||||
// {path: '/home/nol/pics/', root: "/img/"},
|
||||
// {path: '/home/nol/reports/', root: "/doc/"},
|
||||
//],
|
||||
|
||||
/**
|
||||
/**
|
||||
* All static routes will be appended to httpStaticRoot
|
||||
* e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/"
|
||||
* then "/home/nol/docs" will be served at "/static/"
|
||||
@@ -256,11 +256,11 @@ module.exports = {
|
||||
*/
|
||||
// lang: "de",
|
||||
|
||||
/** Configure diagnostics options
|
||||
/** Configure diagnostics options
|
||||
* - enabled: When `enabled` is `true` (or unset), diagnostics data will
|
||||
* be available at http://localhost:1880/diagnostics
|
||||
* - ui: When `ui` is `true` (or unset), the action `show-system-info` will
|
||||
* be available to logged in users of node-red editor
|
||||
* be available at http://localhost:1880/diagnostics
|
||||
* - ui: When `ui` is `true` (or unset), the action `show-system-info` will
|
||||
* be available to logged in users of node-red editor
|
||||
*/
|
||||
diagnostics: {
|
||||
/** enable or disable diagnostics endpoint. Must be set to `false` to disable */
|
||||
@@ -268,10 +268,10 @@ module.exports = {
|
||||
/** enable or disable diagnostics display in the node-red editor. Must be set to `false` to disable */
|
||||
ui: true,
|
||||
},
|
||||
/** Configure runtimeState options
|
||||
* - enabled: When `enabled` is `true` flows runtime can be Started/Stoped
|
||||
* by POSTing to available at http://localhost:1880/flows/state
|
||||
* - ui: When `ui` is `true`, the action `core:start-flows` and
|
||||
/** Configure runtimeState options
|
||||
* - enabled: When `enabled` is `true` flows runtime can be Started/Stopped
|
||||
* by POSTing to available at http://localhost:1880/flows/state
|
||||
* - ui: When `ui` is `true`, the action `core:start-flows` and
|
||||
* `core:stop-flows` will be available to logged in users of node-red editor
|
||||
* Also, the deploy menu (when set to default) will show a stop or start button
|
||||
*/
|
||||
@@ -416,7 +416,7 @@ module.exports = {
|
||||
*/
|
||||
// theme: "vs",
|
||||
/** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc.
|
||||
* for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html
|
||||
* for the full list, see https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html
|
||||
*/
|
||||
//fontSize: 14,
|
||||
//fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace",
|
||||
@@ -519,7 +519,7 @@ module.exports = {
|
||||
*/
|
||||
//tlsConfigDisableLocalFiles: true,
|
||||
|
||||
/** The following property can be used to verify websocket connection attempts.
|
||||
/** The following property can be used to verify WebSocket connection attempts.
|
||||
* This allows, for example, the HTTP request headers to be checked to ensure
|
||||
* they include valid authentication information.
|
||||
*/
|
||||
|
@@ -854,7 +854,7 @@ describe('inject node', function() {
|
||||
});
|
||||
n1.on("call:error", function(err) {
|
||||
count++;
|
||||
if (count == 2) {
|
||||
if (count == 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
@@ -194,6 +194,55 @@ describe('file Nodes', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should append to a file and add newline, except last line of multipart input', function(done) {
|
||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false, wires: [["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
try {
|
||||
fs.unlinkSync(fileToTest);
|
||||
} catch(err) {
|
||||
}
|
||||
helper.load(fileNode, flow, function() {
|
||||
var n1 = helper.getNode("fileNode1");
|
||||
var n2 = helper.getNode("helperNode1");
|
||||
var count = 0;
|
||||
//var data = ["Line1", "Line2"];
|
||||
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
//data.should.containDeep([msg.payload]);
|
||||
if (count === 3) {
|
||||
var f = fs.readFileSync(fileToTest).toString();
|
||||
if (os.type() !== "Windows_NT") {
|
||||
f.should.have.length(23);
|
||||
f.should.equal("Line1\nLine2\nLine3\nLine4");
|
||||
}
|
||||
else {
|
||||
f.should.have.length(23);
|
||||
f.should.equal("Line1\r\nLine2\r\nLine3\r\nLine4");
|
||||
}
|
||||
done();
|
||||
}
|
||||
count++;
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
n1.receive({payload:"Line1",parts:{index:0,type:"string"}}); // string
|
||||
setTimeout(function() {
|
||||
n1.receive({payload:"Line2",parts:{index:1,type:"string"}}); // string
|
||||
},30);
|
||||
setTimeout(function() {
|
||||
n1.receive({payload:"Line3",parts:{index:2,type:"string"}}); // string
|
||||
},60);
|
||||
setTimeout(function() {
|
||||
n1.receive({payload:"Line4",parts:{index:3,type:"string",count:4}}); // string
|
||||
},90);
|
||||
});
|
||||
});
|
||||
|
||||
it('should append to a file after it has been deleted ', function(done) {
|
||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false, wires: [["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
|
Reference in New Issue
Block a user