ONOS-293 Added summary pane and related keyboard shortcuts; also tweaked key help sizes and dropped instances toggle from mast. Fixed ONOS-295 bug.
Change-Id: I694901957451cf88df06e6fca3a8d71de144f68e
diff --git a/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java b/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java
index 9703970..ad6d142 100644
--- a/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java
@@ -43,10 +43,10 @@
.put("node", get(ClusterService.class).getLocalNode().ip().toString())
.put("version", get(CoreService.class).version().toString())
.put("nodes", get(ClusterService.class).getNodes().size())
- .put("devices", get(DeviceService.class).getDeviceCount())
- .put("links", get(LinkService.class).getLinkCount())
+ .put("devices", topology.deviceCount())
+ .put("links", topology.linkCount())
.put("hosts", get(HostService.class).getHostCount())
- .put("clusters", topologyService.getClusters(topology).size())
+ .put("clusters", topology.clusterCount())
.put("paths", topology.pathCount())
.put("flows", get(FlowRuleService.class).getFlowRuleCount())
.put("intents", get(IntentService.class).getIntentCount()));
diff --git a/tools/package/bin/onos-service b/tools/package/bin/onos-service
index ae6d970..7ce1b15 100755
--- a/tools/package/bin/onos-service
+++ b/tools/package/bin/onos-service
@@ -4,7 +4,7 @@
# -----------------------------------------------------------------------------
#export JAVA_HOME=${JAVA_HOME:-/usr/lib/jvm/java-7-openjdk-amd64/}
-export JAVA_OPTS="${JAVA_OPTS:--Xms256M -Xmx2048M}"
+export JAVA_OPTS="${JAVA_OPTS:--Xms256m -Xmx2048m}"
cd /opt/onos
/opt/onos/apache-karaf-$KARAF_VERSION/bin/karaf "$@"
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java
index 6c12400..91a820c 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java
@@ -23,6 +23,7 @@
import org.onlab.onos.cluster.ClusterService;
import org.onlab.onos.cluster.ControllerNode;
import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.core.CoreService;
import org.onlab.onos.mastership.MastershipService;
import org.onlab.onos.net.Annotated;
import org.onlab.onos.net.Annotations;
@@ -56,6 +57,8 @@
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.statistic.Load;
import org.onlab.onos.net.statistic.StatisticService;
+import org.onlab.onos.net.topology.Topology;
+import org.onlab.onos.net.topology.TopologyService;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.IpAddress;
import org.slf4j.Logger;
@@ -117,8 +120,10 @@
protected final IntentService intentService;
protected final FlowRuleService flowService;
protected final StatisticService statService;
+ protected final TopologyService topologyService;
protected final ObjectMapper mapper = new ObjectMapper();
+ private final String version;
// TODO: extract into an external & durable state; good enough for now and demo
private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>();
@@ -138,6 +143,9 @@
intentService = directory.get(IntentService.class);
flowService = directory.get(FlowRuleService.class);
statService = directory.get(StatisticService.class);
+ topologyService = directory.get(TopologyService.class);
+
+ version = directory.get(CoreService.class).version().toString();
}
// Retrieves the payload from the specified event.
@@ -419,6 +427,22 @@
metaUi.put(string(payload, "id"), (ObjectNode) payload.path("memento"));
}
+ // Returns summary response.
+ protected ObjectNode summmaryMessage(long sid) {
+ Topology topology = topologyService.currentTopology();
+ return envelope("showSummary", sid,
+ json("ONOS Summary", "node",
+ new Prop("Devices", format(topology.deviceCount())),
+ new Prop("Links", format(topology.linkCount())),
+ new Prop("Hosts", format(hostService.getHostCount())),
+ new Prop("Topology SCCs", format(topology.clusterCount())),
+ new Prop("Paths", format(topology.pathCount())),
+ new Separator(),
+ new Prop("Intents", format(intentService.getIntentCount())),
+ new Prop("Flows", format(flowService.getFlowRuleCount())),
+ new Prop("Version", version.replace(".SNAPSHOT", "*"))));
+ }
+
// Returns device details response.
protected ObjectNode deviceDetails(DeviceId deviceId, long sid) {
Device device = deviceService.getDevice(deviceId);
@@ -435,12 +459,12 @@
new Prop("S/W Version", device.swVersion()),
new Prop("Serial Number", device.serialNumber()),
new Separator(),
+ new Prop("Master", master(deviceId)),
new Prop("Latitude", annot.value("latitude")),
new Prop("Longitude", annot.value("longitude")),
- new Prop("Ports", Integer.toString(portCount)),
- new Prop("Flows", Integer.toString(flowCount)),
new Separator(),
- new Prop("Master", master(deviceId))));
+ new Prop("Ports", Integer.toString(portCount)),
+ new Prop("Flows", Integer.toString(flowCount))));
}
protected int getFlowCount(DeviceId deviceId) {
@@ -641,6 +665,12 @@
return format.format(value) + " " + unit;
}
+ // Formats the given number into a string.
+ private String format(Number number) {
+ DecimalFormat format = new DecimalFormat("#,###");
+ return format.format(number);
+ }
+
private boolean isInfrastructureEgress(Link link) {
return link.src().elementId() instanceof DeviceId;
}
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java
index 104fa95..9562040 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java
@@ -42,7 +42,11 @@
import org.onlab.osgi.ServiceDirectory;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
@@ -70,8 +74,17 @@
private static final String APP_ID = "org.onlab.onos.gui";
+ private static final long SUMMARY_FREQUENCY_SEC = 2000;
private static final long TRAFFIC_FREQUENCY_SEC = 1000;
+ private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
+ new Comparator<ControllerNode>() {
+ @Override
+ public int compare(ControllerNode o1, ControllerNode o2) {
+ return o1.id().toString().compareTo(o2.id().toString());
+ }
+ };
+
private final ApplicationId appId;
private Connection connection;
@@ -83,10 +96,14 @@
private final HostListener hostListener = new InternalHostListener();
private final IntentListener intentListener = new InternalIntentListener();
- // Intents that are being monitored for the GUI
- private ObjectNode monitorRequest;
- private final Timer timer = new Timer("intent-traffic-monitor");
- private final TimerTask timerTask = new IntentTrafficMonitor();
+ // Timers and objects being monitored
+ private final Timer timer = new Timer("topology-view");
+
+ private TimerTask trafficTask;
+ private ObjectNode trafficEvent;
+
+ private TimerTask summaryTask;
+ private ObjectNode summaryEvent;
private long lastActive = System.currentTimeMillis();
private boolean listenersRemoved = false;
@@ -140,7 +157,6 @@
this.connection = connection;
this.control = (FrameConnection) connection;
addListeners();
- timer.schedule(timerTask, TRAFFIC_FREQUENCY_SEC, TRAFFIC_FREQUENCY_SEC);
sendAllInstances();
sendAllDevices();
@@ -181,6 +197,7 @@
updateMetaUi(event);
} else if (type.equals("addHostIntent")) {
createHostIntent(event);
+
} else if (type.equals("requestTraffic")) {
requestTraffic(event);
} else if (type.equals("requestAllTraffic")) {
@@ -189,6 +206,11 @@
requestDeviceLinkFlows(event);
} else if (type.equals("cancelTraffic")) {
cancelTraffic(event);
+
+ } else if (type.equals("requestSummary")) {
+ requestSummary(event);
+ } else if (type.equals("cancelSummary")) {
+ cancelSummary(event);
}
}
@@ -205,7 +227,9 @@
// Sends all controller nodes to the client as node-added messages.
private void sendAllInstances() {
- for (ControllerNode node : clusterService.getNodes()) {
+ List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
+ Collections.sort(nodes, NODE_COMPARATOR);
+ for (ControllerNode node : nodes) {
sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node)));
}
}
@@ -255,22 +279,37 @@
HostToHostIntent hostIntent = new HostToHostIntent(appId, one, two,
DefaultTrafficSelector.builder().build(),
DefaultTrafficTreatment.builder().build());
- monitorRequest = event;
+ trafficEvent = event;
intentService.submit(hostIntent);
}
+ private synchronized long startMonitoring(ObjectNode event) {
+ if (trafficTask == null) {
+ trafficEvent = event;
+ trafficTask = new TrafficMonitor();
+ timer.schedule(trafficTask, TRAFFIC_FREQUENCY_SEC, TRAFFIC_FREQUENCY_SEC);
+ }
+ return number(event, "sid");
+ }
+
+ private synchronized void stopMonitoring() {
+ if (trafficTask != null) {
+ trafficTask.cancel();
+ trafficTask = null;
+ trafficEvent = null;
+ }
+ }
+
// Subscribes for host traffic messages.
private synchronized void requestAllTraffic(ObjectNode event) {
ObjectNode payload = payload(event);
- long sid = number(event, "sid");
- monitorRequest = event;
+ long sid = startMonitoring(event);
sendMessage(trafficSummaryMessage(sid));
}
private void requestDeviceLinkFlows(ObjectNode event) {
ObjectNode payload = payload(event);
- long sid = number(event, "sid");
- monitorRequest = event;
+ long sid = startMonitoring(event);
// Get the set of selected hosts and their intents.
ArrayNode ids = (ArrayNode) payload.path("ids");
@@ -294,8 +333,7 @@
return;
}
- long sid = number(event, "sid");
- monitorRequest = event;
+ long sid = startMonitoring(event);
// Get the set of selected hosts and their intents.
ArrayNode ids = (ArrayNode) payload.path("ids");
@@ -325,9 +363,30 @@
// Cancels sending traffic messages.
private void cancelTraffic(ObjectNode event) {
sendMessage(trafficMessage(number(event, "sid")));
- monitorRequest = null;
+ stopMonitoring();
}
+
+ // Subscribes for summary messages.
+ private synchronized void requestSummary(ObjectNode event) {
+ if (summaryTask == null) {
+ summaryEvent = event;
+ summaryTask = new SummaryMonitor();
+ timer.schedule(summaryTask, SUMMARY_FREQUENCY_SEC, SUMMARY_FREQUENCY_SEC);
+ }
+ sendMessage(summmaryMessage(number(event, "sid")));
+ }
+
+ // Cancels sending summary messages.
+ private synchronized void cancelSummary(ObjectNode event) {
+ if (summaryTask != null) {
+ summaryTask.cancel();
+ summaryTask = null;
+ summaryEvent = null;
+ }
+ }
+
+
// Adds all internal listeners.
private void addListeners() {
clusterService.addListener(clusterListener);
@@ -385,26 +444,36 @@
private class InternalIntentListener implements IntentListener {
@Override
public void event(IntentEvent event) {
- if (monitorRequest != null) {
- requestTraffic(monitorRequest);
+ if (trafficEvent != null) {
+ requestTraffic(trafficEvent);
}
}
}
- private class IntentTrafficMonitor extends TimerTask {
+ private class TrafficMonitor extends TimerTask {
@Override
public void run() {
- if (monitorRequest != null) {
- String type = string(monitorRequest, "event", "unknown");
+ if (trafficEvent != null) {
+ String type = string(trafficEvent, "event", "unknown");
if (type.equals("requestAllTraffic")) {
- requestAllTraffic(monitorRequest);
+ requestAllTraffic(trafficEvent);
} else if (type.equals("requestDeviceLinkFlows")) {
- requestDeviceLinkFlows(monitorRequest);
+ requestDeviceLinkFlows(trafficEvent);
} else {
- requestTraffic(monitorRequest);
+ requestTraffic(trafficEvent);
}
}
}
}
+
+ private class SummaryMonitor extends TimerTask {
+ @Override
+ public void run() {
+ if (summaryEvent != null) {
+ requestSummary(summaryEvent);
+ }
+ }
+ }
+
}
diff --git a/web/gui/src/main/webapp/feedback.css b/web/gui/src/main/webapp/feedback.css
index 952688d..06716bb 100644
--- a/web/gui/src/main/webapp/feedback.css
+++ b/web/gui/src/main/webapp/feedback.css
@@ -23,7 +23,7 @@
#feedback svg {
position: absolute;
bottom: 0;
- opacity: 0.5;
+ opacity: 0.8;
}
#feedback svg g.feedbackItem {
@@ -31,14 +31,11 @@
}
#feedback svg g.feedbackItem rect {
- fill: #888;
- stroke: #666;
- stroke-width: 3;
- opacity: 0.5
+ fill: #ccc;
}
#feedback svg g.feedbackItem text {
- fill: #000;
+ fill: #333;
stroke: none;
text-anchor: middle;
alignment-baseline: middle;
diff --git a/web/gui/src/main/webapp/feedback.js b/web/gui/src/main/webapp/feedback.js
index 10f87c9..644202e 100644
--- a/web/gui/src/main/webapp/feedback.js
+++ b/web/gui/src/main/webapp/feedback.js
@@ -33,7 +33,7 @@
var w = '100%',
h = 200,
fade = 200,
- showFor = 500,
+ showFor = 1200,
vb = '-200 -' + (h/2) + ' 400 ' + h,
xpad = 20,
ypad = 10;
diff --git a/web/gui/src/main/webapp/floatPanel.css b/web/gui/src/main/webapp/floatPanel.css
index bacf29e..2a9b8a2 100644
--- a/web/gui/src/main/webapp/floatPanel.css
+++ b/web/gui/src/main/webapp/floatPanel.css
@@ -24,8 +24,8 @@
position: absolute;
z-index: 100;
display: block;
- top: 10%;
- width: 280px;
+ top: 64px;
+ width: 260px;
right: -300px;
opacity: 0;
background-color: rgba(255,255,255,0.8);
diff --git a/web/gui/src/main/webapp/keymap.css b/web/gui/src/main/webapp/keymap.css
index 7e6ade0..e6b9715 100644
--- a/web/gui/src/main/webapp/keymap.css
+++ b/web/gui/src/main/webapp/keymap.css
@@ -31,10 +31,10 @@
}
#keymap svg text.title {
- font-size: 12pt;
+ font-size: 10pt;
font-style: italic;
text-anchor: middle;
- fill: #444;
+ fill: #999;
}
#keymap svg g.keyItem {
@@ -47,17 +47,17 @@
}
#keymap svg text {
- font-size: 10pt;
+ font-size: 7pt;
alignment-baseline: middle;
}
#keymap svg text.key {
- font-size: 10pt;
- fill: #8aa;
+ font-size: 7pt;
+ fill: #add;
}
#keymap svg text.desc {
- font-size: 10pt;
- fill: #888;
+ font-size: 7pt;
+ fill: #aaa;
}
diff --git a/web/gui/src/main/webapp/keymap.js b/web/gui/src/main/webapp/keymap.js
index 85f2539..3d96a56 100644
--- a/web/gui/src/main/webapp/keymap.js
+++ b/web/gui/src/main/webapp/keymap.js
@@ -35,9 +35,9 @@
fade = 500,
vb = '-220 -220 440 440',
paneW = 400,
- paneH = 340,
+ paneH = 280,
offy = 65,
- dy = 20,
+ dy = 14,
offKey = 40,
offDesc = offKey + 50,
lineW = paneW - (2*offKey);
diff --git a/web/gui/src/main/webapp/onos2.js b/web/gui/src/main/webapp/onos2.js
index d2a7baa..a9cb1b0 100644
--- a/web/gui/src/main/webapp/onos2.js
+++ b/web/gui/src/main/webapp/onos2.js
@@ -763,7 +763,8 @@
var pos = position || 'TR',
cfg = fpConfig[pos],
el,
- fp;
+ fp,
+ on = false;
if (fpanels[id]) {
buildError('Float panel with id "' + id + '" already exists.');
@@ -792,15 +793,20 @@
id: id,
el: el,
pos: pos,
+ isVisible: function () {
+ return on;
+ },
show: function () {
console.log('show pane: ' + id);
+ on = true;
el.transition().duration(750)
.style(cfg.side, pxShow())
.style('opacity', 1);
},
hide: function () {
console.log('hide pane: ' + id);
+ on = false;
el.transition().duration(750)
.style(cfg.side, pxHide())
.style('opacity', 0);
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index 809458d..d982ee2 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -177,10 +177,66 @@
font-size: 9pt;
}
+/* Fly-in summary pane */
+
+#topo-summary {
+ /* gets base CSS from .fpanel in floatPanel.css */
+ top: 64px;
+}
+
+#topo-summary svg {
+ display: inline-block;
+ width: 42px;
+ height: 42px;
+}
+
+#topo-summary svg .glyphIcon {
+ fill: black;
+ stroke: none;
+ fill-rule: evenodd;
+}
+
+#topo-summary h2 {
+ position: absolute;
+ margin: 0px 4px;
+ top: 20px;
+ left: 50px;
+ color: black;
+}
+
+#topo-summary h3 {
+ margin: 0px 4px;
+ top: 20px;
+ left: 50px;
+ color: black;
+}
+
+#topo-summary p, table {
+ margin: 4px 4px;
+}
+
+#topo-summary td.label {
+ font-style: italic;
+ color: #777;
+ padding-right: 12px;
+}
+
+#topo-summary td.value {
+}
+
+#topo-summary hr {
+ height: 1px;
+ color: #ccc;
+ background-color: #ccc;
+ border: 0;
+}
+
/* Fly-in details pane */
#topo-detail {
-/* gets base CSS from .fpanel in floatPanel.css */
+ /* gets base CSS from .fpanel in floatPanel.css */
+ top: 320px;
+
}
#topo-detail svg {
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 9db6461..44b90f0 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -141,6 +141,8 @@
S: injectStartupEvents,
space: injectTestEvent,
+ O: [toggleSummary, 'Toggle ONOS summary pane'],
+ I: [toggleInstances, 'Toggle ONOS instances pane'],
B: [toggleBg, 'Toggle background image'],
L: [cycleLabels, 'Cycle Device labels'],
P: togglePorts,
@@ -182,6 +184,7 @@
selections = {},
selectOrder = [],
hovered = null,
+ summaryPane,
detailPane,
antTimer = null,
onosInstances = {},
@@ -329,7 +332,7 @@
if (hoverMode === hoverModes.length) {
hoverMode = 0;
}
- view.flash('Hover Mode: ' + hoverModes[hoverMode]);
+ view.flash('Mode: ' + hoverModes[hoverMode]);
}
function togglePorts(view) {
@@ -347,8 +350,12 @@
function handleEscape(view) {
if (oiShowMaster) {
cancelAffinity();
- } else {
+ } else if (detailPane.isVisible()) {
deselectAll();
+ } else if (oiBox.isVisible()) {
+ oiBox.hide();
+ } else if (summaryPane.isVisible()) {
+ cancelSummary();
}
}
@@ -585,6 +592,7 @@
removeHost: removeHost,
showDetails: showDetails,
+ showSummary: showSummary,
showTraffic: showTraffic
};
@@ -737,6 +745,12 @@
}
}
+ function showSummary(data) {
+ evTrace(data);
+ populateSummary(data.payload);
+ summaryPane.show();
+ }
+
function showDetails(data) {
evTrace(data);
populateDetails(data.payload);
@@ -824,6 +838,33 @@
return true;
}
+
+ function toggleInstances() {
+ if (!oiBox.isVisible()) {
+ oiBox.show();
+ } else {
+ oiBox.hide();
+ }
+ }
+
+ function toggleSummary() {
+ if (!summaryPane.isVisible()) {
+ requestSummary();
+ } else {
+ cancelSummary();
+ }
+ }
+
+ // request overall summary data
+ function requestSummary() {
+ sendMessage('requestSummary', {});
+ }
+
+ function cancelSummary() {
+ sendMessage('cancelSummary', {});
+ summaryPane.hide();
+ }
+
// request details for the selected element
// invoked from selection of a single node.
function requestDetails() {
@@ -845,16 +886,20 @@
}
function showTrafficAction() {
- // force intents hover mode
+ cancelTraffic();
hoverMode = 1;
showSelectTraffic();
network.view.flash('Related Traffic');
}
+ function cancelTraffic() {
+ sendMessage('cancelTraffic', {});
+ }
+
function showSelectTraffic() {
// if nothing is hovered over, and nothing selected, send cancel request
if (!hovered && nSel() === 0) {
- sendMessage('cancelTraffic', {});
+ cancelTraffic();
return;
}
@@ -870,12 +915,13 @@
}
function showAllTrafficAction() {
+ cancelTraffic();
sendMessage('requestAllTraffic', {});
network.view.flash('All Traffic');
}
function showDeviceLinkFlowsAction() {
- // force intents hover mode
+ cancelTraffic();
hoverMode = 2;
showDeviceLinkFlows();
network.view.flash('Device Flows');
@@ -884,7 +930,7 @@
function showDeviceLinkFlows() {
// if nothing is hovered over, and nothing selected, send cancel request
if (!hovered && nSel() === 0) {
- sendMessage('cancelTraffic', {});
+ cancelTraffic();
return;
}
var hoverId = (flowsHover() && hovered && hovered.class === 'device') ?
@@ -907,7 +953,6 @@
'xlink:href': iid,
width: dim,
height: dim
-
});
}
@@ -940,6 +985,15 @@
});
var dim = 30;
appendGlyph(svg, 2, 2, 30, '#node');
+ 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);
@@ -1720,6 +1774,8 @@
webSock.ws.onopen = function() {
noWebSock(false);
+ requestSummary();
+ oiBox.show();
};
webSock.ws.onmessage = function(m) {
@@ -1881,12 +1937,17 @@
updateDetailPane();
}
+ // update the state of the sumary pane
+ function updateSummaryPane() {
+
+ }
+
// update the state of the detail pane, based on current selections
function updateDetailPane() {
var nSel = selectOrder.length;
if (!nSel) {
detailPane.hide();
- showTrafficAction(); // sends cancelTraffic event
+ cancelTraffic();
} else if (nSel === 1) {
singleSelect();
} else {
@@ -1936,6 +1997,40 @@
addMultiSelectActions();
}
+ // TODO: refactor to consolidate with populateDetails
+ function populateSummary(data) {
+ summaryPane.empty();
+
+ var svg = summaryPane.append('svg'),
+ iid = iconGlyphUrl(data);
+
+ var title = summaryPane.append('h2'),
+ table = summaryPane.append('table'),
+ tbody = table.append('tbody');
+
+ appendGlyph(svg, 0, 0, 40, iid);
+
+ svg.append('use')
+ .attr({
+ class: 'birdBadge',
+ transform: translate(8,12),
+ 'xlink:href': '#bird',
+ width: 24,
+ height: 24,
+ fill: '#fff'
+ });
+
+ title.text('ONOS Summary');
+
+ data.propOrder.forEach(function(p) {
+ if (p === '-') {
+ addSep(tbody);
+ } else {
+ addProp(tbody, p, data.props[p]);
+ }
+ });
+ }
+
function populateDetails(data) {
detailPane.empty();
@@ -2056,7 +2151,7 @@
// TODO: toggle button (and other widgets in the masthead) should be provided
// by the framework; not generated by the view.
- var showInstances;
+ //var showInstances;
function addButtonBar(view) {
var bb = d3.select('#mast')
@@ -2069,20 +2164,20 @@
.on('click', cb);
}
- showInstances = mkTogBtn('Show Instances', toggleInst);
+ //showInstances = mkTogBtn('Show Instances', toggleInst);
}
- function instShown() {
- return showInstances.classed('active');
- }
- function toggleInst() {
- showInstances.classed('active', !instShown());
- if (instShown()) {
- oiBox.show();
- } else {
- oiBox.hide();
- }
- }
+ //function instShown() {
+ // return showInstances.classed('active');
+ //}
+ //function toggleInst() {
+ // showInstances.classed('active', !instShown());
+ // if (instShown()) {
+ // oiBox.show();
+ // } else {
+ // oiBox.hide();
+ // }
+ //}
function panZoom() {
return false;
@@ -2370,6 +2465,7 @@
resize: resize
});
+ summaryPane = onos.ui.addFloatingPanel('topo-summary');
detailPane = onos.ui.addFloatingPanel('topo-detail');
oiBox = onos.ui.addFloatingPanel('topo-oibox', 'TL');