mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge changes by reimporting changed node config
This commit is contained in:
		| @@ -16,6 +16,289 @@ | ||||
| RED.history = (function() { | ||||
|     var undo_history = []; | ||||
|  | ||||
|     function undoEvent(ev) { | ||||
|         var i; | ||||
|         var len; | ||||
|         var node; | ||||
|         var subflow; | ||||
|         var modifiedTabs = {}; | ||||
|         if (ev) { | ||||
|             if (ev.t == 'multi') { | ||||
|                 len = ev.events.length; | ||||
|                 for (i=len-1;i>=0;i--) { | ||||
|                     undoEvent(ev.events[i]); | ||||
|                 } | ||||
|             } else if (ev.t == 'replace') { | ||||
|                 RED.nodes.clear(); | ||||
|                 var imported = RED.nodes.import(ev.config); | ||||
|                 imported[0].forEach(function(n) { | ||||
|                     if (ev.changed[n.id]) { | ||||
|                         n.changed = true; | ||||
|                     } | ||||
|                 }) | ||||
|  | ||||
|                 RED.nodes.version(ev.rev); | ||||
|             } else if (ev.t == 'add') { | ||||
|                 if (ev.nodes) { | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         node = RED.nodes.node(ev.nodes[i]); | ||||
|                         if (node.z) { | ||||
|                             modifiedTabs[node.z] = true; | ||||
|                         } | ||||
|                         RED.nodes.remove(ev.nodes[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.workspaces) { | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
|                         RED.nodes.removeWorkspace(ev.workspaces[i].id); | ||||
|                         RED.workspaces.remove(ev.workspaces[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflows) { | ||||
|                     for (i=0;i<ev.subflows.length;i++) { | ||||
|                         RED.nodes.removeSubflow(ev.subflows[i]); | ||||
|                         RED.workspaces.remove(ev.subflows[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     if (ev.subflow.instances) { | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                     if (ev.subflow.hasOwnProperty('changed')) { | ||||
|                         subflow = RED.nodes.subflow(ev.subflow.id); | ||||
|                         if (subflow) { | ||||
|                             subflow.changed = ev.subflow.changed; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.removedLinks) { | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } else if (ev.t == "delete") { | ||||
|                 if (ev.workspaces) { | ||||
|                     for (i=0;i<ev.workspaces.length;i++) { | ||||
|                         RED.nodes.addWorkspace(ev.workspaces[i]); | ||||
|                         RED.workspaces.add(ev.workspaces[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow && ev.subflow.subflow) { | ||||
|                     RED.nodes.addSubflow(ev.subflow.subflow); | ||||
|                 } | ||||
|                 if (ev.subflowInputs && ev.subflowInputs.length > 0) { | ||||
|                     subflow = RED.nodes.subflow(ev.subflowInputs[0].z); | ||||
|                     subflow.in.push(ev.subflowInputs[0]); | ||||
|                     subflow.in[0].dirty = true; | ||||
|                 } | ||||
|                 if (ev.subflowOutputs && ev.subflowOutputs.length > 0) { | ||||
|                     subflow = RED.nodes.subflow(ev.subflowOutputs[0].z); | ||||
|                     ev.subflowOutputs.sort(function(a,b) { return a.i-b.i}); | ||||
|                     for (i=0;i<ev.subflowOutputs.length;i++) { | ||||
|                         var output = ev.subflowOutputs[i]; | ||||
|                         subflow.out.splice(output.i,0,output); | ||||
|                         for (var j=output.i+1;j<subflow.out.length;j++) { | ||||
|                             subflow.out[j].i++; | ||||
|                             subflow.out[j].dirty = true; | ||||
|                         } | ||||
|                         RED.nodes.eachLink(function(l) { | ||||
|                             if (l.source.type == "subflow:"+subflow.id) { | ||||
|                                 if (l.sourcePort >= output.i) { | ||||
|                                     l.sourcePort++; | ||||
|                                 } | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow && ev.subflow.hasOwnProperty('instances')) { | ||||
|                     ev.subflow.instances.forEach(function(n) { | ||||
|                         var node = RED.nodes.node(n.id); | ||||
|                         if (node) { | ||||
|                             node.changed = n.changed; | ||||
|                             node.dirty = true; | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
|                 if (subflow) { | ||||
|                     RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) { | ||||
|                         n.inputs = subflow.in.length; | ||||
|                         n.outputs = subflow.out.length; | ||||
|                         while (n.outputs > n.ports.length) { | ||||
|                             n.ports.push(n.ports.length); | ||||
|                         } | ||||
|                         n.resize = true; | ||||
|                         n.dirty = true; | ||||
|                     }); | ||||
|                 } | ||||
|                 if (ev.nodes) { | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         RED.nodes.add(ev.nodes[i]); | ||||
|                         modifiedTabs[ev.nodes[i].z] = true; | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.changes) { | ||||
|                     for (i in ev.changes) { | ||||
|                         if (ev.changes.hasOwnProperty(i)) { | ||||
|                             node = RED.nodes.node(i); | ||||
|                             if (node) { | ||||
|                                 for (var d in ev.changes[i]) { | ||||
|                                     if (ev.changes[i].hasOwnProperty(d)) { | ||||
|                                         node[d] = ev.changes[i][d]; | ||||
|                                     } | ||||
|                                 } | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|             } else if (ev.t == "move") { | ||||
|                 for (i=0;i<ev.nodes.length;i++) { | ||||
|                     var n = ev.nodes[i]; | ||||
|                     n.n.x = n.ox; | ||||
|                     n.n.y = n.oy; | ||||
|                     n.n.dirty = true; | ||||
|                     n.n.changed = n.changed; | ||||
|                 } | ||||
|                 // A move could have caused a link splice | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.removedLinks) { | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "edit") { | ||||
|                 for (i in ev.changes) { | ||||
|                     if (ev.changes.hasOwnProperty(i)) { | ||||
|                         if (ev.node._def.defaults[i].type) { | ||||
|                             // This is a config node property | ||||
|                             var currentConfigNode = RED.nodes.node(ev.node[i]); | ||||
|                             if (currentConfigNode) { | ||||
|                                 currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1); | ||||
|                             } | ||||
|                             var newConfigNode = RED.nodes.node(ev.changes[i]); | ||||
|                             if (newConfigNode) { | ||||
|                                 newConfigNode.users.push(ev.node); | ||||
|                             } | ||||
|                         } | ||||
|                         ev.node[i] = ev.changes[i]; | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.subflow) { | ||||
|                     if (ev.subflow.hasOwnProperty('inputCount')) { | ||||
|                         if (ev.node.in.length > ev.subflow.inputCount) { | ||||
|                             ev.node.in.splice(ev.subflow.inputCount); | ||||
|                         } else if (ev.subflow.inputs.length > 0) { | ||||
|                             ev.node.in = ev.node.in.concat(ev.subflow.inputs); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow.hasOwnProperty('outputCount')) { | ||||
|                         if (ev.node.out.length > ev.subflow.outputCount) { | ||||
|                             ev.node.out.splice(ev.subflow.outputCount); | ||||
|                         } else if (ev.subflow.outputs.length > 0) { | ||||
|                             ev.node.out = ev.node.out.concat(ev.subflow.outputs); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow.hasOwnProperty('instances')) { | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                     RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) { | ||||
|                         n.inputs = ev.node.in.length; | ||||
|                         n.outputs = ev.node.out.length; | ||||
|                         RED.editor.updateNodeProperties(n); | ||||
|                     }); | ||||
|                 } else { | ||||
|                     var outputMap; | ||||
|                     if (ev.outputMap) { | ||||
|                         outputMap = {}; | ||||
|                         for (var port in ev.outputMap) { | ||||
|                             if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== -1) { | ||||
|                                 outputMap[ev.outputMap[port]] = port; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     RED.editor.updateNodeProperties(ev.node,outputMap); | ||||
|                     RED.editor.validateNode(ev.node); | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.addLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 ev.node.dirty = true; | ||||
|                 ev.node.changed = ev.changed; | ||||
|             } else if (ev.t == "createSubflow") { | ||||
|                 if (ev.nodes) { | ||||
|                     RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                         n.z = ev.activeWorkspace; | ||||
|                         n.dirty = true; | ||||
|                     }); | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         RED.nodes.remove(ev.nodes[i]); | ||||
|                     } | ||||
|                 } | ||||
|                 if (ev.links) { | ||||
|                     for (i=0;i<ev.links.length;i++) { | ||||
|                         RED.nodes.removeLink(ev.links[i]); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 RED.nodes.removeSubflow(ev.subflow.subflow); | ||||
|                 RED.workspaces.remove(ev.subflow.subflow); | ||||
|  | ||||
|                 if (ev.removedLinks) { | ||||
|                     for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                         RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                     } | ||||
|                 } | ||||
|             } else if (ev.t == "reorder") { | ||||
|                 if (ev.order) { | ||||
|                     RED.workspaces.order(ev.order); | ||||
|                 } | ||||
|             } | ||||
|             Object.keys(modifiedTabs).forEach(function(id) { | ||||
|                 var subflow = RED.nodes.subflow(id); | ||||
|                 if (subflow) { | ||||
|                     RED.editor.validateNode(subflow); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             RED.nodes.dirty(ev.dirty); | ||||
|             RED.view.redraw(true); | ||||
|             RED.palette.refresh(); | ||||
|             RED.workspaces.refresh(); | ||||
|             RED.sidebar.config.refresh(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         //TODO: this function is a placeholder until there is a 'save' event that can be listened to | ||||
|         markAllDirty: function() { | ||||
| @@ -34,269 +317,7 @@ RED.history = (function() { | ||||
|         }, | ||||
|         pop: function() { | ||||
|             var ev = undo_history.pop(); | ||||
|             var i; | ||||
|             var node; | ||||
|             var subflow; | ||||
|             var modifiedTabs = {}; | ||||
|             if (ev) { | ||||
|                 if (ev.t == 'add') { | ||||
|                     if (ev.nodes) { | ||||
|                         for (i=0;i<ev.nodes.length;i++) { | ||||
|                             node = RED.nodes.node(ev.nodes[i]); | ||||
|                             if (node.z) { | ||||
|                                 modifiedTabs[node.z] = true; | ||||
|                             } | ||||
|                             RED.nodes.remove(ev.nodes[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.removeLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.workspaces) { | ||||
|                         for (i=0;i<ev.workspaces.length;i++) { | ||||
|                             RED.nodes.removeWorkspace(ev.workspaces[i].id); | ||||
|                             RED.workspaces.remove(ev.workspaces[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflows) { | ||||
|                         for (i=0;i<ev.subflows.length;i++) { | ||||
|                             RED.nodes.removeSubflow(ev.subflows[i]); | ||||
|                             RED.workspaces.remove(ev.subflows[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow) { | ||||
|                         if (ev.subflow.instances) { | ||||
|                             ev.subflow.instances.forEach(function(n) { | ||||
|                                 var node = RED.nodes.node(n.id); | ||||
|                                 if (node) { | ||||
|                                     node.changed = n.changed; | ||||
|                                     node.dirty = true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                         if (ev.subflow.hasOwnProperty('changed')) { | ||||
|                             subflow = RED.nodes.subflow(ev.subflow.id); | ||||
|                             if (subflow) { | ||||
|                                 subflow.changed = ev.subflow.changed; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.removedLinks) { | ||||
|                         for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                             RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                 } else if (ev.t == "delete") { | ||||
|                     if (ev.workspaces) { | ||||
|                         for (i=0;i<ev.workspaces.length;i++) { | ||||
|                             RED.nodes.addWorkspace(ev.workspaces[i]); | ||||
|                             RED.workspaces.add(ev.workspaces[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow && ev.subflow.subflow) { | ||||
|                         RED.nodes.addSubflow(ev.subflow.subflow); | ||||
|                     } | ||||
|                     if (ev.subflowInputs && ev.subflowInputs.length > 0) { | ||||
|                         subflow = RED.nodes.subflow(ev.subflowInputs[0].z); | ||||
|                         subflow.in.push(ev.subflowInputs[0]); | ||||
|                         subflow.in[0].dirty = true; | ||||
|                     } | ||||
|                     if (ev.subflowOutputs && ev.subflowOutputs.length > 0) { | ||||
|                         subflow = RED.nodes.subflow(ev.subflowOutputs[0].z); | ||||
|                         ev.subflowOutputs.sort(function(a,b) { return a.i-b.i}); | ||||
|                         for (i=0;i<ev.subflowOutputs.length;i++) { | ||||
|                             var output = ev.subflowOutputs[i]; | ||||
|                             subflow.out.splice(output.i,0,output); | ||||
|                             for (var j=output.i+1;j<subflow.out.length;j++) { | ||||
|                                 subflow.out[j].i++; | ||||
|                                 subflow.out[j].dirty = true; | ||||
|                             } | ||||
|                             RED.nodes.eachLink(function(l) { | ||||
|                                 if (l.source.type == "subflow:"+subflow.id) { | ||||
|                                     if (l.sourcePort >= output.i) { | ||||
|                                         l.sourcePort++; | ||||
|                                     } | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow && ev.subflow.hasOwnProperty('instances')) { | ||||
|                         ev.subflow.instances.forEach(function(n) { | ||||
|                             var node = RED.nodes.node(n.id); | ||||
|                             if (node) { | ||||
|                                 node.changed = n.changed; | ||||
|                                 node.dirty = true; | ||||
|                             } | ||||
|                         }); | ||||
|                     } | ||||
|                     if (subflow) { | ||||
|                         RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) { | ||||
|                             n.inputs = subflow.in.length; | ||||
|                             n.outputs = subflow.out.length; | ||||
|                             while (n.outputs > n.ports.length) { | ||||
|                                 n.ports.push(n.ports.length); | ||||
|                             } | ||||
|                             n.resize = true; | ||||
|                             n.dirty = true; | ||||
|                         }); | ||||
|                     } | ||||
|                     if (ev.nodes) { | ||||
|                         for (i=0;i<ev.nodes.length;i++) { | ||||
|                             RED.nodes.add(ev.nodes[i]); | ||||
|                             modifiedTabs[ev.nodes[i].z] = true; | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.addLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.changes) { | ||||
|                         for (i in ev.changes) { | ||||
|                             if (ev.changes.hasOwnProperty(i)) { | ||||
|                                 node = RED.nodes.node(i); | ||||
|                                 if (node) { | ||||
|                                     for (var d in ev.changes[i]) { | ||||
|                                         if (ev.changes[i].hasOwnProperty(d)) { | ||||
|                                             node[d] = ev.changes[i][d]; | ||||
|                                         } | ||||
|                                     } | ||||
|                                     node.dirty = true; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 } else if (ev.t == "move") { | ||||
|                     for (i=0;i<ev.nodes.length;i++) { | ||||
|                         var n = ev.nodes[i]; | ||||
|                         n.n.x = n.ox; | ||||
|                         n.n.y = n.oy; | ||||
|                         n.n.dirty = true; | ||||
|                         n.n.changed = n.changed; | ||||
|                     } | ||||
|                     // A move could have caused a link splice | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.removeLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.removedLinks) { | ||||
|                         for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                             RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (ev.t == "edit") { | ||||
|                     for (i in ev.changes) { | ||||
|                         if (ev.changes.hasOwnProperty(i)) { | ||||
|                             if (ev.node._def.defaults[i].type) { | ||||
|                                 // This is a config node property | ||||
|                                 var currentConfigNode = RED.nodes.node(ev.node[i]); | ||||
|                                 if (currentConfigNode) { | ||||
|                                     currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1); | ||||
|                                 } | ||||
|                                 var newConfigNode = RED.nodes.node(ev.changes[i]); | ||||
|                                 if (newConfigNode) { | ||||
|                                     newConfigNode.users.push(ev.node); | ||||
|                                 } | ||||
|                             } | ||||
|                             ev.node[i] = ev.changes[i]; | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.subflow) { | ||||
|                         if (ev.subflow.hasOwnProperty('inputCount')) { | ||||
|                             if (ev.node.in.length > ev.subflow.inputCount) { | ||||
|                                 ev.node.in.splice(ev.subflow.inputCount); | ||||
|                             } else if (ev.subflow.inputs.length > 0) { | ||||
|                                 ev.node.in = ev.node.in.concat(ev.subflow.inputs); | ||||
|                             } | ||||
|                         } | ||||
|                         if (ev.subflow.hasOwnProperty('outputCount')) { | ||||
|                             if (ev.node.out.length > ev.subflow.outputCount) { | ||||
|                                 ev.node.out.splice(ev.subflow.outputCount); | ||||
|                             } else if (ev.subflow.outputs.length > 0) { | ||||
|                                 ev.node.out = ev.node.out.concat(ev.subflow.outputs); | ||||
|                             } | ||||
|                         } | ||||
|                         if (ev.subflow.hasOwnProperty('instances')) { | ||||
|                             ev.subflow.instances.forEach(function(n) { | ||||
|                                 var node = RED.nodes.node(n.id); | ||||
|                                 if (node) { | ||||
|                                     node.changed = n.changed; | ||||
|                                     node.dirty = true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         } | ||||
|                         RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) { | ||||
|                             n.inputs = ev.node.in.length; | ||||
|                             n.outputs = ev.node.out.length; | ||||
|                             RED.editor.updateNodeProperties(n); | ||||
|                         }); | ||||
|                     } else { | ||||
|                         var outputMap; | ||||
|                         if (ev.outputMap) { | ||||
|                             outputMap = {}; | ||||
|                             for (var port in ev.outputMap) { | ||||
|                                 if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== -1) { | ||||
|                                     outputMap[ev.outputMap[port]] = port; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         RED.editor.updateNodeProperties(ev.node,outputMap); | ||||
|                         RED.editor.validateNode(ev.node); | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.addLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     ev.node.dirty = true; | ||||
|                     ev.node.changed = ev.changed; | ||||
|                 } else if (ev.t == "createSubflow") { | ||||
|                     if (ev.nodes) { | ||||
|                         RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) { | ||||
|                             n.z = ev.activeWorkspace; | ||||
|                             n.dirty = true; | ||||
|                         }); | ||||
|                         for (i=0;i<ev.nodes.length;i++) { | ||||
|                             RED.nodes.remove(ev.nodes[i]); | ||||
|                         } | ||||
|                     } | ||||
|                     if (ev.links) { | ||||
|                         for (i=0;i<ev.links.length;i++) { | ||||
|                             RED.nodes.removeLink(ev.links[i]); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     RED.nodes.removeSubflow(ev.subflow.subflow); | ||||
|                     RED.workspaces.remove(ev.subflow.subflow); | ||||
|  | ||||
|                     if (ev.removedLinks) { | ||||
|                         for (i=0;i<ev.removedLinks.length;i++) { | ||||
|                             RED.nodes.addLink(ev.removedLinks[i]); | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (ev.t == "reorder") { | ||||
|                     if (ev.order) { | ||||
|                         RED.workspaces.order(ev.order); | ||||
|                     } | ||||
|                 } | ||||
|                 Object.keys(modifiedTabs).forEach(function(id) { | ||||
|                     var subflow = RED.nodes.subflow(id); | ||||
|                     if (subflow) { | ||||
|                         RED.editor.validateNode(subflow); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 RED.nodes.dirty(ev.dirty); | ||||
|                 RED.view.redraw(true); | ||||
|                 RED.palette.refresh(); | ||||
|                 RED.workspaces.refresh(); | ||||
|                 RED.sidebar.config.refresh(); | ||||
|             } | ||||
|             undoEvent(ev); | ||||
|         }, | ||||
|         peek: function() { | ||||
|             return undo_history[undo_history.length-1]; | ||||
|   | ||||
| @@ -701,17 +701,19 @@ RED.nodes = (function() { | ||||
|         } | ||||
|  | ||||
|         var activeWorkspace = RED.workspaces.active(); | ||||
|         //TODO: check the z of the subflow instance and check _that_ if it exists | ||||
|         var activeSubflow = getSubflow(activeWorkspace); | ||||
|         if (activeSubflow) { | ||||
|             for (i=0;i<newNodes.length;i++) { | ||||
|                 var m = /^subflow:(.+)$/.exec(newNodes[i].type); | ||||
|                 if (m) { | ||||
|                     var subflowId = m[1]; | ||||
|         for (i=0;i<newNodes.length;i++) { | ||||
|             var m = /^subflow:(.+)$/.exec(newNodes[i].type); | ||||
|             if (m) { | ||||
|                 var subflowId = m[1]; | ||||
|                 var parent = getSubflow(newNodes[i].z || activeWorkspace); | ||||
|                 if (parent) { | ||||
|                     var err; | ||||
|                     if (subflowId === activeSubflow.id) { | ||||
|                     if (subflowId === parent.id) { | ||||
|                         err = new Error(RED._("notification.errors.cannotAddSubflowToItself")); | ||||
|                     } | ||||
|                     if (subflowContains(m[1],activeSubflow.id)) { | ||||
|                     if (subflowContains(subflowId,parent.id)) { | ||||
|                         err = new Error(RED._("notification.errors.cannotAddCircularReference")); | ||||
|                     } | ||||
|                     if (err) { | ||||
| @@ -1144,6 +1146,38 @@ RED.nodes = (function() { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function clear() { | ||||
|         nodes = []; | ||||
|         links = []; | ||||
|         configNodes = {}; | ||||
|         workspacesOrder = []; | ||||
|         var subflowIds = Object.keys(subflows); | ||||
|         subflowIds.forEach(function(id) { | ||||
|             RED.subflow.removeSubflow(id) | ||||
|         }); | ||||
|         var workspaceIds = Object.keys(workspaces); | ||||
|         workspaceIds.forEach(function(id) { | ||||
|             RED.workspaces.remove(workspaces[id]); | ||||
|         }); | ||||
|         defaultWorkspace = null; | ||||
|  | ||||
|         RED.nodes.dirty(true); | ||||
|         RED.view.redraw(true); | ||||
|         RED.palette.refresh(); | ||||
|         RED.workspaces.refresh(); | ||||
|         RED.sidebar.config.refresh(); | ||||
|  | ||||
|         // var node_defs = {}; | ||||
|         // var nodes = []; | ||||
|         // var configNodes = {}; | ||||
|         // var links = []; | ||||
|         // var defaultWorkspace; | ||||
|         // var workspaces = {}; | ||||
|         // var workspacesOrder =[]; | ||||
|         // var subflows = {}; | ||||
|         // var loadedFlowVersion = null; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         registry:registry, | ||||
|         setNodeList: registry.setNodeList, | ||||
| @@ -1160,6 +1194,7 @@ RED.nodes = (function() { | ||||
|  | ||||
|         add: addNode, | ||||
|         remove: removeNode, | ||||
|         clear: clear, | ||||
|  | ||||
|         addLink: addLink, | ||||
|         removeLink: removeLink, | ||||
|   | ||||
| @@ -105,6 +105,9 @@ RED.tabs = (function() { | ||||
|             if (typeof link === "string") { | ||||
|                 link = ul.find("a[href='#"+link+"']"); | ||||
|             } | ||||
|             if (link.length === 0) { | ||||
|                 return; | ||||
|             } | ||||
|             if (!link.parent().hasClass("active")) { | ||||
|                 ul.children().removeClass("active"); | ||||
|                 ul.children().css({"transition": "width 100ms"}); | ||||
|   | ||||
| @@ -119,6 +119,8 @@ RED.deploy = (function() { | ||||
|                         text: RED._("deploy.confirm.button.merge"), | ||||
|                         class: "primary disabled", | ||||
|                         click: function() { | ||||
|                             RED.diff.mergeDiff(currentDiff); | ||||
|                             $( this ).dialog( "close" ); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
| @@ -156,7 +158,7 @@ RED.deploy = (function() { | ||||
|  | ||||
|                         var now = Date.now(); | ||||
|                         RED.diff.getRemoteDiff(function(diff) { | ||||
|                             var ellapsed = Math.max(2000 - (Date.now()-now), 0); | ||||
|                             var ellapsed = Math.max(1000 - (Date.now()-now), 0); | ||||
|                             currentDiff = diff; | ||||
|                             setTimeout(function() { | ||||
|                                 $("#node-dialog-confirm-deploy-conflict-checking").hide(); | ||||
| @@ -239,25 +241,6 @@ RED.deploy = (function() { | ||||
|         $( "#node-dialog-confirm-deploy-conflict" ).show(); | ||||
|         $( "#node-dialog-confirm-deploy-type" ).val("conflict"); | ||||
|         $( "#node-dialog-confirm-deploy" ).dialog( "open" ); | ||||
|  | ||||
|         // $("#node-dialog-confirm-deploy-review").append($('<img src="red/images/spin.svg" style="background: rgba(255,255,255,0.8); margin-top: -16px; margin-left: -8px; height:16px; position: absolute; "/>')); | ||||
|         // $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",0.4); | ||||
|         // $("#node-dialog-confirm-deploy-review").attr("disabled",true).addClass("disabled"); | ||||
|         // $.ajax({ | ||||
|         //     headers: { | ||||
|         //         "Accept":"application/json", | ||||
|         //     }, | ||||
|         //     cache: false, | ||||
|         //     url: 'flows', | ||||
|         //     success: function(nodes) { | ||||
|         //         var newNodes = nodes.flows; | ||||
|         //         var newRevision = nodes.rev; | ||||
|         //         generateDiff(currentNodes,newNodes); | ||||
|         //         $("#node-dialog-confirm-deploy-review").attr("disabled",false).removeClass("disabled"); | ||||
|         //         $("#node-dialog-confirm-deploy-review img").remove(); | ||||
|         //         $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",1); | ||||
|         //     } | ||||
|         // }); | ||||
|     } | ||||
|  | ||||
|     function save(skipValidation,force) { | ||||
|   | ||||
| @@ -4,10 +4,10 @@ RED.diff = (function() { | ||||
|  | ||||
|     function init() { | ||||
|  | ||||
|         RED.actions.add("core:show-current-diff",showLocalDiff); | ||||
|         // RED.actions.add("core:show-current-diff",showLocalDiff); | ||||
|         RED.actions.add("core:show-remote-diff",showRemoteDiff); | ||||
|  | ||||
|         RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff"); | ||||
|         // RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff"); | ||||
|         RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff"); | ||||
|  | ||||
|  | ||||
| @@ -74,6 +74,8 @@ RED.diff = (function() { | ||||
|                 var remoteDiff = object.remoteDiff; | ||||
|                 var tab = object.tab.n; | ||||
|                 var def = object.def; | ||||
|                 var conflicts = currentDiff.conflicts; | ||||
|  | ||||
|                 var tabDiv = $('<div>',{class:"node-diff-tab"}).appendTo(container); | ||||
|                 tabDiv.addClass('collapsed'); | ||||
|                 var titleRow = $('<div>',{class:"node-diff-tab-title"}).appendTo(tabDiv); | ||||
| @@ -132,6 +134,7 @@ RED.diff = (function() { | ||||
|                         var originalNodeDiv = $("<div>",{class:"node-diff-node-entry-cell"}).appendTo(row); | ||||
|                         var localNodeDiv = $("<div>",{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(row); | ||||
|                         var localChanged = false; | ||||
|                         var remoteChanged = false; | ||||
|  | ||||
|                         if (!localDiff.newConfig.all[tab.id]) { | ||||
|                             localNodeDiv.addClass("node-diff-empty"); | ||||
| @@ -153,11 +156,16 @@ RED.diff = (function() { | ||||
|                             remoteNodeDiv = $("<div>",{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(row); | ||||
|                             if (!remoteDiff.newConfig.all[tab.id]) { | ||||
|                                 remoteNodeDiv.addClass("node-diff-empty"); | ||||
|                                 if (remoteDiff.deleted[tab.id]) { | ||||
|                                     remoteChanged = true; | ||||
|                                 } | ||||
|                             } else if (remoteDiff.added[tab.id]) { | ||||
|                                 remoteNodeDiv.addClass("node-diff-node-added"); | ||||
|                                 remoteChanged = true; | ||||
|                                 $('<span class="node-diff-status"><i class="fa fa-plus-square"></i> added</span>').appendTo(remoteNodeDiv); | ||||
|                             } else if (remoteDiff.changed[tab.id]) { | ||||
|                                 remoteNodeDiv.addClass("node-diff-node-changed"); | ||||
|                                 remoteChanged = true; | ||||
|                                 $('<span class="node-diff-status"><i class="fa fa-square"></i> changed</span>').appendTo(remoteNodeDiv); | ||||
|                             } else { | ||||
|                                 remoteNodeDiv.addClass("node-diff-node-unchanged"); | ||||
| @@ -172,9 +180,9 @@ RED.diff = (function() { | ||||
|                             $(this).parent().toggleClass('collapsed'); | ||||
|                         }); | ||||
|  | ||||
|                         createNodePropertiesTable(def,tab,localTabNode,remoteTabNode,object.conflicts).appendTo(div); | ||||
|                         createNodePropertiesTable(def,tab,localTabNode,remoteTabNode,conflicts).appendTo(div); | ||||
|                         selectState = ""; | ||||
|                         if (object.conflicts[tab.id]) { | ||||
|                         if (conflicts[tab.id]) { | ||||
|                             flowStats.conflicts++; | ||||
|  | ||||
|                             if (!localNodeDiv.hasClass("node-diff-empty")) { | ||||
| @@ -185,14 +193,10 @@ RED.diff = (function() { | ||||
|                             } | ||||
|                             div.addClass("node-diff-node-entry-conflict"); | ||||
|                         } else { | ||||
|                             if (!localChanged) { | ||||
|                                 selectState = "remote"; | ||||
|                             } else { | ||||
|                                 selectState = "local"; | ||||
|                             } | ||||
|                             selectState = currentDiff.resolutions[tab.id]; | ||||
|                         } | ||||
|  | ||||
|                         createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!object.conflicts[tab.id],selectState); | ||||
|                         // Tab properties row | ||||
|                         createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState); | ||||
|                     } | ||||
|                 } | ||||
|                 // var stats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(titleRow); | ||||
| @@ -201,14 +205,14 @@ RED.diff = (function() { | ||||
|                 var seen = {}; | ||||
|                 object.tab.nodes.forEach(function(node) { | ||||
|                     seen[node.id] = true; | ||||
|                     createNodeDiffRow(node,flowStats,localDiff,remoteDiff,object.conflicts[node.id]).appendTo(nodesDiv) | ||||
|                     createNodeDiffRow(node,flowStats).appendTo(nodesDiv) | ||||
|                 }); | ||||
|                 if (object.newTab) { | ||||
|                     localNodeCount = object.newTab.nodes.length; | ||||
|                     object.newTab.nodes.forEach(function(node) { | ||||
|                         if (!seen[node.id]) { | ||||
|                             seen[node.id] = true; | ||||
|                             createNodeDiffRow(node,flowStats,localDiff,remoteDiff,object.conflicts[node.id]).appendTo(nodesDiv) | ||||
|                             createNodeDiffRow(node,flowStats).appendTo(nodesDiv) | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
| @@ -216,7 +220,7 @@ RED.diff = (function() { | ||||
|                     remoteNodeCount = object.remoteTab.nodes.length; | ||||
|                     object.remoteTab.nodes.forEach(function(node) { | ||||
|                         if (!seen[node.id]) { | ||||
|                             createNodeDiffRow(node,flowStats,localDiff,remoteDiff,object.conflicts[node.id]).appendTo(nodesDiv) | ||||
|                             createNodeDiffRow(node,flowStats).appendTo(nodesDiv) | ||||
|                         } | ||||
|                     }); | ||||
|                 } | ||||
| @@ -304,12 +308,16 @@ RED.diff = (function() { | ||||
|                     } else { | ||||
|                         remoteCell.addClass("node-diff-empty"); | ||||
|                     } | ||||
|                     selectState = ""; | ||||
|                     if (flowStats.conflicts > 0) { | ||||
|                         titleRow.addClass("node-diff-node-entry-conflict"); | ||||
|                     } else { | ||||
|                         selectState = currentDiff.resolutions[tab.id]; | ||||
|                     } | ||||
|                     if (tab.id) { | ||||
|                         selectState = ""; | ||||
|                         createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, !(flowStats.conflicts > 0 &&(localDiff.deleted[tab.id] || remoteDiff.deleted[tab.id])),selectState); | ||||
|                         var hide = !(flowStats.conflicts > 0 &&(localDiff.deleted[tab.id] || remoteDiff.deleted[tab.id])); | ||||
|                         // Tab parent row | ||||
|                         createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, hide, selectState); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
| @@ -383,7 +391,11 @@ RED.diff = (function() { | ||||
|         $('<span>',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv); | ||||
|         return nodeTitleDiv; | ||||
|     } | ||||
|     function createNodeDiffRow(node,stats,localDiff,remoteDiff,conflicted) { | ||||
|     function createNodeDiffRow(node,stats) { | ||||
|         var localDiff = currentDiff.localDiff; | ||||
|         var remoteDiff = currentDiff.remoteDiff; | ||||
|         var conflicted = currentDiff.conflicts[node.id]; | ||||
|  | ||||
|         var hasChanges = false; // exists in original and local/remote but with changes | ||||
|         var unChanged = true; // existing in original,local,remote unchanged | ||||
|         var localChanged = false; | ||||
| @@ -450,6 +462,7 @@ RED.diff = (function() { | ||||
|                 remoteNodeDiv.addClass("node-diff-node-unchanged"); | ||||
|                 $('<span class="node-diff-status"><i class="fa fa-square-o"></i> unchanged</span>').appendTo(remoteNodeDiv); | ||||
|             } | ||||
|             div.addClass("node-diff-node-unchanged"); | ||||
|         } else if (localDiff.added[node.id]) { | ||||
|             localNodeDiv.addClass("node-diff-node-added"); | ||||
|             if (remoteNodeDiv) { | ||||
| @@ -569,12 +582,9 @@ RED.diff = (function() { | ||||
|             } | ||||
|             div.addClass("node-diff-node-entry-conflict"); | ||||
|         } else { | ||||
|             if (!localChanged) { | ||||
|                 selectState = "remote"; | ||||
|             } else { | ||||
|                 selectState = "local"; | ||||
|             } | ||||
|             selectState = currentDiff.resolutions[node.id]; | ||||
|         } | ||||
|         // Node row | ||||
|         createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState); | ||||
|         row.click(function(evt) { | ||||
|             $(this).parent().toggleClass('collapsed'); | ||||
| @@ -840,17 +850,14 @@ RED.diff = (function() { | ||||
|  | ||||
|     } | ||||
|     function refreshConflictHeader() { | ||||
|         currentDiff.resolutions = {}; | ||||
|         var resolutionCount = 0; | ||||
|         $(".node-diff-selectbox>input:checked").each(function() { | ||||
|             if (currentDiff.conflicts[$(this).data('node-id')]) { | ||||
|                 resolutionCount++; | ||||
|             } | ||||
|             currentDiff.resolutions[$(this).data('node-id')] = $(this).val(); | ||||
|             // console.log($(this).data('node-id'),$(this).val()) | ||||
|         }) | ||||
|         var conflictCount = Object.keys(currentDiff.conflicts).length; | ||||
|         // console.log(resolutionCount,"of",conflictCount,"conflicts resolve"); | ||||
|         if (conflictCount - resolutionCount === 0) { | ||||
|             $("#node-diff-toolbar-resolved-conflicts").html('<span class="node-diff-node-added"><span class="node-diff-status"><i class="fa fa-check"></i></span></span> '+RED._("diff.unresolvedCount",{count:conflictCount - resolutionCount})); | ||||
|         } else { | ||||
| @@ -873,30 +880,23 @@ RED.diff = (function() { | ||||
|                 var remoteFlow = nodes.flows; | ||||
|                 var localDiff = generateDiff(originalFlow,localFlow); | ||||
|                 var remoteDiff = generateDiff(originalFlow,remoteFlow); | ||||
|                 var conflicts = identifyConflicts(localDiff,remoteDiff); | ||||
|                 console.log(localDiff.moved); | ||||
|                 console.log(remoteDiff.moved); | ||||
|  | ||||
|                 callback({ | ||||
|                     localDiff:localDiff, | ||||
|                     remoteDiff:remoteDiff, | ||||
|                     conflicts: conflicts | ||||
|                 }); | ||||
|                 remoteDiff.rev = nodes.rev; | ||||
|                 callback(resolveDiffs(localDiff,remoteDiff)) | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     } | ||||
|     function showLocalDiff() { | ||||
|         var nns = RED.nodes.createCompleteNodeSet(); | ||||
|         var originalFlow = RED.nodes.originalFlow(); | ||||
|         var diff = generateDiff(originalFlow,nns); | ||||
|         showDiff(diff); | ||||
|     } | ||||
|     // function showLocalDiff() { | ||||
|     //     var nns = RED.nodes.createCompleteNodeSet(); | ||||
|     //     var originalFlow = RED.nodes.originalFlow(); | ||||
|     //     var diff = generateDiff(originalFlow,nns); | ||||
|     //     showDiff(diff); | ||||
|     // } | ||||
|     function showRemoteDiff(diff) { | ||||
|         if (diff === undefined) { | ||||
|             getRemoteDiff(showRemoteDiff); | ||||
|         } else { | ||||
|             showDiff(diff.localDiff,diff.remoteDiff,diff.conflicts); | ||||
|             showDiff(diff); | ||||
|         } | ||||
|     } | ||||
|     function parseNodes(nodeList) { | ||||
| @@ -971,11 +971,18 @@ RED.diff = (function() { | ||||
|             moved: moved | ||||
|         } | ||||
|     } | ||||
|     function identifyConflicts(localDiff,remoteDiff) { | ||||
|         var seen = {}; | ||||
|     function resolveDiffs(localDiff,remoteDiff) { | ||||
|         var conflicted = {}; | ||||
|         var id,node; | ||||
|         var resolutions = {}; | ||||
|  | ||||
|         var diff = { | ||||
|             localDiff: localDiff, | ||||
|             remoteDiff: remoteDiff, | ||||
|             conflicts: conflicted, | ||||
|             resolutions: resolutions | ||||
|         } | ||||
|         var seen = {}; | ||||
|         var id,node; | ||||
|         for (id in localDiff.currentConfig.all) { | ||||
|             if (localDiff.currentConfig.all.hasOwnProperty(id)) { | ||||
|                 seen[id] = true; | ||||
| @@ -990,6 +997,13 @@ RED.diff = (function() { | ||||
|                         conflicted[id] = true; | ||||
|                     } | ||||
|                 } | ||||
|                 if (!conflicted[id]) { | ||||
|                     if (remoteDiff.added[id]||remoteDiff.changed[id]||remoteDiff.deleted[id]) { | ||||
|                         resolutions[id] = 'remote'; | ||||
|                     } else { | ||||
|                         resolutions[id] = 'local'; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         for (id in localDiff.added) { | ||||
| @@ -998,6 +1012,8 @@ RED.diff = (function() { | ||||
|                 if (remoteDiff.deleted[node.z]) { | ||||
|                     conflicted[id] = true; | ||||
|                     // conflicted[node.z] = true; | ||||
|                 } else { | ||||
|                     resolutions[id] = 'local'; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -1007,13 +1023,20 @@ RED.diff = (function() { | ||||
|                 if (localDiff.deleted[node.z]) { | ||||
|                     conflicted[id] = true; | ||||
|                     // conflicted[node.z] = true; | ||||
|                 } else { | ||||
|                     resolutions[id] = 'remote'; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // console.log(diff.resolutions); | ||||
|         // console.log(conflicted); | ||||
|         return conflicted; | ||||
|         return diff; | ||||
|     } | ||||
|     function showDiff(localDiff,remoteDiff,conflicts) { | ||||
|     function showDiff(diff) { | ||||
|         var localDiff = diff.localDiff; | ||||
|         var remoteDiff = diff.remoteDiff; | ||||
|         var conflicts = diff.conflicts; | ||||
|         currentDiff = diff; | ||||
|         var list = $("#node-dialog-view-diff-diff"); | ||||
|         list.editableList('empty'); | ||||
|  | ||||
| @@ -1027,12 +1050,6 @@ RED.diff = (function() { | ||||
|         } else { | ||||
|             $("#node-diff-view-diff-merge").hide(); | ||||
|         } | ||||
|         currentDiff = { | ||||
|             localDiff: localDiff, | ||||
|             remoteDiff: remoteDiff, | ||||
|             conflicts: conflicts, | ||||
|             resolutions: {} | ||||
|         } | ||||
|         refreshConflictHeader(); | ||||
|  | ||||
|         $("#node-dialog-view-diff-headers").empty(); | ||||
| @@ -1044,7 +1061,6 @@ RED.diff = (function() { | ||||
|         conflicts = conflicts || {}; | ||||
|  | ||||
|         var el = { | ||||
|             conflicts: conflicts, | ||||
|             diff: localDiff, | ||||
|             def: { | ||||
|                 category: 'config', | ||||
| @@ -1080,7 +1096,6 @@ RED.diff = (function() { | ||||
|         currentConfig.tabOrder.forEach(function(tabId) { | ||||
|             var tab = currentConfig.tabs[tabId]; | ||||
|             var el = { | ||||
|                 conflicts: conflicts, | ||||
|                 diff: localDiff, | ||||
|                 def: {}, | ||||
|                 tab:tab | ||||
| @@ -1100,7 +1115,6 @@ RED.diff = (function() { | ||||
|                 seenTabs[tabId] = true; | ||||
|                 var tab = newConfig.tabs[tabId]; | ||||
|                 var el = { | ||||
|                     conflicts: conflicts, | ||||
|                     diff: localDiff, | ||||
|                     def: {}, | ||||
|                     tab:tab, | ||||
| @@ -1118,7 +1132,6 @@ RED.diff = (function() { | ||||
|                     var tab = remoteDiff.newConfig.tabs[tabId]; | ||||
|                     // TODO how to recognise this is a remotely added flow | ||||
|                     var el = { | ||||
|                         conflicts: conflicts, | ||||
|                         diff: localDiff, | ||||
|                         remoteDiff: remoteDiff, | ||||
|                         def: {}, | ||||
| @@ -1134,7 +1147,6 @@ RED.diff = (function() { | ||||
|             if (currentConfig.subflows.hasOwnProperty(subflowId)) { | ||||
|                 seenTabs[subflowId] = true; | ||||
|                 el = { | ||||
|                     conflicts: conflicts, | ||||
|                     diff: localDiff, | ||||
|                     def: { | ||||
|                         defaults:{}, | ||||
| @@ -1158,7 +1170,6 @@ RED.diff = (function() { | ||||
|             if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) { | ||||
|                 seenTabs[subflowId] = true; | ||||
|                 el = { | ||||
|                     conflicts: conflicts, | ||||
|                     diff: localDiff, | ||||
|                     def: { | ||||
|                         defaults:{}, | ||||
| @@ -1178,9 +1189,7 @@ RED.diff = (function() { | ||||
|         if (remoteDiff !== undefined) { | ||||
|             for (subflowId in remoteDiff.newConfig.subflows) { | ||||
|                 if (remoteDiff.newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) { | ||||
|                     // TODO how to recognise this is a remotely added flow | ||||
|                     el = { | ||||
|                         conflicts: conflicts, | ||||
|                         diff: localDiff, | ||||
|                         remoteDiff: remoteDiff, | ||||
|                         def: { | ||||
| @@ -1205,109 +1214,77 @@ RED.diff = (function() { | ||||
|     } | ||||
|     function mergeDiff(diff) { | ||||
|         var currentConfig = diff.localDiff.currentConfig; | ||||
|  | ||||
|         var localDiff = diff.localDiff; | ||||
|         var remoteDiff = diff.remoteDiff; | ||||
|         var conflicts = diff.conflicts; | ||||
|         var resolutions = diff.resolutions; | ||||
|  | ||||
|         var toAdd = []; | ||||
|         var toRemove = []; | ||||
|         var toMerge = []; | ||||
|         var toMove = []; | ||||
|  | ||||
|         var id; | ||||
|         for (id in remoteDiff.added) { | ||||
|             if (remoteDiff.added.hasOwnProperty(id) && !localDiff.added.hasOwnProperty(id)) { | ||||
|                 toAdd.push(remoteDiff.newConfig.all[id]); | ||||
|  | ||||
|         for (id in conflicts) { | ||||
|             if (conflicts.hasOwnProperty(id)) { | ||||
|                 if (!resolutions.hasOwnProperty(id)) { | ||||
|                     console.log(diff); | ||||
|                     throw new Error("No resolution for conflict on node",id); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         for (id in currentConfig.all) { | ||||
|             if (currentConfig.all.hasOwnProperty(id)) { | ||||
|                 var node = currentConfig.all[id]; | ||||
|  | ||||
|         var newConfig = []; | ||||
|         var node; | ||||
|         var nodeChangedStates = {}; | ||||
|         var localChangedStates = {}; | ||||
|         for (id in localDiff.newConfig.all) { | ||||
|             if (localDiff.newConfig.all.hasOwnProperty(id)) { | ||||
|                 node = RED.nodes.node(id); | ||||
|                 if (resolutions[id] === 'local') { | ||||
|                     // use local - nothing to change then | ||||
|                 } else { | ||||
|                     if (remoteDiff.deleted[id]) { | ||||
|                         toRemove.push(id); | ||||
|                     } else if (remoteDiff.moved[id]) { | ||||
|                         toRemove.push(id); | ||||
|                         toAdd.push(remoteDiff.newConfig.all[id]); | ||||
|                     } else if (remoteDiff.changed[id]) { | ||||
|                         if (localDiff.deleted[id]) { | ||||
|                             toAdd.push(remoteDiff.newConfig.all[id]); | ||||
|                         } else { | ||||
|                             if (node.type !== 'tab' && node.type !== 'subflow') { | ||||
|                                 toRemove.push(id); | ||||
|                                 toAdd.push(remoteDiff.newConfig.all[id]); | ||||
|                             } else { | ||||
|                                 toMerge.push(remoteDiff.newConfig.all[id]); | ||||
|                             } | ||||
|                         } | ||||
|                     if (node) { | ||||
|                         nodeChangedStates[id] = node.changed; | ||||
|                     } | ||||
|                     newConfig.push(localDiff.newConfig.all[id]); | ||||
|                 } else if (resolutions[id] === 'remote') { | ||||
|                     if (!remoteDiff.deleted[id] && remoteDiff.newConfig.all.hasOwnProperty(id)) { | ||||
|                         if (node) { | ||||
|                             nodeChangedStates[id] = node.changed; | ||||
|                         } | ||||
|                         localChangedStates[id] = true; | ||||
|                         newConfig.push(remoteDiff.newConfig.all[id]); | ||||
|                     } | ||||
|                 } else { | ||||
|                     console.log("Unresolved",id) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         console.log("adding",toAdd); | ||||
|         console.log("deleting",toRemove); | ||||
|         console.log("replacing",toMerge); | ||||
|         console.log("moving",toMove); | ||||
|  | ||||
|         var removed = []; | ||||
|         toRemove.forEach(function(id) { | ||||
|             var node = currentConfig.all[id]; | ||||
|             if (node.type === 'tab') { | ||||
|                 console.log("removing tab",id); | ||||
|                 RED.workspaces.remove(node); | ||||
|                 removed.push(RED.nodes.removeWorkspace(id)); | ||||
|             } else if (node.type === 'subflow') { | ||||
|                 console.log("removing subflow",id); | ||||
|                 removed.push(RED.subflow.removeSubflow(id)); | ||||
|             } else { | ||||
|                 console.log("removing node",id); | ||||
|                 var r = RED.nodes.remove(id); | ||||
|                 if (r.links.length > 0 || r.nodes.length > 0) { | ||||
|                     removed.push(r); | ||||
|         for (id in remoteDiff.added) { | ||||
|             if (remoteDiff.added.hasOwnProperty(id)) { | ||||
|                 node = RED.nodes.node(id); | ||||
|                 if (node) { | ||||
|                     nodeChangedStates[id] = node.changed; | ||||
|                 } | ||||
|                 if (!localDiff.added.hasOwnProperty(id)) { | ||||
|                     localChangedStates[id] = true; | ||||
|                     newConfig.push(remoteDiff.newConfig.all[id]); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         // Need to refresh the view so when we add back nodes with the same id, | ||||
|         // they get properly initialised in the view. | ||||
|         RED.view.redraw(true); | ||||
|         } | ||||
|         var historyEvent = { | ||||
|             t:"replace", | ||||
|             config: RED.nodes.createCompleteNodeSet(), | ||||
|             changed: nodeChangedStates, | ||||
|             dirty: RED.nodes.dirty(), | ||||
|             rev: RED.nodes.version() | ||||
|         } | ||||
|  | ||||
|         var imported = RED.nodes.import(toAdd); | ||||
|         RED.history.push(historyEvent); | ||||
|  | ||||
|  | ||||
|         // toMove.forEach(function(newNode) { | ||||
|         //     var currentNode; | ||||
|         //     currentNode = RED.nodes.node(newNode.id); | ||||
|         //     currentNode.z = newNode.z; | ||||
|         // }); | ||||
|         toMerge.forEach(function(newNode) { | ||||
|             var currentNode; | ||||
|             console.log("merging node",newNode.id); | ||||
|             if (newNode.type !== 'tab' && newNode.type !== 'subflow') { | ||||
|                 currentNode = RED.nodes.node(newNode.id); | ||||
|                 var def = RED.nodes.getType(currentNode.type); | ||||
|                 if (currentNode.hasOwnProperty('x')) { | ||||
|                     currentNode.x = newNode.x; | ||||
|                     currentNode.y = newNode.y; | ||||
|                 } | ||||
|                 for (var d in def.defaults) { | ||||
|                     if (def.defaults.hasOwnProperty(d)) { | ||||
|                         currentNode[d] = newNode[d]; | ||||
|                     } | ||||
|                 } | ||||
|                 var removedLinks = RED.editor.updateNodeProperties(currentNode); | ||||
|                 if (removedLinks.length > 0) { | ||||
|                     removed.push({links:removedLinks}); | ||||
|                 } | ||||
|             } else if (newNode.type === 'tab') { | ||||
|                 currentNode = RED.nodes.workspace(newNode.id); | ||||
|                 currentNode.label = newNode.label; | ||||
|         RED.nodes.clear(); | ||||
|         var imported = RED.nodes.import(newConfig); | ||||
|         imported[0].forEach(function(n) { | ||||
|             if (nodeChangedStates[n.id] || localChangedStates[n.id]) { | ||||
|                 n.changed = true; | ||||
|             } | ||||
|         }); | ||||
|         }) | ||||
|  | ||||
|         RED.nodes.version(remoteDiff.rev); | ||||
|  | ||||
|         RED.view.redraw(true); | ||||
|         RED.palette.refresh(); | ||||
| @@ -1318,6 +1295,7 @@ RED.diff = (function() { | ||||
|     return { | ||||
|         init: init, | ||||
|         getRemoteDiff: getRemoteDiff, | ||||
|         showRemoteDiff: showRemoteDiff | ||||
|         showRemoteDiff: showRemoteDiff, | ||||
|         mergeDiff: mergeDiff | ||||
|     } | ||||
| })(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user