GUI Fixes.

Change-Id: I5b5de2b74b65f1af613e04e226ee633ee50f695d
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewIntentFilter.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewIntentFilter.java
index 0f9a29b..2585b84 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewIntentFilter.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewIntentFilter.java
@@ -164,16 +164,18 @@
 
     // Indicates whether the specified intent involves the given device.
     private boolean isIntentRelevantToDevice(List<Intent> installables, Device device) {
-        for (Intent installable : installables) {
-            if (installable instanceof PathIntent) {
-                PathIntent pathIntent = (PathIntent) installable;
-                if (pathContainsDevice(pathIntent.path().links(), device.id())) {
-                    return true;
-                }
-            } else if (installable instanceof LinkCollectionIntent) {
-                LinkCollectionIntent linksIntent = (LinkCollectionIntent) installable;
-                if (pathContainsDevice(linksIntent.links(), device.id())) {
-                    return true;
+        if (installables != null) {
+            for (Intent installable : installables) {
+                if (installable instanceof PathIntent) {
+                    PathIntent pathIntent = (PathIntent) installable;
+                    if (pathContainsDevice(pathIntent.path().links(), device.id())) {
+                        return true;
+                    }
+                } else if (installable instanceof LinkCollectionIntent) {
+                    LinkCollectionIntent linksIntent = (LinkCollectionIntent) installable;
+                    if (pathContainsDevice(linksIntent.links(), device.id())) {
+                        return true;
+                    }
                 }
             }
         }
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index fd88ccb..c2deffc 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -124,7 +124,6 @@
 
 #topo svg .link {
     opacity: .7;
-    stroke-width: 1.2px;
 }
 
 #topo svg .link.inactive {
@@ -210,15 +209,17 @@
     text-align: center;
 
     /* theme specific... */
-    border: 1px solid #ddf;
-    color: #99f;
+    border: 2px solid #ddd;
+    border-radius: 4px;
+    color: #eee;
+    background: #888;
 }
 
 #topo-detail .actionBtn:hover {
     /* theme specific... */
-    border: 1px solid #ddf;
-    background: #eef;
-    color: #77d;
+    border: 2px solid #ddd;
+    color: #eee;
+    background: #444;
 }
 
 
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index aed6087..c273f81 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -741,21 +741,15 @@
 
     function showTraffic(data) {
         evTrace(data);
-        var paths = data.payload.paths;
+        var paths = data.payload.paths,
+            hasTraffic = false;
 
         // Revert any links hilighted previously.
-        link.attr('stroke-width', null)
-            .style('stroke-width', null)
+        link.style('stroke-width', null)
             .classed('primary secondary animated optical', false);
         // Remove all previous labels.
         removeLinkLabels();
 
-        if (paths.length && !antTimer) {
-            startAntTimer();
-        } else if (!paths.length && antTimer) {
-            stopAntTimer();
-        }
-
         // Now hilight all links in the paths payload, and attach
         //  labels to them, if they are defined.
         paths.forEach(function (p) {
@@ -763,15 +757,23 @@
                 i,
                 ldata;
 
+            hasTraffic = hasTraffic || p.traffic;
             for (i=0; i<n; i++) {
                 ldata = findLinkById(p.links[i]);
-                if (ldata) {
+                if (ldata && ldata.el) {
                     ldata.el.classed(p.class, true);
                     ldata.label = p.labels[i];
                 }
             }
         });
+
         updateLinks();
+
+        if (hasTraffic && !antTimer) {
+            startAntTimer();
+        } else if (!hasTraffic && antTimer) {
+            stopAntTimer();
+        }
     }
 
     // ...............................
@@ -1736,14 +1738,17 @@
 
         linkLabel.each(function (d) {
             var el = d3.select(this);
-            var lnk = findLinkById(d.key),
-                parms = {
+            var lnk = findLinkById(d.key);
+
+            if (lnk) {
+                var parms = {
                     x1: lnk.source.x,
                     y1: lnk.source.y,
                     x2: lnk.target.x,
                     y2: lnk.target.y
                 };
-            el.attr('transform', transformLabel(parms));
+                el.attr('transform', transformLabel(parms));
+            }
         });
     }
 
@@ -1973,7 +1978,7 @@
             table = detailPane.append("table"),
             tbody = table.append("tbody");
 
-        title.text('Multi-Select...');
+        title.text('Selected Nodes');
 
         selectOrder.forEach(function (d, i) {
             addProp(tbody, i+1, d);
@@ -2000,22 +2005,26 @@
             }
         });
 
-        addSingleSelectActions();
+        addSingleSelectActions(data);
     }
 
-    function addSingleSelectActions() {
+    function addSingleSelectActions(data) {
         detailPane.append('hr');
         // always want to allow 'show traffic'
-        addAction(detailPane, 'Show Traffic', showTrafficAction);
+        addAction(detailPane, 'Show Related Traffic', showTrafficAction);
+
+        if (data.type === 'switch') {
+            addAction(detailPane, 'Show Device Flows', showDeviceLinkFlowsAction);
+        }
     }
 
     function addMultiSelectActions() {
         detailPane.append('hr');
         // always want to allow 'show traffic'
-        addAction(detailPane, 'Show Traffic', showTrafficAction);
+        addAction(detailPane, 'Show Related Traffic', showTrafficAction);
         // if exactly two hosts are selected, also want 'add host intent'
         if (nSel() === 2 && allSelectionsClass('host')) {
-            addAction(detailPane, 'Add Host Intent', addIntentAction);
+            addAction(detailPane, 'Add Host-to-Host Intent', addIntentAction);
         }
     }
 
@@ -2306,13 +2315,15 @@
     }
 
     function startAntTimer() {
-        var pulses = [ 5, 3, 1.2, 3 ],
-            pulse  = 0;
-        antTimer = setInterval(function () {
-            pulse = pulse + 1;
-            pulse = pulse === pulses.length ? 0 : pulse;
-            d3.selectAll('.animated').style('stroke-width', pulses[pulse]);
-        }, 200);
+        if (!antTimer) {
+            var pulses = [5, 3, 1.2, 3],
+                pulse = 0;
+            antTimer = setInterval(function () {
+                pulse = pulse + 1;
+                pulse = pulse === pulses.length ? 0 : pulse;
+                d3.selectAll('.animated').style('stroke-width', pulses[pulse]);
+            }, 200);
+        }
     }
 
     function stopAntTimer() {