GUI -- Reworked selection logic to populate fly-in detail pane with action items.
Change-Id: I1a7ba3e04d608b7ec7bc635c21658d2d55b2d5c9
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index c09dcb6..0d76c3b 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -146,6 +146,26 @@
}
+#topo-detail .actionBtn {
+ margin: 6px 12px;
+ padding: 2px 6px;
+ font-size: 9pt;
+ cursor: pointer;
+ width: 50%;
+ text-align: center;
+
+ /* theme specific... */
+ border: 1px solid #ddf;
+ color: #99f;
+}
+
+#topo-detail .actionBtn:hover {
+ /* theme specific... */
+ border: 1px solid #ddf;
+ background: #eef;
+ color: #77d;
+}
+
#topo-detail hr {
height: 1px;
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 9fd92d7..9c3edf0 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -129,11 +129,7 @@
P: togglePorts,
U: unpin,
R: resetZoomPan,
- esc: deselectAll,
-
- W: requestTraffic, // bag of selections
- X: cancelTraffic,
- Z: requestPath // host-to-host intent (and monitor)
+ esc: deselectAll
};
// state variables
@@ -355,14 +351,17 @@
}
var eventDispatch = {
+ addInstance: stillToImplement,
addDevice: addDevice,
addLink: addLink,
addHost: addHost,
+ updateInstance: stillToImplement,
updateDevice: updateDevice,
updateLink: updateLink,
updateHost: updateHost,
+ removeInstance: stillToImplement,
removeDevice: stillToImplement,
removeLink: removeLink,
removeHost: removeHost,
@@ -482,11 +481,11 @@
function showDetails(data) {
fnTrace('showDetails', data.payload.id);
populateDetails(data.payload);
- // TODO: Add single-select actions ...
detailPane.show();
}
function showPath(data) {
+ // TODO: review - making sure we are handling the payload correctly.
fnTrace('showPath', data.payload.id);
var links = data.payload.links,
s = [ data.event + "\n" + links.length ];
@@ -501,11 +500,11 @@
link.el.classed('showPath', true);
}
});
-
- // TODO: add selection-highlite lines to links
}
function showTraffic(data) {
+ // TODO: review - making sure we are handling the payload correctly.
+ // TODO: handle 'class' of link: primary, secondary, animated...
fnTrace('showTraffic', data.payload.id);
var paths = data.payload.paths;
@@ -524,7 +523,6 @@
}
});
});
- //network.view.alert("showTraffic() -- TODO")
}
// ...............................
@@ -571,42 +569,8 @@
return true;
}
- function requestTraffic(hoverNode) {
- if (nSel() > 0 || hoverNode) {
- var nodes = hoverNode ? selectOrder.concat(hoverNode.id) : selectOrder;
- sendMessage('requestTraffic', {
- ids: nodes
- });
- } else {
- userFeedback('Request-Traffic requires one or\n' +
- 'more items to be selected.');
- }
- }
-
- function requestPath() {
- if (nSel() === 2 && allSelectionsClass('host')) {
- sendMessage('requestPath', {
- one: getSelId(0),
- two: getSelId(1)
- });
- } else {
- userFeedback('Request-Path requires two\n' +
- 'hosts to be selected.');
- }
- }
-
- function cancelTraffic(hoverNode) {
- if (hoverNode && selectOrder.length) {
- requestTraffic();
- } else {
- // FIXME: from where do we get the intent id(s) to send to the server?
- sendMessage('cancelTraffic', {
- ids: ["need_the_intent_id"]
- });
- }
- }
-
// request details for the selected element
+ // invoked from selection of a single node.
function requestDetails() {
var data = getSel(0).obj,
payload = {
@@ -616,6 +580,31 @@
sendMessage('requestDetails', payload);
}
+ function addIntentAction() {
+ sendMessage('addHostIntent', {
+ one: getSelId(0),
+ two: getSelId(1)
+ });
+ }
+
+ function showTrafficAction() {
+ // if nothing is hovered over, and nothing selected, send cancel request
+ if (!hovered && nSel() === 0) {
+ sendMessage('cancelTraffic', {});
+ return;
+ }
+
+ // NOTE: hover is only populated if "show traffic on hover" is
+ // toggled on, and the item hovered is a host...
+ var hoverId = (trafficHover() && hovered && hovered.class === 'host')
+ ? hovered.id : '';
+ sendMessage('requestTraffic', {
+ ids: selectOrder,
+ hover: hoverId
+ });
+ }
+
+
// ==============================
// force layout modification functions
@@ -942,18 +931,16 @@
}
function nodeMouseOver(d) {
- console.log("Hover:", d);
hovered = d;
- if (d.class === 'host') {
- //requestTraffic(d);
+ if (trafficHover() && d.class === 'host') {
+ showTrafficAction();
}
}
function nodeMouseOut(d) {
- console.log("Unhover:", d);
hovered = null;
- if (d.class === 'host') {
- //cancelTraffic(d);
+ if (trafficHover() && d.class === 'host') {
+ showTrafficAction();
}
}
@@ -1293,6 +1280,7 @@
var nSel = selectOrder.length;
if (!nSel) {
detailPane.hide();
+ showTrafficAction(); // sends cancelTraffic event
} else if (nSel === 1) {
singleSelect();
} else {
@@ -1307,7 +1295,6 @@
function multiSelect() {
populateMultiSelect();
- // TODO: Add multi-select actions ...
}
function addSep(tbody) {
@@ -1339,6 +1326,8 @@
selectOrder.forEach(function (d, i) {
addProp(tbody, i+1, d);
});
+
+ addMultiSelectActions();
}
function populateDetails(data) {
@@ -1358,8 +1347,34 @@
addProp(tbody, p, data.props[p]);
}
});
+
+ addSingleSelectActions();
}
+ function addSingleSelectActions() {
+ detailPane.append('hr');
+ // always want to allow 'show traffic'
+ addAction('Show Traffic', showTrafficAction);
+ }
+
+ function addMultiSelectActions() {
+ detailPane.append('hr');
+ // always want to allow 'show traffic'
+ addAction('Show Traffic', showTrafficAction);
+ // if exactly two hosts are selected, also want 'add host intent'
+ if (nSel() === 2 && allSelectionsClass('host')) {
+ addAction('Add Host Intent', addIntentAction);
+ }
+ }
+
+ function addAction(text, cb) {
+ detailPane.append('div')
+ .classed('actionBtn', true)
+ .text(text)
+ .on('click', cb);
+ }
+
+
function zoomPan(scale, translate) {
zoomPanContainer.attr("transform", "translate(" + translate + ")scale(" + scale + ")");
// keep the map lines constant width while zooming