From 932ea7ba8f4b3b1fdbce575a846abb634483aeee Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 6 Dec 2016 22:37:21 +0000 Subject: [PATCH] Add flow diff view --- Gruntfile.js | 1 + editor/js/main.js | 2 +- editor/js/nodes.js | 12 ++ editor/js/ui/deploy.js | 310 +------------------------------------ editor/sass/diff.scss | 96 ++++++++++-- editor/templates/index.mst | 3 - 6 files changed, 97 insertions(+), 327 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index f9531d1c2..60b474103 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -119,6 +119,7 @@ module.exports = function(grunt) { "editor/js/ui/utils.js", "editor/js/ui/actions.js", "editor/js/ui/deploy.js", + "editor/js/ui/diff.js", "editor/js/ui/keyboard.js", "editor/js/ui/workspaces.js", "editor/js/ui/view.js", diff --git a/editor/js/main.js b/editor/js/main.js index 4f16af488..17dd1963a 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -249,10 +249,10 @@ RED.view.init(); RED.editor.init(); RED.keyboard.init(); + RED.diff.init(); RED.menu.init({id:"btn-sidemenu",options: menuOptions}); - RED.deploy.init(RED.settings.theme("deployButton",null)); RED.actions.add("core:show-about", showAbout); diff --git a/editor/js/nodes.js b/editor/js/nodes.js index 49bd29860..e471d9081 100644 --- a/editor/js/nodes.js +++ b/editor/js/nodes.js @@ -29,6 +29,8 @@ RED.nodes = (function() { added: {} }; + var initialLoad; + var dirty = false; function setDirty(d) { @@ -697,6 +699,9 @@ RED.nodes = (function() { if (!$.isArray(newNodes)) { newNodes = [newNodes]; } + if (!initialLoad) { + initialLoad = JSON.parse(JSON.stringify(newNodes)); + } var unknownTypes = []; for (i=0;i',{class:"node-diff-tab collapsed"}).appendTo(container); - // - // var titleRow = $('
',{class:"node-diff-tab-title"}).appendTo(tabDiv); - // titleRow.click(function(evt) { - // evt.preventDefault(); - // titleRow.parent().toggleClass('collapsed'); - // }) - // var chevron = $('').appendTo(titleRow); - // var title = $('').html(tab.label||tab.id).appendTo(titleRow); - // - // var stats = $('',{class:"node-diff-tab-stats"}).appendTo(titleRow); - // - // var addedCount = 0; - // var deletedCount = 0; - // var changedCount = 0; - // var conflictedCount = 0; - // - // object.tab.nodes.forEach(function(node) { - // var realNode = RED.nodes.node(node.id); - // var hasChanges = false; - // if (currentDiff.added[node.id]) { - // addedCount++; - // hasChanges = true; - // } - // if (currentDiff.deleted[node.id]) { - // deletedCount++; - // hasChanges = true; - // } - // if (currentDiff.changed[node.id]) { - // changedCount++; - // hasChanges = true; - // } - // if (currentDiff.conflicted[node.id]) { - // conflictedCount++; - // hasChanges = true; - // } - // - // if (hasChanges) { - // var def = RED.nodes.getType(node.type)||{}; - // var div = $("
",{class:"node-diff-node-entry collapsed"}).appendTo(tabDiv); - // var nodeTitleDiv = $("
",{class:"node-diff-node-entry-title"}).appendTo(div); - // nodeTitleDiv.click(function(evt) { - // evt.preventDefault(); - // $(this).parent().toggleClass('collapsed'); - // }) - // var newNode = currentDiff.newConfig.all[node.id]; - // var nodePropertiesDiv = $("
",{class:"node-diff-node-entry-properties"}).appendTo(div); - // - // var nodePropertiesTable = $("").appendTo(nodePropertiesDiv); - // - // if (node.hasOwnProperty('x')) { - // if (newNode.x !== node.x || newNode.y !== node.y) { - // var currentPosition = node.x+", "+node.y - // var newPosition = newNode.x+", "+newNode.y; - // $("").appendTo(nodePropertiesTable); - // } - // } - // var properties = Object.keys(node).filter(function(p) { return p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))}); - // if (def.defaults) { - // properties = properties.concat(Object.keys(def.defaults)); - // } - // properties.forEach(function(d) { - // var localValue = JSON.stringify(node[d]); - // var remoteValue = JSON.stringify(newNode[d]); - // var originalValue = realNode._config[d]; - // - // if (remoteValue !== originalValue) { - // var formattedProperty = formatNodeProperty(node[d]); - // var newFormattedProperty = formatNodeProperty(newNode[d]); - // if (localValue === originalValue) { - // // no conflict change - // } else { - // // conflicting change - // } - // $("").appendTo(nodePropertiesTable); - // } - // - // }) - // var nodeChevron = $('').appendTo(nodeTitleDiv); - // - // - // // var leftColumn = $('
',{class:"node-diff-column"}).appendTo(div); - // // var rightColumn = $('
',{class:"node-diff-column"}).appendTo(div); - // // rightColumn.html(" "); - // - // - // - // var nodeDiv = $("
",{class:"node-diff-node-entry-node"}).appendTo(nodeTitleDiv); - // var colour = def.color; - // var icon_url = "arrow-in.png"; - // if (node.type === 'tab') { - // colour = "#C0DEED"; - // icon_url = "subflow.png"; - // } else if (def.category === 'config') { - // icon_url = "cog.png"; - // } else if (node.type === 'unknown') { - // icon_url = "alert.png"; - // } else { - // icon_url = def.icon; - // } - // nodeDiv.css('backgroundColor',colour); - // - // var iconContainer = $('
',{class:"palette_icon_container"}).appendTo(nodeDiv); - // $('
',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer); - // - // - // - // var contentDiv = $('
',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv); - // - // $('',{class:"node-diff-node-label"}).html(node.label || node.name || node.id).appendTo(contentDiv); - // //$('
',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv); - // //$('
',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv); - // } - // - // }); - // - // var statsInfo = ''+object.tab.nodes.length+" nodes"+ - // (addedCount+deletedCount+changedCount+conflictedCount > 0 ? " : ":"")+ - // " "+ - // ((addedCount > 0)?''+addedCount+' added ':'')+ - // ((deletedCount > 0)?''+deletedCount+' deleted ':'')+ - // ((changedCount > 0)?''+changedCount+' changed ':'')+ - // ((conflictedCount > 0)?''+conflictedCount+' conflicts':''); - // stats.html(statsInfo); - // - // - // - // // - // // - // // - // // var node = object.node; - // // var realNode = RED.nodes.node(node.id); - // // var def = RED.nodes.getType(object.node.type)||{}; - // // var l = ""; - // // if (def && def.label && realNode) { - // // l = def.label; - // // try { - // // l = (typeof l === "function" ? l.call(realNode) : l); - // // } catch(err) { - // // console.log("Definition error: "+node.type+".label",err); - // // } - // // } - // // l = l||node.label||node.name||node.id||""; - // // console.log(node); - // // var div = $('
').appendTo(container); - // // div.html(l); - // } - // }); - } - - function formatNodeProperty(prop) { - var formattedProperty = prop; - if (formattedProperty === null) { - formattedProperty = 'null'; - } else if (formattedProperty === undefined) { - formattedProperty = 'undefined'; - } else if (typeof formattedProperty === 'object') { - formattedProperty = JSON.stringify(formattedProperty); - } - if (/\n/.test(formattedProperty)) { - formattedProperty = "
"+formattedProperty+"
" - } - return formattedProperty; } function getNodeInfo(node) { @@ -414,124 +223,6 @@ RED.deploy = (function() { // }); } - // function parseNodes(nodeList) { - // var tabOrder = []; - // var tabs = {}; - // var subflows = {}; - // var globals = []; - // var all = {}; - // - // nodeList.forEach(function(node) { - // all[node.id] = node; - // if (node.type === 'tab') { - // tabOrder.push(node.id); - // tabs[node.id] = {n:node,nodes:[]}; - // } else if (node.type === 'subflow') { - // subflows[node.id] = {n:node,nodes:[]}; - // } - // }); - // - // nodeList.forEach(function(node) { - // if (node.type !== 'tab' && node.type !== 'subflow') { - // if (tabs[node.z]) { - // tabs[node.z].nodes.push(node); - // } else if (subflows[node.z]) { - // subflows[node.z].nodes.push(node); - // } else { - // globals.push(node); - // } - // } - // }); - // - // return { - // all: all, - // tabOrder: tabOrder, - // tabs: tabs, - // subflows: subflows, - // globals: globals - // } - // } - - // function generateDiff(currentNodes,newNodes) { - // var currentConfig = parseNodes(currentNodes); - // var newConfig = parseNodes(newNodes); - // var pending = RED.nodes.pending(); - // var added = {}; - // var deleted = {}; - // var changed = {}; - // var conflicted = {}; - // - // - // Object.keys(currentConfig.all).forEach(function(id) { - // var node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id); - // if (!newConfig.all.hasOwnProperty(id)) { - // if (!pending.added.hasOwnProperty(id)) { - // deleted[id] = true; - // conflicted[id] = node.changed; - // } - // } else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) { - // changed[id] = true; - // conflicted[id] = node.changed; - // } - // }); - // Object.keys(newConfig.all).forEach(function(id) { - // if (!currentConfig.all.hasOwnProperty(id) && !pending.deleted.hasOwnProperty(id)) { - // added[id] = true; - // } - // }); - // - // // console.log("Added",added); - // // console.log("Deleted",deleted); - // // console.log("Changed",changed); - // // console.log("Conflicted",conflicted); - // - // var formatString = function(id) { - // return conflicted[id]?"!":(added[id]?"+":(deleted[id]?"-":(changed[id]?"~":" "))); - // } - // newConfig.tabOrder.forEach(function(tabId) { - // var tab = newConfig.tabs[tabId]; - // console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")"); - // tab.nodes.forEach(function(node) { - // console.log(" ",formatString(node.id),node.type,node.name || node.id); - // }) - // if (currentConfig.tabs[tabId]) { - // currentConfig.tabs[tabId].nodes.forEach(function(node) { - // if (deleted[node.id]) { - // console.log(" ",formatString(node.id),node.type,node.name || node.id); - // } - // }) - // } - // }); - // currentConfig.tabOrder.forEach(function(tabId) { - // if (deleted[tabId]) { - // console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")"); - // } - // }); - // - // currentDiff = { - // currentConfig: currentConfig, - // newConfig: newConfig, - // added: added, - // deleted: deleted, - // changed: changed, - // conflicted: conflicted - // } - // } - - // function showDiff() { - // if (currentDiff) { - // var list = $("#node-dialog-view-diff-diff"); - // list.editableList('empty'); - // var currentConfig = currentDiff.currentConfig; - // currentConfig.tabOrder.forEach(function(tabId) { - // var tab = currentConfig.tabs[tabId]; - // list.editableList('addItem',{tab:tab}) - // }); - // } - // $("#node-dialog-view-diff").dialog("open"); - // } - - function save(skipValidation,force) { if (!$("#btn-deploy").hasClass("disabled")) { if (!skipValidation) { @@ -624,6 +315,7 @@ RED.deploy = (function() { }).done(function(data,textStatus,xhr) { RED.nodes.dirty(false); RED.nodes.version(data.rev); + RED.nodes.originalFlow(nns); if (hasUnusedConfig) { RED.notify( '

'+RED._("deploy.successfulDeploy")+'

'+ diff --git a/editor/sass/diff.scss b/editor/sass/diff.scss index 8c27f4ad4..8f6febf00 100644 --- a/editor/sass/diff.scss +++ b/editor/sass/diff.scss @@ -22,26 +22,40 @@ border-radius:1px; padding:0; } - ol { + #node-dialog-view-diff-diff { position: absolute; - top:10px; + top:50px; bottom:10px; left:10px; right:10px; li { padding: 0px; border: none; + min-height: 0; } } .red-ui-editableList-item-content { padding: 5px; + padding-bottom: 0; } - +} +.node-diff-toolbar { + position:absolute; + top:0; + left:0; + right:0; + color: #666; + text-align: right; + padding: 8px 10px; + background: #f3f3f3; + border-bottom: 1px solid $secondary-border-color; + white-space: nowrap; } .node-diff-tab { border: 1px solid $secondary-border-color; border-radius: 3px; + overflow: hidden; &.collapsed { .node-diff-tab-title > .node-diff-chevron { @@ -55,9 +69,11 @@ .node-diff-tab-stats { position: absolute; left: 50%; + top: 13px; } .node-diff-chevron { + display: inline-block; width: 15px; text-align: center; margin: 3px 5px 3px 5px; @@ -65,10 +81,7 @@ } .node-diff-node-entry { - padding: 0 0 0 5px; - &:not(:last-child) { - border-bottom: 1px solid $secondary-border-color; - } + border-top: 1px solid $secondary-border-color; &.collapsed { .node-diff-chevron { @@ -88,13 +101,16 @@ border: 1px solid $secondary-border-color; padding: 3px 5px; text-align: left; + overflow-x: auto; + } + tr { + vertical-align: top; } - td:nth-child(1) { - width: 150px; + width: 100px; } td:not(:first-child) { - width: calc(50% - 150px); + width: calc(50% - 100px); } } .node-diff-column { @@ -108,6 +124,7 @@ border-right: 1px solid $secondary-border-color } } + .node-diff-tab-title { padding: 3px 3px 3px 0; background: #f6f6f6; @@ -135,15 +152,60 @@ width: 24px; } } +.node-diff-tab-empty { + .node-diff-chevron i { + display: none; + } + .node-diff-tab-title { + cursor: default; + } +} +.node-diff-node-deleted { + //background: #fadddd; + cursor: default !important; + .node-diff-status { + color: #f80000; + } + .node-diff-node-entry-node { + opacity: 0.5; + } + .node-diff-node-description { + opacity: 0.5; + text-decoration: line-through; + } +} +.node-diff-node-added { + //background: #eefaee; + cursor: default !important; + .node-diff-status { + color: #009900; + } +} +.node-diff-node-changed { + //background: #fff2ca; + .node-diff-status { + color: #f89406; + } +} .node-diff-node-entry-title { cursor: pointer; + .node-diff-status { + margin-left: 15px; + } } .node-diff-node-entry-properties { - margin-left: 30px; - margin-right: 8px; - margin-bottom:8px; + margin: 6px 8px 6px 30px; color: #666; } +.node-diff-status { + display: inline-block; + width: 15px; + height: 20px; + margin-left: 5px; + vertical-align: middle; + text-align: center; +} + .node-diff-node-description { color: $form-text-color; margin-left: 5px; @@ -156,7 +218,13 @@ clear: both; } } - +.node-diff-node-meta { + float: right; + font-size: 0.9em; + color: #999; + margin-top: 7px; + margin-right: 10px; +} .node-diff-count { color: #999} .node-diff-added { color: #009900} diff --git a/editor/templates/index.mst b/editor/templates/index.mst index d8cbb2537..0847b1a84 100644 --- a/editor/templates/index.mst +++ b/editor/templates/index.mst @@ -97,9 +97,6 @@
-
-
    -
    position"+currentPosition+""+newPosition+"
    "+d+''+formattedProperty+''+newFormattedProperty+"