ONOS-6327: Implement details panel for host view.
ONOS-6326: Add friendly names to hosts.
- PLENTY more YakShaving:
* some cleanup of the device view handler
* introduce navPath field to PropertyPanel
* introduce "-" name annotation to represent "use default"
* (and more...)
Change-Id: I2afc0f1f29c726b90e97e492527edde2d1345ece
diff --git a/web/gui/src/main/webapp/app/common.css b/web/gui/src/main/webapp/app/common.css
index b8952c3..7aed6ef 100644
--- a/web/gui/src/main/webapp/app/common.css
+++ b/web/gui/src/main/webapp/app/common.css
@@ -22,3 +22,18 @@
cursor: pointer;
}
+.light .editable {
+ border-bottom: 1px dashed #ca504b;
+}
+
+.dark .editable {
+ border-bottom: 1px dashed #df4f4a;
+}
+
+.light svg.embeddedIcon .icon .glyph {
+ fill: #0071bd;
+}
+
+.dark svg.embeddedIcon .icon .glyph {
+ fill: #375b7f;
+}
diff --git a/web/gui/src/main/webapp/app/view/device/device-theme.css b/web/gui/src/main/webapp/app/view/device/device-theme.css
index 3aa67d2..f7e2873 100644
--- a/web/gui/src/main/webapp/app/view/device/device-theme.css
+++ b/web/gui/src/main/webapp/app/view/device/device-theme.css
@@ -18,15 +18,6 @@
ONOS GUI -- Device View (theme) -- CSS file
*/
-
-.light .dev-icon svg.embeddedIcon .icon .glyph {
- fill: #0071bd;
-}
-
-.light #device-details-panel .editable {
- border-bottom: 1px dashed #ca504b;
-}
-
.light #device-details-panel .bottom th {
background-color: #e5e5e6;
}
@@ -38,12 +29,3 @@
background-color: #f4f4f4;
}
-/* ========== DARK Theme ========== */
-
-.dark .dev-icon svg.embeddedIcon .icon .glyph {
- fill: #375b7f;
-}
-
-.dark #device-details-panel .editable {
- border-bottom: 1px dashed #df4f4a;
-}
diff --git a/web/gui/src/main/webapp/app/view/host/host.css b/web/gui/src/main/webapp/app/view/host/host.css
index 377918a..1aa6f86 100644
--- a/web/gui/src/main/webapp/app/view/host/host.css
+++ b/web/gui/src/main/webapp/app/view/host/host.css
@@ -58,7 +58,7 @@
#host-details-panel h2 input {
font-size: 0.90em;
- width: 106%;
+ width: 112%;
}
#host-details-panel .top-tables {
diff --git a/web/gui/src/main/webapp/app/view/host/host.js b/web/gui/src/main/webapp/app/view/host/host.js
index ee23f00..4e8153c 100644
--- a/web/gui/src/main/webapp/app/view/host/host.js
+++ b/web/gui/src/main/webapp/app/view/host/host.js
@@ -29,7 +29,6 @@
pStartY,
pHeight,
top,
- bottom,
iconDiv,
wSize,
editingName = false,
@@ -37,15 +36,19 @@
// constants
var topPdg = 28,
- ctnrPdg = 24,
- scrollSize = 17,
-
pName = 'host-details-panel',
detailsReq = 'hostDetailsRequest',
detailsResp = 'hostDetailsResponse',
nameChangeReq = 'hostNameChangeRequest',
nameChangeResp = 'hostNameChangeResponse';
+ var propOrder = [
+ 'id', 'ip', 'mac', 'vlan', 'configured', 'location'
+ ],
+ friendlyProps = [
+ 'Host ID', 'IP Address', 'MAC Address', 'VLAN',
+ 'Configured', 'Location'
+ ];
function closePanel() {
if (detailsPanel.isVisible()) {
@@ -71,12 +74,13 @@
function editNameSave() {
var nameH2 = top.select('h2'),
id = $scope.panelData.id,
+ ip = $scope.panelData.ip,
val,
newVal;
if (editingName) {
val = nameH2.select('input').property('value').trim();
- newVal = val || id;
+ newVal = val || ip;
exitEditMode(nameH2, newVal);
$scope.panelData.name = newVal;
@@ -115,7 +119,7 @@
}
function setUpPanel() {
- var container, closeBtn, tblDiv;
+ var container, closeBtn;
detailsPanel.empty();
container = detailsPanel.append('div').classed('container', true);
@@ -126,22 +130,29 @@
iconDiv = top.append('div').classed('host-icon', true);
top.append('h2').classed('editable clickable', true).on('click', editName);
- // tblDiv = top.append('div').classed('top-tables', true);
- // tblDiv.append('div').classed('left', true).append('table');
- // tblDiv.append('div').classed('right', true).append('table');
-
+ top.append('div').classed('top-tables', true);
top.append('hr');
+ }
- // bottom = container.append('div').classed('bottom', true);
- // bottom.append('h2').classed('ports-title', true).text('Ports');
- // bottom.append('table');
+ function addProp(tbody, index, value) {
+ var tr = tbody.append('tr');
+
+ function addCell(cls, txt) {
+ tr.append('td').attr('class', cls).text(txt);
+ }
+ addCell('label', friendlyProps[index] + ' :');
+ addCell('value', value);
}
function populateTop(details) {
+ var tab = top.select('.top-tables').append('tbody');
+
is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
top.select('h2').text(details.name);
- // TODO: still need to add host properties (one per line)
+ propOrder.forEach(function (prop, i) {
+ addProp(tab, i, details[prop]);
+ });
}
function populateDetails(details) {
@@ -149,7 +160,7 @@
populateTop(details);
detailsPanel.height(pHeight);
// configure width based on content.. for now hardcoded
- detailsPanel.width(600);
+ detailsPanel.width(400);
}
function respDetailsCb(data) {
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js
index 8acebcc..29f149f 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -61,6 +61,7 @@
Z: [tos.toggleOblique, 'Toggle oblique view (Experimental)'],
N: [fltr.clickAction, 'Cycle node layers'],
L: [tfs.cycleDeviceLabels, 'Cycle device labels'],
+ 'shift-L': [tfs.cycleHostLabels, 'Cycle host labels'],
U: [tfs.unpin, 'Unpin node (hover mouse over)'],
R: [resetZoom, 'Reset pan / zoom'],
dot: [ttbs.toggleToolbar, 'Toggle Toolbar'],
@@ -83,7 +84,7 @@
_helpFormat: [
['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B', 'G', 'S' ],
- ['X', 'Z', 'N', 'L', 'U', 'R', '-', 'E', '-', 'dot'],
+ ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', '-', 'E', '-', 'dot'],
[] // this column reserved for overlay actions
]
};
@@ -494,6 +495,7 @@
toggleMap(prefsState.bg);
toggleSprites(prefsState.spr);
t3s.setDevLabIndex(prefsState.dlbls);
+ t3s.setHostLabIndex(prefsState.hlbls);
flash.enable(true);
}
diff --git a/web/gui/src/main/webapp/app/view/topo/topoD3.js b/web/gui/src/main/webapp/app/view/topo/topoD3.js
index e45f491..3d232ee 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoD3.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoD3.js
@@ -139,6 +139,22 @@
ps.setPrefs('topo_prefs', p);
}
+ function incHostLabIndex() {
+ setHostLabIndex(hostLabelIndex+1);
+ switch(hostLabelIndex) {
+ case 0: return 'Show friendly host labels';
+ case 1: return 'Show host IP Addresses';
+ case 2: return 'Show host MAC Addresses';
+ }
+ }
+
+ function setHostLabIndex(mode) {
+ hostLabelIndex = mode % 3;
+ var p = ps.getPrefs('topo_prefs', ttbs.defaultPrefs);
+ p.hlbls = hostLabelIndex;
+ ps.setPrefs('topo_prefs', p);
+ }
+
function hostLabel(d) {
var idx = (hostLabelIndex < d.labels.length) ? hostLabelIndex : 0;
return d.labels[idx];
@@ -617,6 +633,8 @@
incDevLabIndex: incDevLabIndex,
setDevLabIndex: setDevLabIndex,
+ incHostLabIndex: incHostLabIndex,
+ setHostLabIndex: setHostLabIndex,
hostLabel: hostLabel,
deviceLabel: deviceLabel,
trimLabel: trimLabel,
diff --git a/web/gui/src/main/webapp/app/view/topo/topoForce.js b/web/gui/src/main/webapp/app/view/topo/topoForce.js
index 9b9a29c..f38fa56 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoForce.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js
@@ -516,6 +516,13 @@
});
}
+ function cycleHostLabels() {
+ flash.flash(td3.incHostLabIndex());
+ tms.findHosts().forEach(function (d) {
+ td3.updateHostLabel(d);
+ });
+ }
+
function unpin() {
var hov = tss.hovered();
if (hov) {
@@ -1240,6 +1247,7 @@
togglePorts: tls.togglePorts,
toggleOffline: toggleOffline,
cycleDeviceLabels: cycleDeviceLabels,
+ cycleHostLabels: cycleHostLabels,
unpin: unpin,
showMastership: showMastership,
showBadLinks: showBadLinks,
diff --git a/web/gui/src/main/webapp/app/view/topo/topoModel.js b/web/gui/src/main/webapp/app/view/topo/topoModel.js
index 3236ae5..e841907 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoModel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoModel.js
@@ -366,6 +366,16 @@
return a;
}
+ function findHosts() {
+ var hosts = [];
+ nodes.forEach(function (d) {
+ if (d.class === 'host') {
+ hosts.push(d);
+ }
+ });
+ return hosts;
+ }
+
function findAttachedHosts(devId) {
var hosts = [];
nodes.forEach(function (d) {
@@ -453,6 +463,7 @@
findLink: findLink,
findLinkById: findLinkById,
findDevices: findDevices,
+ findHosts: findHosts,
findAttachedHosts: findAttachedHosts,
findAttachedLinks: findAttachedLinks,
findBadLinks: findBadLinks
diff --git a/web/gui/src/main/webapp/app/view/topo/topoPanel.js b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
index 100cd96..8f8eef5 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoPanel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
@@ -35,8 +35,7 @@
sumMax = 226, // summary panel max height
padTop = 16, // summary panel padding below masthead
padding = 16, // panel internal padding
- padFudge = padTop + 2 * padding,
- devPath = 'device';
+ padFudge = padTop + 2 * padding;
// internal state
var useDetails = true, // should we show details if we have 'em?
@@ -230,10 +229,9 @@
// === -----------------------------------------------------
// Functions for populating the detail panel
- var isDevice = {
- switch: 1,
- roadm: 1,
- otn:1
+ var navPathIdKey = {
+ device: 'devId',
+ host: 'hostId'
};
function displaySingle(data) {
@@ -246,15 +244,19 @@
.classed('clickable', true),
table = detail.appendBody('table'),
tbody = table.append('tbody'),
- navFn;
+ navFn,
+ navPath;
gs.addGlyph(svg, (data.type || 'unknown'), 26);
title.text(data.title);
- // only add navigation when displaying a device
- if (isDevice[data.type]) {
+ // add navigation hot-link if defined
+ navPath = data.navPath;
+ if (navPath) {
navFn = function () {
- ns.navTo(devPath, { devId: data.id });
+ var arg = {};
+ arg[navPathIdKey[navPath]] = data.id;
+ ns.navTo(navPath, arg);
};
svg.on('click', navFn);
diff --git a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
index 351154c..82d14ac 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
@@ -75,6 +75,7 @@
hosts: 0,
offdev: 1,
dlbls: 0,
+ hlbls: 0,
porthl: 1,
bg: 0,
spr: 0,
@@ -278,7 +279,7 @@
toolbar.toggle();
persistTopoPrefs('toolbar');
}
-
+
function selectOverlay(ovid) {
var idx = ovIndex[defaultOverlay] || 0,
pidx = (ovid === null) ? 0 : ovIndex[ovid] || -1;
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Prefs.js b/web/gui/src/main/webapp/app/view/topo2/topo2Prefs.js
index ef3698e..9d822c8 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Prefs.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Prefs.js
@@ -26,6 +26,7 @@
hosts: 0,
offdev: 1,
dlbls: 0,
+ hlbls: 0,
porthl: 1,
bg: 0,
spr: 0,
diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js
index f0a2914..d14e9ab 100644
--- a/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js
+++ b/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js
@@ -41,8 +41,8 @@
'updateDeviceColors', 'toggleHosts',
'togglePorts', 'toggleOffline',
- 'cycleDeviceLabels', 'unpin', 'showMastership', 'showBadLinks',
- 'setNodeScale',
+ 'cycleDeviceLabels', 'cycleHostLabels', 'unpin',
+ 'showMastership', 'showBadLinks', 'setNodeScale',
'resetAllLocations', 'addDevice', 'updateDevice', 'removeDevice',
'addHost', 'updateHost', 'moveHost', 'removeHost',
diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topoModel-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topoModel-spec.js
index d1db42a..dd32491 100644
--- a/web/gui/src/main/webapp/tests/app/view/topo/topoModel-spec.js
+++ b/web/gui/src/main/webapp/tests/app/view/topo/topoModel-spec.js
@@ -210,10 +210,11 @@
it('should define api functions', function () {
expect(fs.areFunctions(tms, [
'initModel', 'newDim', 'destroyModel',
- 'positionNode', 'resetAllLocations', 'createDeviceNode', 'createHostNode',
+ 'positionNode', 'resetAllLocations',
+ 'createDeviceNode', 'createHostNode',
'createHostLink', 'createLink',
'coordFromLngLat', 'lngLatFromCoord',
- 'findLink', 'findLinkById', 'findDevices',
+ 'findLink', 'findLinkById', 'findDevices', 'findHosts',
'findAttachedHosts', 'findAttachedLinks', 'findBadLinks'
])).toBeTruthy();
});