Added GUI to intent perf app to monitor performance stats in real-time.
Fixed app ids for metrics app.
Change-Id: Icea99991ad71c80c53a832c236dcc05fefbb9b02
diff --git a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfCollector.java b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfCollector.java
index 90eb9d7..8683f3f 100644
--- a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfCollector.java
+++ b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfCollector.java
@@ -65,7 +65,7 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
- @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentPerfUi ui;
// Auxiliary structures used to accrue data for normalized time interval
@@ -99,6 +99,7 @@
nodeToIndex.put(nodes[i].id(), i);
}
+ ui.setHeaders(getSampleHeaders());
clearSamples();
log.info("Started");
}
diff --git a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
index 02aa1b3..96f2b32 100644
--- a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
+++ b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfInstaller.java
@@ -99,7 +99,7 @@
private static final int DEFAULT_NUM_NEIGHBORS = 0;
private static final int START_DELAY = 5_000; // ms
- private static final int REPORT_PERIOD = 5_000; //ms
+ private static final int REPORT_PERIOD = 1_000; //ms
private static final String START = "start";
private static final String STOP = "stop";
diff --git a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfUi.java b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfUi.java
index d30fe4e..f50ed3b 100644
--- a/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfUi.java
+++ b/apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfUi.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.intentperf;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -23,6 +24,7 @@
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
import org.onlab.osgi.ServiceDirectory;
import org.onosproject.intentperf.IntentPerfCollector.Sample;
import org.onosproject.ui.UiConnection;
@@ -34,14 +36,17 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Random;
import java.util.Set;
+import java.util.TimerTask;
import static java.util.Collections.synchronizedSet;
/**
* Mechanism to stream data to the GUI.
*/
-@Component(immediate = true, enabled = false)
+@Component(immediate = true, enabled = true)
+@Service(value = IntentPerfUi.class)
public class IntentPerfUi {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -53,9 +58,25 @@
private UiExtension uiExtension = new UiExtension(views, this::newHandlers,
getClass().getClassLoader());
+ private List<String> headers = ImmutableList.of("One", "Two", "Three", "Four", "Five");
+
+ private Random random = new Random();
+ private TimerTask task;
+
@Activate
protected void activate() {
uiExtensionService.register(uiExtension);
+// task = new TimerTask() {
+// @Override
+// public void run() {
+// Sample sample = new Sample(System.currentTimeMillis(), headers.size());
+// for (int i = 0; i < headers.size(); i++) {
+// sample.data[i] = 25_000 + random.nextInt(20_000) - 5_000;
+// }
+// reportSample(sample);
+// }
+// };
+// SharedExecutors.getTimer().scheduleAtFixedRate(task, 1000, 1000);
}
@Deactivate
@@ -74,6 +95,15 @@
}
}
+ /**
+ * Sets the headers for the subsequently reported samples.
+ *
+ * @param headers list of headers for future samples
+ */
+ public void setHeaders(List<String> headers) {
+ this.headers = headers;
+ }
+
// Creates and returns session specific message handler.
private Collection<UiMessageHandler> newHandlers() {
return ImmutableList.of(new StreamingControl());
@@ -90,7 +120,22 @@
@Override
public void process(ObjectNode message) {
- streamingEnabled = message.path("event").asText("unknown").equals("initPerfStart");
+ streamingEnabled = message.path("event").asText("unknown").equals("intentPerfStart");
+ if (streamingEnabled) {
+ sendHeaders();
+ }
+ }
+
+ private void sendHeaders() {
+ ArrayNode an = mapper.createArrayNode();
+ for (String header : headers) {
+ an.add(header);
+ }
+
+ ObjectNode sn = mapper.createObjectNode();
+ sn.set("headers", an);
+
+ connection().sendMessage("intentPerfHeaders", 0, sn);
}
@Override
@@ -106,10 +151,18 @@
}
private void send(Sample sample) {
- // FIXME: finish this
- ObjectNode sn = mapper.createObjectNode()
- .put("time", sample.time);
- connection().sendMessage("intentPerf", 0, sn);
+ if (streamingEnabled) {
+ ArrayNode an = mapper.createArrayNode();
+ for (double d : sample.data) {
+ an.add(d);
+ }
+
+ ObjectNode sn = mapper.createObjectNode();
+ sn.put("time", sample.time);
+ sn.set("data", an);
+
+ connection().sendMessage("intentPerfSample", 0, sn);
+ }
}
}
diff --git a/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.css b/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.css
index 604a169..d98b620 100644
--- a/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.css
+++ b/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.css
@@ -18,39 +18,35 @@
ONOS GUI -- Intent Perf View -- CSS file
*/
-.light #ov-intentPerf {
- color: navy;
+svg {
+ font: 12px sans-serif;
}
-.dark #ov-intentPerf {
- color: #1e5e6f;
+.line {
+ fill: none;
+ stroke: #000;
+ stroke-width: 2px;
}
-.dark a {
- color: #88c;
-}
-
-#ov-intentPerf .msg {
- color: darkorange;
-}
-
-.light #ov-intentPerf .msg {
- color: darkorange;
-}
-
-.dark #ov-intentPerf .msg {
- color: #904e00;
-}
-
-
-
.axis path,
.axis line {
fill: none;
- stroke: #000;
+ stroke-width: 2px;
shape-rendering: crispEdges;
}
-.browser text {
- text-anchor: end;
+.light .axis path,
+.light .axis line,
+.light .axis text {
+ stroke: #999;
}
+
+.dark .axis path,
+.dark .axis line,
+.dark .axis text {
+ stroke: #eee;
+}
+
+.axis text {
+ stroke-width: 0.3;
+}
\ No newline at end of file
diff --git a/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.html b/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.html
index b1ef9d2..6cdbc66 100644
--- a/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.html
+++ b/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.html
@@ -15,10 +15,12 @@
-->
<!-- Intent Performance partial HTML -->
-<div id="ov-sample">
+<div id="ov-intentPerf">
<h2> Intent Performance View </h2>
- <span class="msg">{{ ctrl.message }}</span>
-
- <div id="intent-perf-chart"></div>
+ <div id="intent-perf-chart"
+ resize
+ ng-style="resizeWithOffset(56, 12)"
+ notifier="ctrl.notifyResize()">
+ </div>
</div>
diff --git a/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.js b/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.js
index e18c47d..4fcdb0a 100644
--- a/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.js
+++ b/apps/test/intent-perf/src/main/resources/app/view/intentPerf/intentPerf.js
@@ -21,122 +21,248 @@
'use strict';
// injected refs
- var $log, tbs, flash;
+ var $log, tbs, ts, wss, sus, flash, fs, mast;
- function start() {
- //var format = d3.time.format("%m/%d/%y");
- var format = d3.time.format("%H:%M:%S");
- var samples = [];
+ // internal state
+ var handlerMap,
+ openListener,
+ theSample = [],
+ graph;
- var margin = {top: 20, right: 30, bottom: 30, left: 40},
- width = 960 - margin.left - margin.right,
- height = 500 - margin.top - margin.bottom;
+ // ==========================
- var x = d3.time.scale()
- .range([0, width]);
+ function createGraph(h) {
+ var stopped = false,
+ n = 243,
+ duration = 750,
+ now = new Date(Date.now() - duration),
+ headers = h,
+ data = [];
- var y = d3.scale.linear()
- .range([height, 0]);
+ var dim = fs.windowSize(mast.mastHeight());
+ var margin, width, height, x, y;
+ var svg, axis;
- var z = d3.scale.category20c();
+ var lines = [],
+ paths = [];
- var xAxis = d3.svg.axis()
- .scale(x)
- .orient("bottom")
- .ticks(d3.time.seconds);
+ var transition = d3.select({}).transition()
+ .duration(duration)
+ .ease("linear");
- var yAxis = d3.svg.axis()
- .scale(y)
- .orient("left");
+ svg = d3.select("#intent-perf-chart").append("p")
+ .append("svg").attr("id", "intent-perf-svg")
+ .append("g").attr("id", "intent-perf-svg-g");
- var stack = d3.layout.stack()
- .offset("zero")
- .values(function(d) { return d.values; })
- .x(function(d) { return d.date; })
- .y(function(d) { return d.value; });
+ svg.append("defs").append("clipPath").attr("id", "intent-perf-clip")
+ .append("rect");
- var nest = d3.nest()
- .key(function(d) { return d.key; });
-
- var area = d3.svg.area()
- .interpolate("cardinal")
- .x(function(d) { return x(d.date); })
- .y0(function(d) { return y(d.y0); })
- .y1(function(d) { return y(d.y0 + d.y); });
-
- var svg = d3.select("body").append("svg")
- .attr("width", width + margin.left + margin.right)
- .attr("height", height + margin.top + margin.bottom)
- .append("g")
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
-
- svg.append("g")
+ axis = svg.append("g")
.attr("class", "x axis")
- .attr("transform", "translate(0," + height + ")")
- .call(xAxis);
+ .attr("id", "intent-perf-x");
+
+ svg.append("g").attr("class", "y axis")
+ .attr("id", "intent-perf-yl");
svg.append("g")
.attr("class", "y axis")
- .call(yAxis);
+ .attr("id", "intent-perf-yr");
- function fetchData() {
- d3.csv("app/view/intentPerf/data.csv", function (data) {
- samples = data;
- updateGraph();
- });
+ resize(dim);
+
+ headers.forEach(function (h, li) {
+ // Prime the data to match the headeres and zero it out.
+ data[li] = d3.range(n).map(function() { return 0 });
+ theSample[li] = 0;
+
+ // Create the lines
+ lines[li] = d3.svg.line()
+ .interpolate("basis")
+ .x(function(d, i) { return x(now - (n - 1 - i) * duration); })
+ .y(function(d, i) { return y(d); });
+
+ // Create the SVG paths
+ paths[li] = svg.append("g")
+ .attr("clip-path", "url(#intent-perf-clip)")
+ .append("path")
+ .datum(function () { return data[li]; })
+ .attr("id", "line" + li)
+ .style("stroke", lineColor(li))
+ .attr("class", "line");
+ });
+
+ function lineColor(li) {
+ return li < headers.length - 1 ?
+ sus.cat7().getColor(li, false, ts.theme()) :
+ ts.theme() == 'light' ? '#333' : '#eee';
}
- function updateGraph() {
- samples.forEach(function(d) {
- d.date = format.parse(d.date);
- d.value = +d.value;
+ function tick() {
+ if (stopped) {
+ return;
+ }
+
+ transition = transition.each(function() {
+ // update the domains
+ now = new Date();
+ x.domain([now - (n - 2) * duration, now - duration]);
+
+ data.forEach(function (d, li) {
+ // push the new most recent sample onto the back
+ d.push(theSample[li]);
+
+ // redraw the line and slide it left
+ paths[li].attr("d", lines[li]).attr("transform", null);
+ paths[li].transition().attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");
+
+ // pop the old data point off the front
+ d.shift();
+ });
+
+ // slide the x-axis left
+ axis.call(x.axis);
+ }).transition().each("start", tick);
+ }
+
+ function start() {
+ stopped = false;
+ headers.forEach(function (h, li) {
+ theSample[li] = 0;
});
+ tick();
+ }
- var layers = stack(nest.entries(samples));
+ function stop() {
+ stopped = true;
+ }
- x.domain(d3.extent(samples, function(d) { return d.date; }));
- y.domain([0, d3.max(samples, function(d) { return d.y0 + d.y; })]);
+ function resize(dim) {
+ margin = {top: 20, right: 90, bottom: 20, left: 70};
+ width = dim.width - margin.right - margin.left;
+ height = 480 - margin.top - margin.bottom;
- svg.selectAll(".layer")
- .data(layers)
- .enter().append("path")
- .attr("class", "layer")
- .attr("d", function(d) { return area(d.values); })
- .style("fill", function(d, i) { return z(i); });
+ x = d3.time.scale()
+ .domain([now - (n - 2) * duration, now - duration])
+ .range([0, width]);
- svg.select(".x")
+ y = d3.scale.linear()
+ .domain([0, 200000])
+ .range([height, 0]);
+
+ d3.select("#intent-perf-svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom);
+ d3.select("#intent-perf-svg-g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.select("#intent-pef-clip rect").attr("width", width).attr("height", height);
+
+ d3.select("#intent-perf-x")
.attr("transform", "translate(0," + height + ")")
- .call(xAxis);
+ .call(x.axis = d3.svg.axis().scale(x).orient("bottom"));
- svg.select(".y")
- .call(yAxis);
-
- console.log('tick');
+ d3.select("#intent-perf-yl")
+ .call(d3.svg.axis().scale(y).orient("left"))
+ d3.select("#intent-perf-yr")
+ .attr("transform", "translate(" + width + " ,0)")
+ .call(d3.svg.axis().scale(y).orient("right"))
}
+
+ return {
+ start: start,
+ stop: stop,
+ resize: resize
+ };
}
- start();
+
+ function wsOpen(host, url) {
+ $log.debug('IntentPerf: web socket open - cluster node:', host, 'URL:', url);
+ // Request batch of initial data from the new server
+ wss.sendEvent('intentPerfStart');
+ }
+
+ function createAndInitGraph(d) {
+ if (!graph) {
+ d.headers.push("total");
+ graph = createGraph(d.headers);
+ }
+ graph.start();
+ }
+
+ function graphResized(dim) {
+ $log.info("Resized: " + dim.width + "x" + dim.height);
+ graph.resize(dim);
+ }
+
+ function recordSample(sample) {
+ var total = 0;
+ sample.data.forEach(function (d, i) {
+ theSample[i] = d;
+ total = total + d;
+ });
+ theSample[sample.data.length] = total;
+ }
+
+ function createHandlerMap() {
+ handlerMap = {
+ intentPerfHeaders: createAndInitGraph,
+ intentPerfSample: recordSample
+ };
+ }
+
+ //setInterval(function () { theSample = samples[++cs]; }, 5000);
+ //createGraph();
// define the controller
angular.module('ovIntentPerf', ['onosUtil'])
.controller('OvIntentPerfCtrl',
- ['$scope', '$log', 'ToolbarService', 'FlashService',
+ ['$scope', '$log', 'ToolbarService', 'WebSocketService',
+ 'ThemeService', 'FlashService', 'SvgUtilService', 'FnService',
+ 'MastService',
- function ($scope, _$log_, _tbs_, _flash_) {
- var self = this
+ function ($scope, _$log_, _tbs_, _wss_, _ts_, _flash_, _sus_, _fs_, _mast_) {
+ var self = this;
$log = _$log_;
tbs = _tbs_;
+ wss = _wss_;
+ ts = _ts_;
flash = _flash_;
+ sus = _sus_;
+ fs = _fs_;
+ mast = _mast_;
- self.message = 'Hey there dudes!';
- start();
+ createHandlerMap();
- // Clean up on destroyed scope
+ self.notifyResize = function () {
+ graphResized(fs.windowSize(mast.mastHeight()));
+ };
+
+ function start() {
+ openListener = wss.addOpenListener(wsOpen);
+ wss.bindHandlers(handlerMap);
+ wss.sendEvent('intentPerfStart');
+ $log.debug('intentPerf comms started');
+ }
+
+ function stop() {
+ graph.stop();
+ wss.sendEvent('intentPerfStop');
+ wss.unbindHandlers(handlerMap);
+ wss.removeOpenListener(openListener);
+ openListener = null;
+ graph = null;
+ $log.debug('intentPerf comms stopped');
+ }
+
+ // Cleanup on destroyed scope..
$scope.$on('$destroy', function () {
+ $log.log('OvIntentPerfCtrl is saying Buh-Bye!');
+ stop();
});
- $log.log('OvIntentPerfCtrl has been created');
- }]);
+ start();
+ }]);
}());
diff --git a/apps/test/intent-perf/src/main/resources/dev.html b/apps/test/intent-perf/src/main/resources/dev.html
index ad059df..d0b59f4 100644
--- a/apps/test/intent-perf/src/main/resources/dev.html
+++ b/apps/test/intent-perf/src/main/resources/dev.html
@@ -18,8 +18,6 @@
<head>
<title>Dev View</title>
<script src="tp/d3.min.js"></script>
- <script src="tp/jquery-2.1.1.min.js"></script>
-
<link rel="stylesheet" href="app/view/intentPerf/intentPerf.css">
</head>
<body>
diff --git a/apps/test/intent-perf/src/main/resources/sliding.html b/apps/test/intent-perf/src/main/resources/sliding.html
new file mode 100644
index 0000000..8dc501b
--- /dev/null
+++ b/apps/test/intent-perf/src/main/resources/sliding.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+
+ svg {
+ font: 10px sans-serif;
+ }
+
+ .line {
+ fill: none;
+ stroke: darkgreen;
+ stroke-width: 2px;
+ }
+
+ .axis path,
+ .axis line {
+ fill: none;
+ stroke: #999;
+ stroke-width: 2px;
+ shape-rendering: crispEdges;
+ }
+
+</style>
+<body>
+<script src="http://d3js.org/d3.v3.min.js"></script>
+<script>
+ (function () {
+ var cs = 0,
+ samples = [
+ 89.53,
+ 37515.81,
+ 104609.6,
+ 113105.11,
+ 103194.74,
+ 122151.63,
+ 128623.9,
+ 137325.33,
+ 154897.31,
+ 161235.07,
+ 162025.4,
+ 164902.64,
+ 158196.26,
+ 161072.44,
+ 160792.54,
+ 164692.44,
+ 161979.74,
+ 162137.4,
+ 159325.19,
+ 170465.44,
+ 168186.46,
+ 171152.34,
+ 168221.02,
+ 167440.73,
+ 165003.39,
+ 166855.18,
+ 157268.79,
+ 164087.54,
+ 162265.21,
+ 165990.16,
+ 176364.01,
+ 172064.07,
+ 184872.24,
+ 183249.8,
+ 182282.47,
+ 171475.11,
+ 158880.58,
+ 166016.69,
+ 168233.16,
+ 177759.92,
+ 179742.87,
+ 170819.44,
+ 167577.73,
+ 169479.9,
+ 175544.89,
+ 183792.01,
+ 184689.52,
+ 178503.87,
+ 173219.27,
+ 179085.49,
+ 179700.54,
+ 174281.17,
+ 181353.08,
+ 180173.14,
+ 184093.16,
+ 186011.5,
+ 176952.79,
+ 175319.2,
+ 169001.05,
+ 174545.12,
+ 169156.29,
+ 171804.3,
+ 159155.54,
+ 154709.96,
+ 157263.97
+ ],
+ theSample,
+ headers = [ "Whole", "Half", "Third" ];
+
+ var n = 243,
+ duration = 750,
+ now = new Date(Date.now() - duration),
+ data = [];
+
+ headers.forEach(function (d, li) {
+ data[li] = d3.range(n).map(function () { return 0; });
+ });
+
+ var margin = {top: 20, right: 100, bottom: 20, left: 100},
+ width = 960 - margin.right,
+ height = 512 - margin.top - margin.bottom;
+
+ var x = d3.time.scale()
+ .domain([now - (n - 2) * duration, now - duration])
+ .range([0, width]);
+
+ var y = d3.scale.linear()
+ .domain([0, 200000])
+ .range([height, 0]);
+
+ var svg = d3.select("body").append("p").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ svg.append("defs").append("clipPath")
+ .attr("id", "clip")
+ .append("rect")
+ .attr("width", width)
+ .attr("height", height);
+
+ var axis = svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(x.axis = d3.svg.axis().scale(x).orient("bottom"));
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(d3.svg.axis().scale(y).orient("left"));
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .attr("transform", "translate(" + width + " ,0)")
+ .call(d3.svg.axis().scale(y).orient("right"));
+
+ var lines = [], paths = [];
+ data.forEach(function (p, li) {
+ lines[li]= d3.svg.line()
+ .interpolate("basis")
+ .x(function (d, i) {
+ return x(now - (n - 1 - i) * duration);
+ })
+ .y(function (d, i) {
+ return y(d);
+ });
+
+ paths[li] = svg.append("g")
+ .attr("clip-path", "url(#clip)")
+ .append("path")
+ .datum(function () { return data[li]; })
+ .attr("id", "line" + li)
+ .attr("class", "line");
+ });
+
+ var transition = d3.select({}).transition()
+ .duration(750)
+ .ease("linear");
+
+ function tick() {
+ transition = transition.each(function () {
+ // update the domains
+ now = new Date();
+ x.domain([now - (n - 2) * duration, now - duration]);
+
+ data.forEach(function (d, li) {
+ // push the new most recent sample onto the back
+ d.push(theSample[li]);
+
+ // redraw the line and slide it left
+ paths[li].attr("d", lines[li]).attr("transform", null);
+ paths[li].transition().attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");
+
+ // pop the old data point off the front
+ d.shift();
+ });
+
+ // slide the x-axis left
+ axis.call(x.axis);
+
+ }).transition().each("start", tick);
+ }
+
+ function setSample() {
+ var v = samples[cs++];
+ theSample = [ v, v/2, v/3 ];
+ }
+
+ setSample();
+ setInterval(setSample, 1000);
+ tick();
+
+ })()
+</script>
+</body>
+</html>
diff --git a/web/gui/src/main/webapp/app/common.css b/web/gui/src/main/webapp/app/common.css
index 34f880d..8963ff5 100644
--- a/web/gui/src/main/webapp/app/common.css
+++ b/web/gui/src/main/webapp/app/common.css
@@ -21,7 +21,7 @@
/* ------ for summary-list tables ------ */
table.summary-list {
- margin: 0 50px 50px 50px;
+ margin: 0 20px 16px 12px;
font-size: 10pt;
border-spacing: 0;
}
diff --git a/web/gui/src/main/webapp/app/onos.css b/web/gui/src/main/webapp/app/onos.css
index 530c06b..b42af35 100644
--- a/web/gui/src/main/webapp/app/onos.css
+++ b/web/gui/src/main/webapp/app/onos.css
@@ -48,6 +48,10 @@
height: 100%;
}
+#view h2 {
+ padding-left: 12px;
+}
+
.light #view h2 {
color: #800;
}