mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'master' into dev
This commit is contained in:
commit
4dd619b8c6
@ -27,6 +27,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "6.12.3",
|
"ajv": "6.12.3",
|
||||||
|
"async-mutex": "0.2.4",
|
||||||
"basic-auth": "2.0.1",
|
"basic-auth": "2.0.1",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"body-parser": "1.19.0",
|
"body-parser": "1.19.0",
|
||||||
|
@ -119,6 +119,9 @@
|
|||||||
if (evt.keyCode === 27) {
|
if (evt.keyCode === 27) {
|
||||||
that.element.val("");
|
that.element.val("");
|
||||||
}
|
}
|
||||||
|
if (evt.keyCode === 13) {
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.element.on("keyup",function(evt) {
|
this.element.on("keyup",function(evt) {
|
||||||
that._change($(this).val());
|
that._change($(this).val());
|
||||||
|
@ -380,11 +380,16 @@ RED.group = (function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var existingGroup;
|
||||||
|
|
||||||
// Second pass, ungroup any groups in the selection and add their contents
|
// Second pass, ungroup any groups in the selection and add their contents
|
||||||
// to the selection
|
// to the selection
|
||||||
for (var i=0; i<selection.nodes.length; i++) {
|
for (var i=0; i<selection.nodes.length; i++) {
|
||||||
n = selection.nodes[i];
|
n = selection.nodes[i];
|
||||||
if (n.type === "group") {
|
if (n.type === "group") {
|
||||||
|
if (!existingGroup) {
|
||||||
|
existingGroup = n;
|
||||||
|
}
|
||||||
ungroupHistoryEvent.groups.push(n);
|
ungroupHistoryEvent.groups.push(n);
|
||||||
nodes = nodes.concat(ungroup(n));
|
nodes = nodes.concat(ungroup(n));
|
||||||
} else {
|
} else {
|
||||||
@ -398,6 +403,10 @@ RED.group = (function() {
|
|||||||
// Finally, create the new group
|
// Finally, create the new group
|
||||||
var group = createGroup(nodes);
|
var group = createGroup(nodes);
|
||||||
if (group) {
|
if (group) {
|
||||||
|
if (existingGroup) {
|
||||||
|
group.style = existingGroup.style;
|
||||||
|
group.name = existingGroup.name;
|
||||||
|
}
|
||||||
RED.view.select({nodes:[group]})
|
RED.view.select({nodes:[group]})
|
||||||
}
|
}
|
||||||
historyEvent.events.push({
|
historyEvent.events.push({
|
||||||
|
@ -1678,7 +1678,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns.length > 0) {
|
if (ns.length > 0 && mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||||
historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()};
|
historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()};
|
||||||
if (activeSpliceLink) {
|
if (activeSpliceLink) {
|
||||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
||||||
@ -2354,6 +2354,10 @@ RED.view = (function() {
|
|||||||
mousedown_port_type = null;
|
mousedown_port_type = null;
|
||||||
activeSpliceLink = null;
|
activeSpliceLink = null;
|
||||||
spliceActive = false;
|
spliceActive = false;
|
||||||
|
if (activeHoverGroup) {
|
||||||
|
activeHoverGroup.hovered = false;
|
||||||
|
activeHoverGroup = null;
|
||||||
|
}
|
||||||
d3.select(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
|
d3.select(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
|
||||||
if (spliceTimer) {
|
if (spliceTimer) {
|
||||||
clearTimeout(spliceTimer);
|
clearTimeout(spliceTimer);
|
||||||
@ -2869,7 +2873,7 @@ RED.view = (function() {
|
|||||||
//RED.touch.radialMenu.show(d3.select(this),pos);
|
//RED.touch.radialMenu.show(d3.select(this),pos);
|
||||||
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||||
RED.keyboard.remove("escape");
|
RED.keyboard.remove("escape");
|
||||||
|
var historyEvent = RED.history.peek();
|
||||||
if (activeSpliceLink) {
|
if (activeSpliceLink) {
|
||||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
||||||
var spliceLink = d3.select(activeSpliceLink).data()[0];
|
var spliceLink = d3.select(activeSpliceLink).data()[0];
|
||||||
@ -2886,12 +2890,27 @@ RED.view = (function() {
|
|||||||
};
|
};
|
||||||
RED.nodes.addLink(link1);
|
RED.nodes.addLink(link1);
|
||||||
RED.nodes.addLink(link2);
|
RED.nodes.addLink(link2);
|
||||||
var historyEvent = RED.history.peek();
|
|
||||||
historyEvent.links = [link1,link2];
|
historyEvent.links = [link1,link2];
|
||||||
historyEvent.removedLinks = [spliceLink];
|
historyEvent.removedLinks = [spliceLink];
|
||||||
updateActiveNodes();
|
updateActiveNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activeHoverGroup) {
|
||||||
|
for (var j=0;j<movingSet.length();j++) {
|
||||||
|
var n = movingSet.get(j);
|
||||||
|
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||||
|
}
|
||||||
|
historyEvent.addedToGroup = activeHoverGroup;
|
||||||
|
|
||||||
|
activeHoverGroup.hovered = false;
|
||||||
|
enterActiveGroup(activeHoverGroup)
|
||||||
|
// TODO: check back whether this should add to moving_set
|
||||||
|
activeGroup.selected = true;
|
||||||
|
activeHoverGroup = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
updateSelection();
|
updateSelection();
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
redraw();
|
redraw();
|
||||||
@ -4418,6 +4437,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
if (d.dirty || dirtyGroups[d.id]) {
|
if (d.dirty || dirtyGroups[d.id]) {
|
||||||
var g = d3.select(this);
|
var g = d3.select(this);
|
||||||
|
var recalculateLabelOffsets = false;
|
||||||
if (d.nodes.length > 0) {
|
if (d.nodes.length > 0) {
|
||||||
// If the group was just moved, all of its contents was
|
// If the group was just moved, all of its contents was
|
||||||
// also moved - so no need to recalculate its bounding box
|
// also moved - so no need to recalculate its bounding box
|
||||||
@ -4446,6 +4466,7 @@ RED.view = (function() {
|
|||||||
d.y = minY;
|
d.y = minY;
|
||||||
d.w = maxX - minX;
|
d.w = maxX - minX;
|
||||||
d.h = maxY - minY;
|
d.h = maxY - minY;
|
||||||
|
recalculateLabelOffsets = true;
|
||||||
// if set explicitly to false, this group has just been
|
// if set explicitly to false, this group has just been
|
||||||
// imported so needed this initial resize calculation.
|
// imported so needed this initial resize calculation.
|
||||||
// Now that's done, delete the flag so the normal
|
// Now that's done, delete the flag so the normal
|
||||||
@ -4459,28 +4480,31 @@ RED.view = (function() {
|
|||||||
} else {
|
} else {
|
||||||
d.w = 40;
|
d.w = 40;
|
||||||
d.h = 40;
|
d.h = 40;
|
||||||
|
recalculateLabelOffsets = true;
|
||||||
}
|
}
|
||||||
if (!d.minWidth) {
|
if (recalculateLabelOffsets) {
|
||||||
if (d.style.label && d.name) {
|
if (!d.minWidth) {
|
||||||
var labelParts = getLabelParts(d.name||"","red-ui-flow-group-label");
|
if (d.style.label && d.name) {
|
||||||
d.minWidth = labelParts.width + 8;
|
var labelParts = getLabelParts(d.name||"","red-ui-flow-group-label");
|
||||||
d.labels = labelParts.lines;
|
d.minWidth = labelParts.width + 8;
|
||||||
} else {
|
d.labels = labelParts.lines;
|
||||||
d.minWidth = 40;
|
} else {
|
||||||
d.labels = [];
|
d.minWidth = 40;
|
||||||
|
d.labels = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
d.w = Math.max(d.minWidth,d.w);
|
||||||
d.w = Math.max(d.minWidth,d.w);
|
if (d.style.label && d.labels.length > 0) {
|
||||||
if (d.style.label && d.labels.length > 0) {
|
var labelPos = d.style["label-position"] || "nw";
|
||||||
var labelPos = d.style["label-position"] || "nw";
|
var h = (d.labels.length-1) * 16;
|
||||||
var h = (d.labels.length-1) * 16;
|
if (labelPos[0] === "s") {
|
||||||
if (labelPos[0] === "s") {
|
h += 8;
|
||||||
h += 8;
|
}
|
||||||
}
|
d.h += h;
|
||||||
d.h += h;
|
if (labelPos[0] === "n") {
|
||||||
if (labelPos[0] === "n") {
|
if (d.nodes.length > 0) {
|
||||||
if (d.nodes.length > 0) {
|
d.y -= h;
|
||||||
d.y -= h;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var runtime;
|
var runtime;
|
||||||
|
var Mutex = require('async-mutex').Mutex;
|
||||||
|
const mutex = new Mutex();
|
||||||
|
|
||||||
var api = module.exports = {
|
var api = module.exports = {
|
||||||
init: function(_runtime) {
|
init: function(_runtime) {
|
||||||
@ -64,35 +66,37 @@ var api = module.exports = {
|
|||||||
* @memberof @node-red/runtime_flows
|
* @memberof @node-red/runtime_flows
|
||||||
*/
|
*/
|
||||||
setFlows: function(opts) {
|
setFlows: function(opts) {
|
||||||
return new Promise(function(resolve,reject) {
|
return mutex.runExclusive(function() {
|
||||||
|
return new Promise(function(resolve,reject) {
|
||||||
|
|
||||||
var flows = opts.flows;
|
var flows = opts.flows;
|
||||||
var deploymentType = opts.deploymentType||"full";
|
var deploymentType = opts.deploymentType||"full";
|
||||||
runtime.log.audit({event: "flows.set",type:deploymentType}, opts.req);
|
runtime.log.audit({event: "flows.set",type:deploymentType}, opts.req);
|
||||||
|
|
||||||
var apiPromise;
|
var apiPromise;
|
||||||
if (deploymentType === 'reload') {
|
if (deploymentType === 'reload') {
|
||||||
apiPromise = runtime.nodes.loadFlows(true);
|
apiPromise = runtime.nodes.loadFlows(true);
|
||||||
} else {
|
} else {
|
||||||
if (flows.hasOwnProperty('rev')) {
|
if (flows.hasOwnProperty('rev')) {
|
||||||
var currentVersion = runtime.nodes.getFlows().rev;
|
var currentVersion = runtime.nodes.getFlows().rev;
|
||||||
if (currentVersion !== flows.rev) {
|
if (currentVersion !== flows.rev) {
|
||||||
var err;
|
var err;
|
||||||
err = new Error();
|
err = new Error();
|
||||||
err.code = "version_mismatch";
|
err.code = "version_mismatch";
|
||||||
err.status = 409;
|
err.status = 409;
|
||||||
//TODO: log warning
|
//TODO: log warning
|
||||||
return reject(err);
|
return reject(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
apiPromise = runtime.nodes.setFlows(flows.flows,flows.credentials,deploymentType);
|
||||||
}
|
}
|
||||||
apiPromise = runtime.nodes.setFlows(flows.flows,flows.credentials,deploymentType);
|
apiPromise.then(function(flowId) {
|
||||||
}
|
return resolve({rev:flowId});
|
||||||
apiPromise.then(function(flowId) {
|
}).catch(function(err) {
|
||||||
return resolve({rev:flowId});
|
runtime.log.warn(runtime.log._("api.flows.error-"+(deploymentType === 'reload'?'reload':'save'),{message:err.message}));
|
||||||
}).catch(function(err) {
|
runtime.log.warn(err.stack);
|
||||||
runtime.log.warn(runtime.log._("api.flows.error-"+(deploymentType === 'reload'?'reload':'save'),{message:err.message}));
|
return reject(err);
|
||||||
runtime.log.warn(err.stack);
|
});
|
||||||
return reject(err);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -107,19 +111,23 @@ var api = module.exports = {
|
|||||||
* @memberof @node-red/runtime_flows
|
* @memberof @node-red/runtime_flows
|
||||||
*/
|
*/
|
||||||
addFlow: function(opts) {
|
addFlow: function(opts) {
|
||||||
return new Promise(function(resolve,reject) {
|
return mutex.runExclusive(function() {
|
||||||
var flow = opts.flow;
|
return new Promise(function (resolve, reject) {
|
||||||
runtime.nodes.addFlow(flow).then(function(id) {
|
var flow = opts.flow;
|
||||||
runtime.log.audit({event: "flow.add",id:id}, opts.req);
|
runtime.nodes.addFlow(flow).then(function (id) {
|
||||||
return resolve(id);
|
runtime.log.audit({event: "flow.add", id: id}, opts.req);
|
||||||
}).catch(function(err) {
|
return resolve(id);
|
||||||
runtime.log.audit({event: "flow.add",error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
}).catch(function (err) {
|
||||||
err.status = 400;
|
runtime.log.audit({
|
||||||
return reject(err);
|
event: "flow.add",
|
||||||
|
error: err.code || "unexpected_error",
|
||||||
|
message: err.toString()
|
||||||
|
}, opts.req);
|
||||||
|
err.status = 400;
|
||||||
|
return reject(err);
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,7 +153,6 @@ var api = module.exports = {
|
|||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Updates an existing flow configuration
|
* Updates an existing flow configuration
|
||||||
@ -158,33 +165,42 @@ var api = module.exports = {
|
|||||||
* @memberof @node-red/runtime_flows
|
* @memberof @node-red/runtime_flows
|
||||||
*/
|
*/
|
||||||
updateFlow: function(opts) {
|
updateFlow: function(opts) {
|
||||||
return new Promise(function (resolve,reject) {
|
return mutex.runExclusive(function() {
|
||||||
var flow = opts.flow;
|
return new Promise(function (resolve, reject) {
|
||||||
var id = opts.id;
|
var flow = opts.flow;
|
||||||
try {
|
var id = opts.id;
|
||||||
runtime.nodes.updateFlow(id,flow).then(function() {
|
try {
|
||||||
runtime.log.audit({event: "flow.update",id:id}, opts.req);
|
runtime.nodes.updateFlow(id, flow).then(function () {
|
||||||
return resolve(id);
|
runtime.log.audit({event: "flow.update", id: id}, opts.req);
|
||||||
}).catch(function(err) {
|
return resolve(id);
|
||||||
runtime.log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
}).catch(function (err) {
|
||||||
err.status = 400;
|
runtime.log.audit({
|
||||||
return reject(err);
|
event: "flow.update",
|
||||||
})
|
error: err.code || "unexpected_error",
|
||||||
} catch(err) {
|
message: err.toString()
|
||||||
if (err.code === 404) {
|
}, opts.req);
|
||||||
runtime.log.audit({event: "flow.update",id:id,error:"not_found"}, opts.req);
|
err.status = 400;
|
||||||
// TODO: this swap around of .code and .status isn't ideal
|
return reject(err);
|
||||||
err.status = 404;
|
})
|
||||||
err.code = "not_found";
|
} catch (err) {
|
||||||
return reject(err);
|
if (err.code === 404) {
|
||||||
} else {
|
runtime.log.audit({event: "flow.update", id: id, error: "not_found"}, opts.req);
|
||||||
runtime.log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
// TODO: this swap around of .code and .status isn't ideal
|
||||||
err.status = 400;
|
err.status = 404;
|
||||||
return reject(err);
|
err.code = "not_found";
|
||||||
|
return reject(err);
|
||||||
|
} else {
|
||||||
|
runtime.log.audit({
|
||||||
|
event: "flow.update",
|
||||||
|
error: err.code || "unexpected_error",
|
||||||
|
message: err.toString()
|
||||||
|
}, opts.req);
|
||||||
|
err.status = 400;
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Deletes a flow
|
* Deletes a flow
|
||||||
@ -196,30 +212,42 @@ var api = module.exports = {
|
|||||||
* @memberof @node-red/runtime_flows
|
* @memberof @node-red/runtime_flows
|
||||||
*/
|
*/
|
||||||
deleteFlow: function(opts) {
|
deleteFlow: function(opts) {
|
||||||
return new Promise(function (resolve,reject) {
|
return mutex.runExclusive(function() {
|
||||||
var id = opts.id;
|
return new Promise(function (resolve, reject) {
|
||||||
try {
|
var id = opts.id;
|
||||||
runtime.nodes.removeFlow(id).then(function() {
|
try {
|
||||||
runtime.log.audit({event: "flow.remove",id:id}, opts.req);
|
runtime.nodes.removeFlow(id).then(function () {
|
||||||
return resolve();
|
runtime.log.audit({event: "flow.remove", id: id}, opts.req);
|
||||||
}).catch(function(err) {
|
return resolve();
|
||||||
runtime.log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
}).catch(function (err) {
|
||||||
err.status = 400;
|
runtime.log.audit({
|
||||||
return reject(err);
|
event: "flow.remove",
|
||||||
});
|
id: id,
|
||||||
} catch(err) {
|
error: err.code || "unexpected_error",
|
||||||
if (err.code === 404) {
|
message: err.toString()
|
||||||
runtime.log.audit({event: "flow.remove",id:id,error:"not_found"}, opts.req);
|
}, opts.req);
|
||||||
// TODO: this swap around of .code and .status isn't ideal
|
err.status = 400;
|
||||||
err.status = 404;
|
return reject(err);
|
||||||
err.code = "not_found";
|
});
|
||||||
return reject(err);
|
} catch (err) {
|
||||||
} else {
|
if (err.code === 404) {
|
||||||
runtime.log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}, opts.req);
|
runtime.log.audit({event: "flow.remove", id: id, error: "not_found"}, opts.req);
|
||||||
err.status = 400;
|
// TODO: this swap around of .code and .status isn't ideal
|
||||||
return reject(err);
|
err.status = 404;
|
||||||
|
err.code = "not_found";
|
||||||
|
return reject(err);
|
||||||
|
} else {
|
||||||
|
runtime.log.audit({
|
||||||
|
event: "flow.remove",
|
||||||
|
id: id,
|
||||||
|
error: err.code || "unexpected_error",
|
||||||
|
message: err.toString()
|
||||||
|
}, opts.req);
|
||||||
|
err.status = 400;
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -264,5 +292,4 @@ var api = module.exports = {
|
|||||||
resolve(sendCredentials);
|
resolve(sendCredentials);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@node-red/registry": "1.2.0-alpha.1",
|
"@node-red/registry": "1.2.0-alpha.1",
|
||||||
"@node-red/util": "1.2.0-alpha.1",
|
"@node-red/util": "1.2.0-alpha.1",
|
||||||
|
"async-mutex": "0.2.4",
|
||||||
"clone": "2.1.2",
|
"clone": "2.1.2",
|
||||||
"express": "4.17.1",
|
"express": "4.17.1",
|
||||||
"fs-extra": "8.1.0",
|
"fs-extra": "8.1.0",
|
||||||
|
Loading…
Reference in New Issue
Block a user