GUI -- Completed ONOS Instance panel, and handling of updateInstance and removeInstance.
- minor refactorings and other cleanup.
Change-Id: I4d0e467f71269f7fb91175e78d2c6af750bf9aad
diff --git a/web/gui/src/main/webapp/feedback.css b/web/gui/src/main/webapp/feedback.css
index 06716bb..a912b41 100644
--- a/web/gui/src/main/webapp/feedback.css
+++ b/web/gui/src/main/webapp/feedback.css
@@ -20,6 +20,10 @@
@author Simon Hunt
*/
+#feedback {
+ z-index: 1400;
+}
+
#feedback svg {
position: absolute;
bottom: 0;
diff --git a/web/gui/src/main/webapp/json/ev/colors/ev_13_onos.json b/web/gui/src/main/webapp/json/ev/colors/ev_13_onos.json
new file mode 100644
index 0000000..5633802
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/colors/ev_13_onos.json
@@ -0,0 +1,14 @@
+{
+ "event": "updateInstance",
+ "payload": {
+ "id": "onos-slave",
+ "ip": "192.168.24.11",
+ "online": true,
+ "uiAttached": false,
+ "switches": 103,
+ "labels": [
+ "onos-slave",
+ "192.168.24.11"
+ ]
+ }
+}
diff --git a/web/gui/src/main/webapp/json/ev/colors/ev_14_onos.json b/web/gui/src/main/webapp/json/ev/colors/ev_14_onos.json
new file mode 100644
index 0000000..f8a9186
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/colors/ev_14_onos.json
@@ -0,0 +1,14 @@
+{
+ "event": "removeInstance",
+ "payload": {
+ "id": "onos-leader",
+ "ip": "192.168.0.5",
+ "online": false,
+ "uiAttached": false,
+ "switches": 0,
+ "labels": [
+ "onos-leader",
+ "192.168.0.5"
+ ]
+ }
+}
diff --git a/web/gui/src/main/webapp/keymap.css b/web/gui/src/main/webapp/keymap.css
index e6b9715..4f465e1 100644
--- a/web/gui/src/main/webapp/keymap.css
+++ b/web/gui/src/main/webapp/keymap.css
@@ -20,6 +20,10 @@
@author Simon Hunt
*/
+#keymap {
+ z-index: 1300;
+}
+
#keymap svg {
position: absolute;
bottom: 40px;
diff --git a/web/gui/src/main/webapp/onos2.css b/web/gui/src/main/webapp/onos2.css
index 0920bac..32cdbe8 100644
--- a/web/gui/src/main/webapp/onos2.css
+++ b/web/gui/src/main/webapp/onos2.css
@@ -49,7 +49,7 @@
#alerts {
display: none;
position: absolute;
- z-index: 2000;
+ z-index: 1200;
opacity: 0.65;
background-color: #006;
color: white;
@@ -83,10 +83,12 @@
color: #66d;
}
+#floatPanels {
+ z-index: 1100;
+}
#flyout {
position: absolute;
- z-index: 100;
display: block;
top: 10%;
width: 280px;
diff --git a/web/gui/src/main/webapp/onos2.js b/web/gui/src/main/webapp/onos2.js
index 2405988..6db968b 100644
--- a/web/gui/src/main/webapp/onos2.js
+++ b/web/gui/src/main/webapp/onos2.js
@@ -785,8 +785,14 @@
function pxHide() {
return (-20 - widthVal()) + 'px';
}
+ function noPx(what) {
+ return el.style(what).replace(/px$/, '');
+ }
function widthVal() {
- return el.style('width').replace(/px$/, '');
+ return noPx('width');
+ }
+ function heightVal() {
+ return noPx('height');
}
fp = {
@@ -822,6 +828,12 @@
return widthVal();
}
el.style('width', w + 'px');
+ },
+ height: function (h) {
+ if (h === undefined) {
+ return heightVal();
+ }
+ el.style('height', h + 'px');
}
};
fpanels[id] = fp;
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index 46c0d02..ef0baf5 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -318,8 +318,9 @@
#topo-oibox div.onosInst {
display: inline-block;
- width: 120px;
- height: 100px;
+ width: 170px;
+ height: 85px;
+ cursor: pointer;
}
#topo-oibox svg rect {
@@ -350,6 +351,22 @@
fill: #fff;
}
+#topo-oibox svg text {
+ text-anchor: middle;
+ fill: #888;
+}
+#topo-oibox .online svg text {
+ fill: #000;
+}
+
+#topo-oibox svg text.instTitle {
+ font-size: 11pt;
+ font-weight: bold;
+}
+#topo-oibox svg text.instLabel {
+ font-size: 9pt;
+ font-style: italic;
+}
#topo-oibox .onosInst.mastership {
opacity: 0.3;
@@ -361,66 +378,6 @@
filter: url(#blue-glow);
}
-/* ------------------------------------------------------ */
-/* ------------------------------------------------------ */
-/* ------------------------------------------------------ */
-
-#topo-oibox .onosInst_OLD {
- position: relative;
- width: 88%;
- left: 4%;
- height: 80px;
- margin: 8px 0;
- cursor: pointer;
-
- -moz-border-radius: 12px;
- border-radius: 12px;
-
- /* theme-related */
- color: #444;
- background-color: #ccc;
- border: 4px solid #aaa;
-}
-
-#topo-oibox .onosInst_OLD .onosTitle {
- text-align: center;
- font-size: 10pt;
- margin-top: 6px;
- color: #888;
-}
-
-#topo-oibox .onosInst_OLD.online .onosTitle {
- color: black;
-}
-
-#topo-oibox .onosInst_OLD svg .glyphIcon {
- opacity: 0.5;
- fill: black;
- stroke: none;
- fill-rule: evenodd;
-}
-#topo-oibox .onosInst_OLD.online svg .glyphIcon {
- opacity: 1;
- fill: black;
- stroke: none;
- fill-rule: evenodd;
-}
-
-
-#topo-oibox .onosInst_OLD.online img {
- opacity: 1.0;
- padding: 3px;
-}
-
-#topo-oibox .onosInst_OLD img.ui {
- opacity: 1;
- position: absolute;
- top: 3px;
- right: 3px;
- width: 20px;
- height: 20px;
-}
-
#topo svg .suppressed {
opacity: 0.2;
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index cd30334..29a3773 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -580,7 +580,7 @@
updateLink: updateLink,
updateHost: updateHost,
- removeInstance: stillToImplement,
+ removeInstance: removeInstance,
removeDevice: stillToImplement,
removeLink: removeLink,
removeHost: removeHost,
@@ -715,6 +715,23 @@
}
// TODO: fold removeX(...) methods into base method - remove dup code
+ function removeInstance(data) {
+ evTrace(data);
+ var inst = data.payload,
+ id = inst.id,
+ instData = onosInstances[id];
+ if (instData) {
+ var idx = find(id, onosOrder, 'id');
+ if (idx >= 0) {
+ onosOrder.splice(idx, 1);
+ }
+ delete onosInstances[id];
+ updateInstances();
+ } else {
+ logicError('updateInstance lookup fail. ID = "' + id + '"');
+ }
+ }
+
function removeLink(data) {
evTrace(data);
var link = data.payload,
@@ -793,7 +810,9 @@
function stillToImplement(data) {
var p = data.payload;
note(data.event, p.id);
- network.view.alert('Not yet implemented: "' + data.event + '"');
+ if (!config.useLiveData) {
+ network.view.alert('Not yet implemented: "' + data.event + '"');
+ }
}
function unknownEvent(data) {
@@ -966,56 +985,62 @@
return true;
}
- // TODO: these should be moved out to utility module.
- function stripPx(s) {
- return s.replace(/px$/,'');
- }
-
- function appendUse(svg, ox, oy, dim, iid, cls) {
- var use = svg.append('use').attr({
- transform: translate(ox,oy),
- 'xlink:href': iid,
- width: dim,
- height: dim
- });
- if (cls) {
- use.classed(cls, true);
- }
- return use;
- }
-
- function appendGlyph(svg, ox, oy, dim, iid, cls) {
- appendUse(svg, ox, oy, dim, iid, cls).classed('glyphIcon', true);
- }
-
- function appendBadge(svg, ox, oy, dim, iid, cls) {
- appendUse(svg, ox, oy, dim, iid,cls ).classed('badgeIcon', true);
- }
-
- function attachUiBadge(svg) {
- appendBadge(svg, 12, 50, 30, '#uiAttached', 'uiBadge');
- }
// ==============================
// onos instance panel functions
- var instW = 120;
- function viewBox(w, h) {
- return '0 0 ' + w + ' ' + h;
+ var instCfg = {
+ rectPad: 8,
+ nodeOx: 9,
+ nodeOy: 9,
+ nodeDim: 40,
+ birdOx: 19,
+ birdOy: 21,
+ birdDim: 21,
+ uiDy: 45,
+ titleDy: 30,
+ textYOff: 20,
+ textYSpc: 15
+ };
+
+ function viewBox(dim) {
+ return '0 0 ' + dim.w + ' ' + dim.h;
+ }
+
+ function instRectAttr(dim) {
+ var pad = instCfg.rectPad;
+ return {
+ x: pad,
+ y: pad,
+ width: dim.w - pad*2,
+ height: dim.h - pad*2,
+ rx: 12
+ };
+ }
+
+ function computeDim(self) {
+ var css = window.getComputedStyle(self);
+ return {
+ w: stripPx(css.width),
+ h: stripPx(css.height)
+ };
}
function updateInstances() {
var onoses = oiBox.el.selectAll('.onosInst')
.data(onosOrder, function (d) { return d.id; }),
- boxW = instW * onosOrder.length;
+ instDim = {w:0,h:0},
+ c = instCfg;
- // adjust the width of the panel based on number of instances...
- oiBox.width(boxW);
+ function nSw(n) {
+ return '# Switches: ' + n;
+ }
// operate on existing onos instances if necessary
onoses.each(function (d) {
var el = d3.select(this),
svg = el.select('svg');
+ instDim = computeDim(this);
// update online state
el.classed('online', d.online);
@@ -1026,7 +1051,12 @@
attachUiBadge(svg);
}
- // TODO: update title and property values
+ function updAttr(id, value) {
+ svg.select('text.instLabel.'+id).text(value);
+ }
+
+ updAttr('ip', d.ip);
+ updAttr('ns', nSw(d.switches));
});
@@ -1039,61 +1069,64 @@
entering.each(function (d) {
var el = d3.select(this),
- css = window.getComputedStyle(this),
- w = stripPx(css.width),
- h = stripPx(css.height);
+ rectAttr,
+ svg;
+ instDim = computeDim(this);
+ rectAttr = instRectAttr(instDim);
- var svg = el.append('svg').attr({
- width: w,
- height: h,
- viewBox: viewBox(w, h)
+ svg = el.append('svg').attr({
+ width: instDim.w,
+ height: instDim.h,
+ viewBox: viewBox(instDim)
});
- svg.append('rect')
- .attr({
- x: 8,
- y: 8,
- width: 104,
- height: 84,
- rx: 12
- });
+ svg.append('rect').attr(rectAttr);
-
- appendGlyph(svg, 9, 9, 36, '#node');
- appendBadge(svg, 17, 19, 21, '#bird');
+ appendGlyph(svg, c.nodeOx, c.nodeOy, c.nodeDim, '#node');
+ appendBadge(svg, c.birdOx, c.birdOy, c.birdDim, '#bird');
if (d.uiAttached) {
attachUiBadge(svg);
}
- //svg.append('use')
- // .attr({
- // class: 'birdBadge',
- // transform: translate(8,10),
- // 'xlink:href': '#bird',
- // width: 18,
- // height: 18,
- // fill: '#fff'
- // });
- //
- //$('<div>').attr('class', 'onosTitle').text(d.id).appendTo(el);
+ var left = c.nodeOx + c.nodeDim,
+ len = rectAttr.width - left,
+ hlen = len / 2,
+ midline = hlen + left;
- // is the UI attached to this instance?
- // TODO: need uiAttached boolean in instance data
- // TODO: use SVG glyph, not png..
- //if (d.uiAttached) {
- //if (i === 0) {
- // $('<img src="img/ui.png">').attr('class','ui').appendTo(el);
- //}
+ // title
+ svg.append('text')
+ .attr({
+ class: 'instTitle',
+ x: midline,
+ y: c.titleDy
+ })
+ .text(d.id);
+
+ // a couple of attributes
+ var ty = c.titleDy + c.textYOff;
+
+ function addAttr(id, label) {
+ svg.append('text').attr({
+ class: 'instLabel ' + id,
+ x: midline,
+ y: ty
+ }).text(label);
+ ty += c.textYSpc;
+ }
+
+ addAttr('ip', d.ip);
+ addAttr('ns', nSw(d.switches));
});
// operate on existing + new onoses here
- // the departed...
- var exiting = onoses.exit()
- .transition()
- .style('opacity', 0)
- .remove();
+ // adjust the panel size appropriately...
+ oiBox.width(instDim.w * onosOrder.length);
+ oiBox.height(instDim.h);
+
+ // remove any outgoing instances
+ onoses.exit().remove();
}
function clickInst(d) {
@@ -1128,6 +1161,36 @@
oiShowMaster = false;
}
+ // TODO: these should be moved out to utility module.
+ function stripPx(s) {
+ return s.replace(/px$/,'');
+ }
+
+ function appendUse(svg, ox, oy, dim, iid, cls) {
+ var use = svg.append('use').attr({
+ transform: translate(ox,oy),
+ 'xlink:href': iid,
+ width: dim,
+ height: dim
+ });
+ if (cls) {
+ use.classed(cls, true);
+ }
+ return use;
+ }
+
+ function appendGlyph(svg, ox, oy, dim, iid, cls) {
+ appendUse(svg, ox, oy, dim, iid, cls).classed('glyphIcon', true);
+ }
+
+ function appendBadge(svg, ox, oy, dim, iid, cls) {
+ appendUse(svg, ox, oy, dim, iid,cls ).classed('badgeIcon', true);
+ }
+
+ function attachUiBadge(svg) {
+ appendBadge(svg, 12, instCfg.uiDy, 30, '#uiAttached', 'uiBadge');
+ }
+
// ==============================
// force layout modification functions
@@ -1763,9 +1826,12 @@
}
- function find(key, array) {
- for (var idx = 0, n = array.length; idx < n; idx++) {
- if (array[idx].key === key) {
+ function find(key, array, tag) {
+ var _tag = tag || 'key',
+ idx, n, d;
+ for (idx = 0, n = array.length; idx < n; idx++) {
+ d = array[idx];
+ if (d[_tag] === key) {
return idx;
}
}