mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
[groups] Support copy/paste/import/export of groups
This commit is contained in:
parent
9a0c843f29
commit
d1dd7d1d51
@ -500,6 +500,9 @@ RED.nodes = (function() {
|
|||||||
if (n.d === true) {
|
if (n.d === true) {
|
||||||
node.d = true;
|
node.d = true;
|
||||||
}
|
}
|
||||||
|
if (n.g) {
|
||||||
|
node.g = n.g;
|
||||||
|
}
|
||||||
if (node.type == "unknown") {
|
if (node.type == "unknown") {
|
||||||
for (var p in n._orig) {
|
for (var p in n._orig) {
|
||||||
if (n._orig.hasOwnProperty(p)) {
|
if (n._orig.hasOwnProperty(p)) {
|
||||||
@ -547,6 +550,9 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (n.type === "group") {
|
||||||
|
node.nodes = node.nodes.map(function(n) { return n.id });
|
||||||
|
}
|
||||||
if (n._def.category != "config") {
|
if (n._def.category != "config") {
|
||||||
node.x = n.x;
|
node.x = n.x;
|
||||||
node.y = n.y;
|
node.y = n.y;
|
||||||
@ -735,6 +741,11 @@ RED.nodes = (function() {
|
|||||||
nns.push(convertSubflow(subflows[i], exportCredentials));
|
nns.push(convertSubflow(subflows[i], exportCredentials));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i in groups) {
|
||||||
|
if (groups.hasOwnProperty(i)) {
|
||||||
|
nns.push(convertNode(groups[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
for (i in configNodes) {
|
for (i in configNodes) {
|
||||||
if (configNodes.hasOwnProperty(i)) {
|
if (configNodes.hasOwnProperty(i)) {
|
||||||
nns.push(convertNode(configNodes[i], exportCredentials));
|
nns.push(convertNode(configNodes[i], exportCredentials));
|
||||||
@ -861,6 +872,7 @@ RED.nodes = (function() {
|
|||||||
if (n.type != "workspace" &&
|
if (n.type != "workspace" &&
|
||||||
n.type != "tab" &&
|
n.type != "tab" &&
|
||||||
n.type != "subflow" &&
|
n.type != "subflow" &&
|
||||||
|
n.type != "group" &&
|
||||||
!registry.getNodeType(n.type) &&
|
!registry.getNodeType(n.type) &&
|
||||||
n.type.substring(0,8) != "subflow:" &&
|
n.type.substring(0,8) != "subflow:" &&
|
||||||
unknownTypes.indexOf(n.type)==-1) {
|
unknownTypes.indexOf(n.type)==-1) {
|
||||||
@ -910,6 +922,7 @@ RED.nodes = (function() {
|
|||||||
var node_map = {};
|
var node_map = {};
|
||||||
var new_nodes = [];
|
var new_nodes = [];
|
||||||
var new_links = [];
|
var new_links = [];
|
||||||
|
var new_groups = [];
|
||||||
var nid;
|
var nid;
|
||||||
var def;
|
var def;
|
||||||
var configNode;
|
var configNode;
|
||||||
@ -1077,20 +1090,25 @@ RED.nodes = (function() {
|
|||||||
y:parseFloat(n.y || 0),
|
y:parseFloat(n.y || 0),
|
||||||
z:n.z,
|
z:n.z,
|
||||||
type:0,
|
type:0,
|
||||||
wires:n.wires||[],
|
|
||||||
inputLabels: n.inputLabels,
|
|
||||||
outputLabels: n.outputLabels,
|
|
||||||
icon: n.icon,
|
|
||||||
info: n.info,
|
info: n.info,
|
||||||
changed:false,
|
changed:false,
|
||||||
_config:{}
|
_config:{}
|
||||||
};
|
}
|
||||||
|
if (n.type !== "group") {
|
||||||
|
node.wires = n.wires||[];
|
||||||
|
node.inputLabels = n.inputLabels;
|
||||||
|
node.outputLabels = n.outputLabels;
|
||||||
|
node.icon = n.icon;
|
||||||
|
}
|
||||||
if (n.hasOwnProperty('l')) {
|
if (n.hasOwnProperty('l')) {
|
||||||
node.l = n.l;
|
node.l = n.l;
|
||||||
}
|
}
|
||||||
if (n.hasOwnProperty('d')) {
|
if (n.hasOwnProperty('d')) {
|
||||||
node.d = n.d;
|
node.d = n.d;
|
||||||
}
|
}
|
||||||
|
if (n.hasOwnProperty('g')) {
|
||||||
|
node.g = n.g;
|
||||||
|
}
|
||||||
if (createNewIds) {
|
if (createNewIds) {
|
||||||
if (subflow_blacklist[n.z]) {
|
if (subflow_blacklist[n.z]) {
|
||||||
continue;
|
continue;
|
||||||
@ -1127,7 +1145,17 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
node.type = n.type;
|
node.type = n.type;
|
||||||
node._def = def;
|
node._def = def;
|
||||||
if (n.type.substring(0,7) === "subflow") {
|
if (node.type === "group") {
|
||||||
|
node._def = RED.group.def;
|
||||||
|
for (d in node._def.defaults) {
|
||||||
|
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
|
||||||
|
node[d] = n[d];
|
||||||
|
node._config[d] = JSON.stringify(n[d]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node._config.x = node.x;
|
||||||
|
node._config.y = node.y;
|
||||||
|
} else if (n.type.substring(0,7) === "subflow") {
|
||||||
var parentId = n.type.split(":")[1];
|
var parentId = n.type.split(":")[1];
|
||||||
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
||||||
if (createNewIds) {
|
if (createNewIds) {
|
||||||
@ -1217,13 +1245,19 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addNode(node);
|
if (node.type !== "group") {
|
||||||
RED.editor.validateNode(node);
|
addNode(node);
|
||||||
|
RED.editor.validateNode(node);
|
||||||
|
} else {
|
||||||
|
addGroup(node);
|
||||||
|
}
|
||||||
node_map[n.id] = node;
|
node_map[n.id] = node;
|
||||||
// If an 'unknown' config node, it will not have been caught by the
|
// If an 'unknown' config node, it will not have been caught by the
|
||||||
// proper config node handling, so needs adding to new_nodes here
|
// proper config node handling, so needs adding to new_nodes here
|
||||||
if (node.type === "unknown" || node._def.category !== "config") {
|
if (node.type === "unknown" || node._def.category !== "config") {
|
||||||
new_nodes.push(node);
|
new_nodes.push(node);
|
||||||
|
} else if (node.type === "group") {
|
||||||
|
new_groups.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1258,6 +1292,11 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
delete n.wires;
|
delete n.wires;
|
||||||
}
|
}
|
||||||
|
if (n.g && node_map[n.g]) {
|
||||||
|
n.g = node_map[n.g].id;
|
||||||
|
} else {
|
||||||
|
delete n.g
|
||||||
|
}
|
||||||
for (var d3 in n._def.defaults) {
|
for (var d3 in n._def.defaults) {
|
||||||
if (n._def.defaults.hasOwnProperty(d3)) {
|
if (n._def.defaults.hasOwnProperty(d3)) {
|
||||||
if (n._def.defaults[d3].type && node_map[n[d3]]) {
|
if (n._def.defaults[d3].type && node_map[n[d3]]) {
|
||||||
@ -1326,6 +1365,17 @@ RED.nodes = (function() {
|
|||||||
delete n.status.wires;
|
delete n.status.wires;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i=0;i<new_groups.length;i++) {
|
||||||
|
n = new_groups[i];
|
||||||
|
if (n.g && node_map[n.g]) {
|
||||||
|
n.g = node_map[n.g].id;
|
||||||
|
} else {
|
||||||
|
delete n.g;
|
||||||
|
}
|
||||||
|
n.nodes = n.nodes.map(function(id) {
|
||||||
|
return node_map[id];
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
RED.workspaces.refresh();
|
RED.workspaces.refresh();
|
||||||
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace];
|
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace];
|
||||||
|
@ -37,7 +37,8 @@ RED.group = (function() {
|
|||||||
var groupDef = {
|
var groupDef = {
|
||||||
defaults:{
|
defaults:{
|
||||||
name:{value:""},
|
name:{value:""},
|
||||||
style:{value:{}}
|
style:{value:{}},
|
||||||
|
nodes:{value:[]}
|
||||||
},
|
},
|
||||||
category: "config",
|
category: "config",
|
||||||
oneditprepare: function() {
|
oneditprepare: function() {
|
||||||
|
@ -1390,13 +1390,15 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
|||||||
if (!d3.event.shiftKey) {
|
if (!d3.event.shiftKey) {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
var selectedGroups = [];
|
||||||
activeNodes.forEach(function(n) {
|
activeNodes.forEach(function(n) {
|
||||||
if (n.z == RED.workspaces.active() && !n.selected) {
|
if (n.z == RED.workspaces.active() && !n.selected) {
|
||||||
if (n.x > x && n.x < x2 && n.y > y && n.y < y2) {
|
if (n.x > x && n.x < x2 && n.y > y && n.y < y2) {
|
||||||
if (n.g) {
|
if (n.g) {
|
||||||
var group = RED.nodes.group(n.g);
|
var group = RED.nodes.group(n.g);
|
||||||
if (!group.selected) {
|
if (!group.selected) {
|
||||||
selectGroup(RED.nodes.group(n.g),true);
|
selectGroup(group,true);
|
||||||
|
selectedGroups.push(group)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
n.selected = true;
|
n.selected = true;
|
||||||
@ -1406,6 +1408,17 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
var selectionChanged = false;
|
||||||
|
do {
|
||||||
|
selectionChanged = false;
|
||||||
|
selectedGroups.forEach(function(g) {
|
||||||
|
if (g.g && g.selected && RED.nodes.group(g.g).selected) {
|
||||||
|
g.selected = false;
|
||||||
|
selectionChanged = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} while(selectionChanged);
|
||||||
|
|
||||||
if (activeSubflow) {
|
if (activeSubflow) {
|
||||||
activeSubflow.in.forEach(function(n) {
|
activeSubflow.in.forEach(function(n) {
|
||||||
n.selected = (n.x > x && n.x < x2 && n.y > y && n.y < y2);
|
n.selected = (n.x > x && n.x < x2 && n.y > y && n.y < y2);
|
||||||
@ -1550,11 +1563,16 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
|||||||
if (mouse_mode === RED.state.SELECTING_NODE && selectNodesOptions.single) {
|
if (mouse_mode === RED.state.SELECTING_NODE && selectNodesOptions.single) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
exitActiveGroup();
|
||||||
activeGroups.forEach(function(g) {
|
activeGroups.forEach(function(g) {
|
||||||
selectGroup(g, true);
|
if (!g.g) {
|
||||||
if (!g.selected) {
|
selectGroup(g, true);
|
||||||
g.selected = true;
|
if (!g.selected) {
|
||||||
|
g.selected = true;
|
||||||
|
g.dirty = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.selected = false;
|
||||||
g.dirty = true;
|
g.dirty = true;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1940,8 +1958,16 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
nodes = nodes.concat(RED.nodes.filterNodes({z:n.id}));
|
nodes = nodes.concat(RED.nodes.filterNodes({z:n.id}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (moving_set.length > 0) {
|
} else {
|
||||||
nodes = moving_set.map(function(n) { return n.n });
|
if (moving_set.length > 0) {
|
||||||
|
nodes = moving_set.map(function(n) { return n.n });
|
||||||
|
}
|
||||||
|
var groups = activeGroups.filter(function(g) { return g.selected && !g.active });
|
||||||
|
while (groups.length > 0) {
|
||||||
|
var group = groups.shift();
|
||||||
|
nodes.push(group);
|
||||||
|
groups = groups.concat(group.nodes.filter(function(n) { return n.type === "group" }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.length > 0) {
|
if (nodes.length > 0) {
|
||||||
@ -1966,6 +1992,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
clipboard = JSON.stringify(nns);
|
clipboard = JSON.stringify(nns);
|
||||||
|
console.log(nns);
|
||||||
RED.notify(RED._("clipboard.nodeCopied",{count:nns.length}),{id:"clipboard"});
|
RED.notify(RED._("clipboard.nodeCopied",{count:nns.length}),{id:"clipboard"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4536,5 +4563,6 @@ if (DEBUG_EVENTS) { console.warn("nodeMouseDown", mouse_mode,d); }
|
|||||||
chart.scrollLeft(chart.scrollLeft()+x);
|
chart.scrollLeft(chart.scrollLeft()+x);
|
||||||
chart.scrollTop(chart.scrollTop()+y)
|
chart.scrollTop(chart.scrollTop()+y)
|
||||||
}
|
}
|
||||||
|
,ms: function() { return moving_set }
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -85,6 +85,7 @@ module.exports = {
|
|||||||
flow.subflows = {};
|
flow.subflows = {};
|
||||||
flow.configs = {};
|
flow.configs = {};
|
||||||
flow.flows = {};
|
flow.flows = {};
|
||||||
|
flow.groups = {};
|
||||||
flow.missingTypes = [];
|
flow.missingTypes = [];
|
||||||
|
|
||||||
config.forEach(function(n) {
|
config.forEach(function(n) {
|
||||||
@ -95,8 +96,12 @@ module.exports = {
|
|||||||
flow.flows[n.id].configs = {};
|
flow.flows[n.id].configs = {};
|
||||||
flow.flows[n.id].nodes = {};
|
flow.flows[n.id].nodes = {};
|
||||||
}
|
}
|
||||||
|
if (n.type === 'group') {
|
||||||
|
flow.groups[n.id] = n;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: why a separate forEach? this can be merged with above
|
||||||
config.forEach(function(n) {
|
config.forEach(function(n) {
|
||||||
if (n.type === 'subflow') {
|
if (n.type === 'subflow') {
|
||||||
flow.subflows[n.id] = n;
|
flow.subflows[n.id] = n;
|
||||||
@ -108,7 +113,7 @@ module.exports = {
|
|||||||
var linkWires = {};
|
var linkWires = {};
|
||||||
var linkOutNodes = [];
|
var linkOutNodes = [];
|
||||||
config.forEach(function(n) {
|
config.forEach(function(n) {
|
||||||
if (n.type !== 'subflow' && n.type !== 'tab') {
|
if (n.type !== 'subflow' && n.type !== 'tab' && n.type !== 'group') {
|
||||||
var subflowDetails = subflowInstanceRE.exec(n.type);
|
var subflowDetails = subflowInstanceRE.exec(n.type);
|
||||||
|
|
||||||
if ( (subflowDetails && !flow.subflows[subflowDetails[1]]) || (!subflowDetails && !typeRegistry.get(n.type)) ) {
|
if ( (subflowDetails && !flow.subflows[subflowDetails[1]]) || (!subflowDetails && !typeRegistry.get(n.type)) ) {
|
||||||
@ -163,7 +168,7 @@ module.exports = {
|
|||||||
|
|
||||||
var addedTabs = {};
|
var addedTabs = {};
|
||||||
config.forEach(function(n) {
|
config.forEach(function(n) {
|
||||||
if (n.type !== 'subflow' && n.type !== 'tab') {
|
if (n.type !== 'subflow' && n.type !== 'tab' && n.type !== 'group') {
|
||||||
for (var prop in n) {
|
for (var prop in n) {
|
||||||
if (n.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== 'type' && prop !== '_users' && flow.configs.hasOwnProperty(n[prop])) {
|
if (n.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== 'type' && prop !== '_users' && flow.configs.hasOwnProperty(n[prop])) {
|
||||||
// This property references a global config node
|
// This property references a global config node
|
||||||
|
Loading…
x
Reference in New Issue
Block a user