ONOS-1479 -- GUI - augmenting topology view for extensibility:
- Preliminary work in implementing installation of custom buttons to details panel for selected device.
Change-Id: Id26ac301f72b4521d2a388d34ee0a287f400c68c
diff --git a/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java b/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
index 87b6839..03ff2a3 100644
--- a/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
+++ b/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
@@ -35,6 +35,7 @@
private String typeId;
private String id;
private List<Prop> properties = new ArrayList<>();
+ private List<Button> buttons = new ArrayList<>();
/**
* Constructs a property panel model with the given title and
@@ -174,6 +175,16 @@
return properties;
}
+ /**
+ * Returns the list of button descriptors.
+ *
+ * @return the button list
+ */
+ // TODO: consider protecting this?
+ public List<Button> buttons() {
+ return buttons;
+ }
+
// == MUTATORS
/**
@@ -226,6 +237,17 @@
return this;
}
+ /**
+ * Adds a button descriptor with the given identifier, to the panel data.
+ *
+ * @param id button identifier
+ * @return self, for chaining
+ */
+ public PropertyPanel addButton(String id) {
+ buttons.add(new Button(id));
+ return this;
+ }
+
// ====================
@@ -300,4 +322,29 @@
}
}
+ /**
+ * Button descriptor. Note that these work in conjunction with
+ * "buttons" defined in the JavaScript code for the overlay.
+ */
+ public static class Button {
+ private final String id;
+
+ /**
+ * Constructs a button descriptor with the given identifier.
+ *
+ * @param id button identifier
+ */
+ public Button(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns the identifier for this button.
+ *
+ * @return button identifier
+ */
+ public String id() {
+ return id;
+ }
+ }
}
diff --git a/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java b/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java
index ca3ce5f..d44ba9f 100644
--- a/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java
+++ b/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java
@@ -73,4 +73,37 @@
public static final String STOP = "stop";
public static final String CLOUD = "cloud";
}
+
+ /**
+ * Defines constants for property names on the default summary and
+ * details panels.
+ */
+ public static final class Properties {
+ // summary panel
+ public static final String DEVICES = "Devices";
+ public static final String LINKS = "Links";
+ public static final String HOSTS = "Hosts";
+ public static final String TOPOLOGY_SSCS = "Topology SCCs";
+ public static final String INTENTS = "Intents";
+ public static final String TUNNELS = "Tunnels";
+ public static final String FLOWS = "Flows";
+ public static final String VERSION = "Version";
+
+ // device details
+ public static final String URI = "URI";
+ public static final String VENDOR = "Vendor";
+ public static final String HW_VERSION = "H/W Version";
+ public static final String SW_VERSION = "S/W Version";
+ public static final String SERIAL_NUMBER = "Serial Number";
+ public static final String PROTOCOL = "Protocol";
+ public static final String LATITUDE = "Latitude";
+ public static final String LONGITUDE = "Longitude";
+ public static final String PORTS = "Ports";
+
+ // host details
+ public static final String MAC = "MAC";
+ public static final String IP = "IP";
+ public static final String VLAN = "VLAN";
+ }
+
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index 017925b..e6b4ac4 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -107,6 +107,7 @@
import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.FLOW;
import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.PORT;
+import static org.onosproject.ui.topo.TopoConstants.*;
/**
* Facility for creating messages bound for the topology viewer.
@@ -448,15 +449,15 @@
Topology topology = topologyService.currentTopology();
return new PropertyPanel("ONOS Summary", "node")
- .addProp("Devices", topology.deviceCount())
- .addProp("Links", topology.linkCount())
- .addProp("Hosts", hostService.getHostCount())
- .addProp("Topology SCCs", topology.clusterCount())
+ .addProp(Properties.DEVICES, topology.deviceCount())
+ .addProp(Properties.LINKS, topology.linkCount())
+ .addProp(Properties.HOSTS, hostService.getHostCount())
+ .addProp(Properties.TOPOLOGY_SSCS, topology.clusterCount())
.addSeparator()
- .addProp("Intents", intentService.getIntentCount())
- .addProp("Tunnels", tunnelService.tunnelCount())
- .addProp("Flows", flowService.getFlowRuleCount())
- .addProp("Version", version);
+ .addProp(Properties.INTENTS, intentService.getIntentCount())
+ .addProp(Properties.TUNNELS, tunnelService.tunnelCount())
+ .addProp(Properties.FLOWS, flowService.getFlowRuleCount())
+ .addProp(Properties.VERSION, version);
}
// Returns property panel model for device details response.
@@ -472,20 +473,20 @@
String typeId = device.type().toString().toLowerCase();
PropertyPanel pp = new PropertyPanel(title, typeId)
- .id(deviceId.toString())
- .addProp("URI", deviceId.toString())
- .addProp("Vendor", device.manufacturer())
- .addProp("H/W Version", device.hwVersion())
- .addProp("S/W Version", device.swVersion())
- .addProp("Serial Number", device.serialNumber())
- .addProp("Protocol", annot.value(AnnotationKeys.PROTOCOL))
- .addSeparator()
- .addProp("Latitude", annot.value(AnnotationKeys.LATITUDE))
- .addProp("Longitude", annot.value(AnnotationKeys.LONGITUDE))
- .addSeparator()
- .addProp("Ports", portCount)
- .addProp("Flows", flowCount)
- .addProp("Tunnels", tunnelCount);
+ .id(deviceId.toString())
+ .addProp(Properties.URI, deviceId.toString())
+ .addProp(Properties.VENDOR, device.manufacturer())
+ .addProp(Properties.HW_VERSION, device.hwVersion())
+ .addProp(Properties.SW_VERSION, device.swVersion())
+ .addProp(Properties.SERIAL_NUMBER, device.serialNumber())
+ .addProp(Properties.PROTOCOL, annot.value(AnnotationKeys.PROTOCOL))
+ .addSeparator()
+ .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
+ .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE))
+ .addSeparator()
+ .addProp(Properties.PORTS, portCount)
+ .addProp(Properties.FLOWS, flowCount)
+ .addProp(Properties.TUNNELS, tunnelCount);
// TODO: add button descriptors
@@ -570,13 +571,13 @@
String typeId = isNullOrEmpty(type) ? "endstation" : type;
PropertyPanel pp = new PropertyPanel(title, typeId)
- .id(hostId.toString())
- .addProp("MAC", host.mac())
- .addProp("IP", host.ipAddresses(), "[\\[\\]]")
- .addProp("VLAN", vlan.equals("-1") ? "none" : vlan)
- .addSeparator()
- .addProp("Latitude", annot.value(AnnotationKeys.LATITUDE))
- .addProp("Longitude", annot.value(AnnotationKeys.LONGITUDE));
+ .id(hostId.toString())
+ .addProp(Properties.MAC, host.mac())
+ .addProp(Properties.IP, host.ipAddresses(), "[\\[\\]]")
+ .addProp(Properties.VLAN, vlan.equals("-1") ? "none" : vlan)
+ .addSeparator()
+ .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
+ .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE));
// TODO: add button descriptors
return pp;
@@ -859,6 +860,12 @@
}
result.set("propOrder", porder);
result.set("props", pnode);
+
+ ArrayNode buttons = arrayNode();
+ for (PropertyPanel.Button b : pp.buttons()) {
+ buttons.add(b.id());
+ }
+ result.set("buttons", buttons);
return result;
}
diff --git a/web/gui/src/main/webapp/_sdh/overlaywork/AppUiTopoOverlay.java b/web/gui/src/main/webapp/_sdh/overlaywork/AppUiTopoOverlay.java
new file mode 100644
index 0000000..494885d
--- /dev/null
+++ b/web/gui/src/main/webapp/_sdh/overlaywork/AppUiTopoOverlay.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.meowster.over;
+
+import org.onosproject.ui.UiTopoOverlay;
+import org.onosproject.ui.topo.PropertyPanel;
+import org.onosproject.ui.topo.TopoConstants.Glyphs;
+
+import static org.onosproject.ui.topo.TopoConstants.Properties.*;
+
+/**
+ * Our topology overlay.
+ */
+public class AppUiTopoOverlay extends UiTopoOverlay {
+
+ // NOTE: this must match the ID defined in topov.js
+ private static final String OVERLAY_ID = "meowster-overlay";
+
+ private static final String MY_TITLE = "I changed the title";
+ private static final String MY_VERSION = "Beta-1.0.0042";
+ private static final String FOO = "foo";
+ private static final String BAR = "bar";
+
+
+ public AppUiTopoOverlay() {
+ super(OVERLAY_ID);
+ }
+
+
+ @Override
+ public void modifySummary(PropertyPanel pp) {
+ pp.title("My App Rocks!")
+ .typeId(Glyphs.CROWN)
+ .removeProps(
+ TOPOLOGY_SSCS,
+ INTENTS,
+ TUNNELS,
+ FLOWS,
+ VERSION
+ )
+ .addProp(VERSION, MY_VERSION);
+
+ }
+
+ @Override
+ public void modifyDeviceDetails(PropertyPanel pp) {
+ pp.title(MY_TITLE);
+ pp.removeProps(LATITUDE, LONGITUDE);
+ pp.addButton(FOO).addButton(BAR);
+ }
+
+// TODO: override more methods, as required...
+
+}
diff --git a/web/gui/src/main/webapp/_sdh/overlaywork/README.txt b/web/gui/src/main/webapp/_sdh/overlaywork/README.txt
new file mode 100644
index 0000000..d7dcbec
--- /dev/null
+++ b/web/gui/src/main/webapp/_sdh/overlaywork/README.txt
@@ -0,0 +1,4 @@
+NOTE:
+
+This directory is putting under revision control some key files from
+an example stand-alone app, as I develop the topology overlay functionality.
diff --git a/web/gui/src/main/webapp/_sdh/overlaywork/topov.js b/web/gui/src/main/webapp/_sdh/overlaywork/topov.js
index b845d54..80a3fa9 100644
--- a/web/gui/src/main/webapp/_sdh/overlaywork/topov.js
+++ b/web/gui/src/main/webapp/_sdh/overlaywork/topov.js
@@ -7,21 +7,52 @@
// our overlay definition
var overlay = {
- overlayId: 'sampleTopoOver',
+ // NOTE: this must match the ID defined in AppUiTopoOverlay
+ overlayId: 'meowster-overlay',
+ glyphId: '*star4',
+ tooltip: 'Sample Meowster Topo Overlay',
- // NOTE: for the glyph, could alternately use id: <existingGlyphId>
- // instead of defining viewbox and data (vb, d)
- // glyph: { id: 'crown' }
- glyph: {
- vb: '0 0 8 8',
- d: 'M1,4l2,-1l1,-2l1,2l2,1l-2,1l-1,2l-1,-2z'
+ // These glyphs get installed using the overlayId as a prefix.
+ // e.g. 'star4' is installed as 'meowster-overlay-star4'
+ // They can be referenced (from this overlay) as '*star4'
+ // That is, the '*' prefix stands in for 'meowster-overlay-'
+ glyphs: {
+ star4: {
+ vb: '0 0 8 8',
+ d: 'M1,4l2,-1l1,-2l1,2l2,1l-2,1l-1,2l-1,-2z'
+ },
+ banner: {
+ vb: '0 0 6 6',
+ d: 'M1,1v4l2,-2l2,2v-4z'
+ }
},
- tooltip: 'Sample Topology Overlay',
activate: activateOverlay,
- deactivate: deactivateOverlay
+ deactivate: deactivateOverlay,
+
+ // button descriptors - these can be added to overview or detail panels
+ buttons: {
+ foo: {
+ gid: 'chain',
+ tt: 'a FOO action',
+ cb: fooCb
+ },
+ bar: {
+ gid: '*banner',
+ tt: 'a BAR action',
+ cb: barCb
+ }
+ }
};
+ function fooCb(data) {
+ $log.debug('FOO callback with data:', data);
+ }
+
+ function barCb(data) {
+ $log.debug('BAR callback with data:', data);
+ }
+
// === implementation of overlay API (essentially callbacks)
function activateOverlay() {
$log.debug("sample topology overlay ACTIVATED");
diff --git a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
index e2b3125..9dddc9b 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
@@ -44,26 +44,36 @@
$log.warn(tos + fn + '(): ' + msg);
}
- function handleGlyph(o) {
- var gdata = fs.isO(o.glyph),
- oid,
- data = {};
+ function mkGlyphId(oid, gid) {
+ return (gid[0] === '*') ? oid + '-' + gid.slice(1) : gid;
+ }
- if (!gdata) {
- o._glyphId = 'unknown';
- } else {
- if (gdata.id) {
- o._glyphId = gdata.id;
- } else if (gdata.vb && gdata.d) {
- oid = o.overlayId;
- data['_' + oid] = gdata.vb;
- data[oid] = gdata.d;
- gs.registerGlyphs(data);
- o._glyphId = oid;
- $log.debug('registered overlay glyph:', oid);
- } else {
- warn('registerGlyph', 'problem with glyph data');
- }
+ function handleGlyphs(o) {
+ var gdata = fs.isO(o.glyphs),
+ oid = o.overlayId,
+ gid = o.glyphId || 'unknown',
+ data = {},
+ note = [];
+
+ o._glyphId = mkGlyphId(oid, gid);
+
+ o.mkGid = function (g) {
+ return mkGlyphId(oid, g);
+ };
+ o.mkId = function (s) {
+ return oid + '-' + s;
+ };
+
+ // process glyphs if defined
+ if (gdata) {
+ angular.forEach(gdata, function (value, key) {
+ var fullkey = oid + '-' + key;
+ data['_' + fullkey] = value.vb;
+ data[fullkey] = value.d;
+ note.push('*' + key);
+ });
+ gs.registerGlyphs(data);
+ $log.debug('registered overlay glyphs:', oid, note);
}
}
@@ -79,7 +89,7 @@
return warn(r, 'already registered: "' + id + '"');
}
overlays[id] = overlay;
- handleGlyph(overlay);
+ handleGlyphs(overlay);
$log.debug(tos + 'registered overlay: ' + id, overlay);
}
@@ -132,6 +142,28 @@
}
}
+ // install buttons from the current overlay
+ function installButtons(bids, addFn, data) {
+ if (current) {
+ bids.forEach(function (bid) {
+ var btn = current.buttons[bid],
+ funcWrap = function () {
+ btn.cb(data);
+ };
+
+ if (btn) {
+ addFn({
+ id: current.mkId(bid),
+ gid: current.mkGid(btn.gid),
+ cb: funcWrap,
+ tt: btn.tt
+ });
+ }
+ });
+ }
+
+ }
+
angular.module('ovTopo')
.factory('TopoOverlayService',
['$log', 'FnService', 'GlyphService', 'WebSocketService',
@@ -147,7 +179,8 @@
unregister: unregister,
list: list,
overlay: overlay,
- tbSelection: tbSelection
+ tbSelection: tbSelection,
+ installButtons: installButtons
}
}]);
diff --git a/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
index 051ce05..c02ef51 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoSelect.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
@@ -23,7 +23,7 @@
'use strict';
// injected refs
- var $log, fs, wss, tps, tts, ns;
+ var $log, fs, wss, tov, tps, tts, ns;
// api to topoForce
var api;
@@ -229,9 +229,13 @@
// Event Handlers
function showDetails(data) {
+ var buttons = fs.isA(data.buttons);
+
// display the data for the single selected node
tps.displaySingle(data);
+ // TODO: use server-side-button-descriptors to add buttons
+
// always add the 'show traffic' action
tps.addAction({
id: '-sin-rel-traf-btn',
@@ -249,6 +253,13 @@
tt: 'Show Device Flows'
});
}
+
+ // TODO: for now, install overlay buttons here
+ if (buttons) {
+ tov.installButtons(buttons, tps.addAction, data);
+ }
+
+
// TODO: have the server return explicit class and ID of each node
// for now, we assume the node is a device if it has a URI
if ((data.props).hasOwnProperty('URI')) {
@@ -308,13 +319,14 @@
angular.module('ovTopo')
.factory('TopoSelectService',
- ['$log', 'FnService', 'WebSocketService',
+ ['$log', 'FnService', 'WebSocketService', 'TopoOverlayService',
'TopoPanelService', 'TopoTrafficService', 'NavService',
- function (_$log_, _fs_, _wss_, _tps_, _tts_, _ns_) {
+ function (_$log_, _fs_, _wss_, _tov_, _tps_, _tts_, _ns_) {
$log = _$log_;
fs = _fs_;
wss = _wss_;
+ tov = _tov_;
tps = _tps_;
tts = _tts_;
ns = _ns_;
diff --git a/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js b/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js
index 1da60c1..71cb94c 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js
@@ -29,7 +29,7 @@
// traffic overlay definition
var overlay = {
overlayId: 'traffic',
- glyph: { id: 'allTraffic' },
+ glyphId: 'allTraffic',
tooltip: 'Traffic Overlay',
activate: activateTraffic,