mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
[groups] Add undo support for group actions
This commit is contained in:
parent
0ef3471f8f
commit
7886e5d57c
@ -278,6 +278,13 @@ RED.history = (function() {
|
|||||||
RED.nodes.addLink(ev.removedLinks[i]);
|
RED.nodes.addLink(ev.removedLinks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ev.addToGroup) {
|
||||||
|
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }));
|
||||||
|
inverseEv.removeFromGroup = ev.addToGroup;
|
||||||
|
} else if (ev.removeFromGroup) {
|
||||||
|
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
|
||||||
|
inverseEv.addToGroup = ev.removeFromGroup;
|
||||||
|
}
|
||||||
} else if (ev.t == "edit") {
|
} else if (ev.t == "edit") {
|
||||||
inverseEv = {
|
inverseEv = {
|
||||||
t: "edit",
|
t: "edit",
|
||||||
@ -469,7 +476,52 @@ RED.history = (function() {
|
|||||||
RED.workspaces.order(ev.order);
|
RED.workspaces.order(ev.order);
|
||||||
}
|
}
|
||||||
} else if (ev.t == "createGroup") {
|
} else if (ev.t == "createGroup") {
|
||||||
|
inverseEv = {
|
||||||
|
t: "ungroup",
|
||||||
|
dirty: RED.nodes.dirty(),
|
||||||
|
groups: []
|
||||||
|
}
|
||||||
|
if (ev.groups) {
|
||||||
|
for (i=0;i<ev.groups.length;i++) {
|
||||||
|
inverseEv.groups.push(ev.groups[i]);
|
||||||
|
RED.group.ungroup(ev.groups[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev.t == "ungroup") {
|
||||||
|
inverseEv = {
|
||||||
|
t: "createGroup",
|
||||||
|
dirty: RED.nodes.dirty(),
|
||||||
|
groups: []
|
||||||
|
}
|
||||||
|
if (ev.groups) {
|
||||||
|
for (i=0;i<ev.groups.length;i++) {
|
||||||
|
inverseEv.groups.push(ev.groups[i]);
|
||||||
|
var nodes = ev.groups[i].nodes.slice();
|
||||||
|
ev.groups[i].nodes = [];
|
||||||
|
RED.nodes.addGroup(ev.groups[i]);
|
||||||
|
RED.group.addToGroup(ev.groups[i],nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev.t == "addToGroup") {
|
||||||
|
inverse = {
|
||||||
|
t: "removeFromGroup",
|
||||||
|
dirty: RED.nodes.dirty(),
|
||||||
|
group: ev.group,
|
||||||
|
nodes: ev.nodes
|
||||||
|
}
|
||||||
|
if (ev.nodes) {
|
||||||
|
RED.group.removeFromGroup(ev.group,ev.nodes);
|
||||||
|
}
|
||||||
|
} else if (ev.t == "removeFromGroup") {
|
||||||
|
inverse = {
|
||||||
|
t: "addToGroup",
|
||||||
|
dirty: RED.nodes.dirty(),
|
||||||
|
group: ev.group,
|
||||||
|
nodes: ev.nodes
|
||||||
|
}
|
||||||
|
if (ev.nodes) {
|
||||||
|
RED.group.addToGroup(ev.group,ev.nodes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(modifiedTabs).forEach(function(id) {
|
Object.keys(modifiedTabs).forEach(function(id) {
|
||||||
|
@ -343,6 +343,7 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
var removedNodes = [];
|
var removedNodes = [];
|
||||||
var removedLinks = [];
|
var removedLinks = [];
|
||||||
|
var removedGroups = [];
|
||||||
var n;
|
var n;
|
||||||
var node;
|
var node;
|
||||||
for (n=0;n<nodes.length;n++) {
|
for (n=0;n<nodes.length;n++) {
|
||||||
@ -359,11 +360,14 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
removedGroups = groupsByZ[id] || [];
|
||||||
|
delete groupsByZ[id];
|
||||||
|
|
||||||
for (n=0;n<removedNodes.length;n++) {
|
for (n=0;n<removedNodes.length;n++) {
|
||||||
var result = removeNode(removedNodes[n].id);
|
var result = removeNode(removedNodes[n].id);
|
||||||
removedLinks = removedLinks.concat(result.links);
|
removedLinks = removedLinks.concat(result.links);
|
||||||
}
|
}
|
||||||
return {nodes:removedNodes,links:removedLinks};
|
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSubflow(sf, createNewIds) {
|
function addSubflow(sf, createNewIds) {
|
||||||
|
@ -74,7 +74,14 @@ RED.group = (function() {
|
|||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var group = createGroup(selection.nodes);
|
var group = createGroup(selection.nodes);
|
||||||
if (group) {
|
if (group) {
|
||||||
RED.view.select({nodes:[group]})
|
var historyEvent = {
|
||||||
|
t:"createGroup",
|
||||||
|
groups: [ group ],
|
||||||
|
dirty: RED.nodes.dirty()
|
||||||
|
}
|
||||||
|
RED.history.push(historyEvent);
|
||||||
|
RED.view.select({nodes:[group]});
|
||||||
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,10 +90,22 @@ RED.group = (function() {
|
|||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var newSelection = [];
|
var newSelection = [];
|
||||||
groups = selection.nodes.filter(function(n) { return n.type === "group" });
|
groups = selection.nodes.filter(function(n) { return n.type === "group" });
|
||||||
|
|
||||||
|
var historyEvent = {
|
||||||
|
t:"ungroup",
|
||||||
|
groups: [ ],
|
||||||
|
dirty: RED.nodes.dirty()
|
||||||
|
}
|
||||||
|
RED.history.push(historyEvent);
|
||||||
|
|
||||||
|
|
||||||
groups.forEach(function(g) {
|
groups.forEach(function(g) {
|
||||||
newSelection = newSelection.concat(ungroup(g))
|
newSelection = newSelection.concat(ungroup(g))
|
||||||
|
historyEvent.groups.push(g);
|
||||||
})
|
})
|
||||||
|
RED.history.push(historyEvent);
|
||||||
RED.view.select({nodes:newSelection})
|
RED.view.select({nodes:newSelection})
|
||||||
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +134,17 @@ RED.group = (function() {
|
|||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
|
|
||||||
|
var historyEvent = {
|
||||||
|
t: "multi",
|
||||||
|
events: []
|
||||||
|
}
|
||||||
|
var ungroupHistoryEvent = {
|
||||||
|
t: "ungroup",
|
||||||
|
groups: []
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var n;
|
var n;
|
||||||
var parentGroup;
|
var parentGroup;
|
||||||
// First pass, check they are all in the same parent
|
// First pass, check they are all in the same parent
|
||||||
@ -133,18 +163,28 @@ RED.group = (function() {
|
|||||||
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") {
|
||||||
|
ungroupHistoryEvent.groups.push(n);
|
||||||
nodes = nodes.concat(ungroup(n));
|
nodes = nodes.concat(ungroup(n));
|
||||||
} else {
|
} else {
|
||||||
nodes.push(n);
|
nodes.push(n);
|
||||||
}
|
}
|
||||||
n.dirty = true;
|
n.dirty = true;
|
||||||
}
|
}
|
||||||
|
if (ungroupHistoryEvent.groups.length > 0) {
|
||||||
|
historyEvent.events.push(ungroupHistoryEvent);
|
||||||
|
}
|
||||||
// Finally, create the new group
|
// Finally, create the new group
|
||||||
var group = createGroup(nodes);
|
var group = createGroup(nodes);
|
||||||
if (group) {
|
if (group) {
|
||||||
RED.view.select({nodes:[group]})
|
RED.view.select({nodes:[group]})
|
||||||
}
|
}
|
||||||
|
historyEvent.events.push({
|
||||||
|
t:"createGroup",
|
||||||
|
groups: [ group ],
|
||||||
|
dirty: RED.nodes.dirty()
|
||||||
|
});
|
||||||
|
RED.history.push(historyEvent);
|
||||||
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,37 +193,24 @@ RED.group = (function() {
|
|||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
var n;
|
var n;
|
||||||
var parentGroup;
|
var parentGroup = RED.nodes.group(selection.nodes[0].g);
|
||||||
// First pass, check they are all in the same parent
|
if (parentGroup) {
|
||||||
// TODO: DRY mergeSelection,removeSelection,...
|
try {
|
||||||
for (var i=0; i<selection.nodes.length; i++) {
|
removeFromGroup(parentGroup,selection.nodes);
|
||||||
n = selection.nodes[i];
|
var historyEvent = {
|
||||||
if (i === 0) {
|
t: "removeFromGroup",
|
||||||
parentGroup = n.g;
|
dirty: RED.nodes.dirty(),
|
||||||
} else if (n.g !== parentGroup) {
|
group: parentGroup,
|
||||||
RED.notify("Cannot merge nodes from different groups","error");
|
nodes: selection.nodes
|
||||||
|
}
|
||||||
|
RED.history.push(historyEvent);
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
} catch(err) {
|
||||||
|
RED.notify(err,"error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parentGroup) {
|
RED.view.select({nodes:selection.nodes})
|
||||||
parentGroup = RED.nodes.group(parentGroup);
|
|
||||||
var grandparentGroup = RED.nodes.group(parentGroup.g);
|
|
||||||
for (var i=0; i<selection.nodes.length; i++) {
|
|
||||||
n = selection.nodes[i];
|
|
||||||
n.dirty = true;
|
|
||||||
nodes.push(n);
|
|
||||||
var index = parentGroup.nodes.indexOf(n);
|
|
||||||
parentGroup.nodes.splice(index,1);
|
|
||||||
if (parentGroup.g) {
|
|
||||||
n.g = parentGroup.g
|
|
||||||
grandparentGroup.nodes.push(n);
|
|
||||||
grandparentGroup.dirty = true;
|
|
||||||
} else {
|
|
||||||
delete n.g;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RED.view.select({nodes:nodes})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createGroup(nodes) {
|
function createGroup(nodes) {
|
||||||
@ -217,7 +244,6 @@ RED.group = (function() {
|
|||||||
RED.nodes.addGroup(group);
|
RED.nodes.addGroup(group);
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToGroup(group,nodes) {
|
function addToGroup(group,nodes) {
|
||||||
if (!Array.isArray(nodes)) {
|
if (!Array.isArray(nodes)) {
|
||||||
nodes = [nodes];
|
nodes = [nodes];
|
||||||
@ -274,6 +300,37 @@ RED.group = (function() {
|
|||||||
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
|
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function removeFromGroup(group, nodes) {
|
||||||
|
if (!Array.isArray(nodes)) {
|
||||||
|
nodes = [nodes];
|
||||||
|
}
|
||||||
|
var n;
|
||||||
|
// First pass, check they are all in the same parent
|
||||||
|
// TODO: DRY mergeSelection,removeSelection,...
|
||||||
|
for (var i=0; i<nodes.length; i++) {
|
||||||
|
if (nodes[i].g !== group.id) {
|
||||||
|
RED.notify("Cannot remove node "+nodes[i].id+" from group it isn't in");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentGroup = RED.nodes.group(group.g);
|
||||||
|
for (var i=0; i<nodes.length; i++) {
|
||||||
|
n = nodes[i];
|
||||||
|
n.dirty = true;
|
||||||
|
var index = group.nodes.indexOf(n);
|
||||||
|
group.nodes.splice(index,1);
|
||||||
|
group.dirty = true;
|
||||||
|
if (group.g) {
|
||||||
|
n.g = group.g
|
||||||
|
parentGroup.nodes.push(n);
|
||||||
|
parentGroup.dirty = true;
|
||||||
|
} else {
|
||||||
|
delete n.g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function getNodes(group,recursive) {
|
function getNodes(group,recursive) {
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
@ -312,7 +369,9 @@ RED.group = (function() {
|
|||||||
def: groupDef,
|
def: groupDef,
|
||||||
init: init,
|
init: init,
|
||||||
createGroup: createGroup,
|
createGroup: createGroup,
|
||||||
|
ungroup: ungroup,
|
||||||
addToGroup: addToGroup,
|
addToGroup: addToGroup,
|
||||||
|
removeFromGroup: removeFromGroup,
|
||||||
getNodes: getNodes,
|
getNodes: getNodes,
|
||||||
contains: groupContains
|
contains: groupContains
|
||||||
}
|
}
|
||||||
|
@ -1008,6 +1008,17 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseDown", mouse_mode); }
|
|||||||
}
|
}
|
||||||
if (targetGroup) {
|
if (targetGroup) {
|
||||||
RED.group.addToGroup(targetGroup, nn);
|
RED.group.addToGroup(targetGroup, nn);
|
||||||
|
if (historyEvent.t !== "multi") {
|
||||||
|
historyEvent = {
|
||||||
|
t:'multi',
|
||||||
|
events: [historyEvent]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
historyEvent.events.push({
|
||||||
|
t: "addToGroup",
|
||||||
|
group: targetGroup,
|
||||||
|
nodes: nn
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1482,11 +1493,14 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
|||||||
}
|
}
|
||||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||||
if (moving_set.length > 0) {
|
if (moving_set.length > 0) {
|
||||||
|
var addedToGroup = null;
|
||||||
if (activeHoverGroup) {
|
if (activeHoverGroup) {
|
||||||
for (var j=0;j<moving_set.length;j++) {
|
for (var j=0;j<moving_set.length;j++) {
|
||||||
var n = moving_set[j];
|
var n = moving_set[j];
|
||||||
RED.group.addToGroup(activeHoverGroup,n.n);
|
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||||
}
|
}
|
||||||
|
addedToGroup = activeHoverGroup;
|
||||||
|
|
||||||
activeHoverGroup.hovered = false;
|
activeHoverGroup.hovered = false;
|
||||||
activeHoverGroup.dirty = true;
|
activeHoverGroup.dirty = true;
|
||||||
activeHoverGroup.active = true;
|
activeHoverGroup.active = true;
|
||||||
@ -1527,6 +1541,9 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
|||||||
historyEvent.removedLinks = [spliceLink];
|
historyEvent.removedLinks = [spliceLink];
|
||||||
updateActiveNodes();
|
updateActiveNodes();
|
||||||
}
|
}
|
||||||
|
if (addedToGroup) {
|
||||||
|
historyEvent.addToGroup = addedToGroup;
|
||||||
|
}
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
}
|
}
|
||||||
@ -1813,6 +1830,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
dirty: RED.nodes.dirty(),
|
dirty: RED.nodes.dirty(),
|
||||||
nodes: [],
|
nodes: [],
|
||||||
links: [],
|
links: [],
|
||||||
|
groups: [],
|
||||||
workspaces: [],
|
workspaces: [],
|
||||||
subflows: []
|
subflows: []
|
||||||
}
|
}
|
||||||
@ -1832,6 +1850,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
}
|
}
|
||||||
historyEvent.nodes = historyEvent.nodes.concat(subEvent.nodes);
|
historyEvent.nodes = historyEvent.nodes.concat(subEvent.nodes);
|
||||||
historyEvent.links = historyEvent.links.concat(subEvent.links);
|
historyEvent.links = historyEvent.links.concat(subEvent.links);
|
||||||
|
historyEvent.groups = historyEvent.groups.concat(subEvent.groups);
|
||||||
}
|
}
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
@ -1842,9 +1861,9 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
var result;
|
var result;
|
||||||
var removedNodes = [];
|
var removedNodes = [];
|
||||||
var removedLinks = [];
|
var removedLinks = [];
|
||||||
|
var removedGroups = [];
|
||||||
var removedSubflowOutputs = [];
|
var removedSubflowOutputs = [];
|
||||||
var removedSubflowInputs = [];
|
var removedSubflowInputs = [];
|
||||||
var removedGroups = [];
|
|
||||||
var removedSubflowStatus;
|
var removedSubflowStatus;
|
||||||
var subflowInstances = [];
|
var subflowInstances = [];
|
||||||
|
|
||||||
@ -1911,7 +1930,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
subflowInstances = instances.instances;
|
subflowInstances = instances.instances;
|
||||||
}
|
}
|
||||||
moving_set = [];
|
moving_set = [];
|
||||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus) {
|
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus || removedGroups.length > 0) {
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1964,6 +1983,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
t:"delete",
|
t:"delete",
|
||||||
nodes:removedNodes,
|
nodes:removedNodes,
|
||||||
links:removedLinks,
|
links:removedLinks,
|
||||||
|
groups: removedGroups,
|
||||||
subflowOutputs:removedSubflowOutputs,
|
subflowOutputs:removedSubflowOutputs,
|
||||||
subflowInputs:removedSubflowInputs,
|
subflowInputs:removedSubflowInputs,
|
||||||
subflow: {
|
subflow: {
|
||||||
@ -2005,7 +2025,9 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
}
|
}
|
||||||
var groups = activeGroups.filter(function(g) { return g.selected && !g.active });
|
var groups = activeGroups.filter(function(g) { return g.selected && !g.active });
|
||||||
while (groups.length > 0) {
|
while (groups.length > 0) {
|
||||||
|
console.log("GROUPS",groups.slice())
|
||||||
var group = groups.shift();
|
var group = groups.shift();
|
||||||
|
console.log("GROUP",group);
|
||||||
nodes.push(group);
|
nodes.push(group);
|
||||||
groups = groups.concat(group.nodes.filter(function(n) { return n.type === "group" }))
|
groups = groups.concat(group.nodes.filter(function(n) { return n.type === "group" }))
|
||||||
}
|
}
|
||||||
@ -2033,7 +2055,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
clipboard = JSON.stringify(nns);
|
clipboard = JSON.stringify(nns);
|
||||||
console.log(nns);
|
console.warn(nns);
|
||||||
RED.notify(RED._("clipboard.nodeCopied",{count:nns.length}),{id:"clipboard"});
|
RED.notify(RED._("clipboard.nodeCopied",{count:nns.length}),{id:"clipboard"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4486,6 +4508,7 @@ if (DEBUG_EVENTS) { console.warn("nodeMouseDown", mouse_mode,d); }
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getGroupAtPoint: getGroupAt,
|
||||||
reveal: function(id) {
|
reveal: function(id) {
|
||||||
if (RED.nodes.workspace(id) || RED.nodes.subflow(id)) {
|
if (RED.nodes.workspace(id) || RED.nodes.subflow(id)) {
|
||||||
RED.workspaces.show(id);
|
RED.workspaces.show(id);
|
||||||
|
Loading…
Reference in New Issue
Block a user