GUI -- Finished Device Details Panel.
- Cleaned up front and backend
- modified table row select callback to take the click $event (in app and device view)
- panel has device glyph
- closing panel deselects clicked on row

Change-Id: I42c372c74fd9fd417ceff01e424f754ea2559595
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java
index b7fb40d..5d79f6e 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/DeviceViewMessageHandler.java
@@ -84,11 +84,8 @@
 
         DeviceService service = get(DeviceService.class);
         MastershipService mastershipService = get(MastershipService.class);
-        LinkService linkService = get(LinkService.class);
 
-        TableRow[] rows = generateTableRows(service,
-                                            mastershipService,
-                                            linkService);
+        TableRow[] rows = generateTableRows(service, mastershipService);
         RowComparator rc =
                 new RowComparator(sortCol, RowComparator.direction(sortDir));
         Arrays.sort(rows, rc);
@@ -111,6 +108,7 @@
 
         data.put(ID, deviceId.toString());
         data.put(TYPE, device.type().toString());
+        data.put(TYPE_IID, getTypeIconId(device));
         data.put(MFR, device.manufacturer());
         data.put(HW, device.hwVersion());
         data.put(SW, device.swVersion());
@@ -131,13 +129,11 @@
     }
 
     private TableRow[] generateTableRows(DeviceService service,
-                                         MastershipService mastershipService,
-                                         LinkService linkService) {
+                                         MastershipService mastershipService) {
         List<TableRow> list = new ArrayList<>();
         for (Device dev : service.getDevices()) {
             list.add(new DeviceTableRow(service,
                                         mastershipService,
-                                        linkService,
                                         dev));
         }
         return list.toArray(new TableRow[list.size()]);
@@ -166,6 +162,10 @@
         return port;
     }
 
+    private static String getTypeIconId(Device d) {
+        return DEV_ICON_PREFIX + d.type().toString();
+    }
+
     /**
      * TableRow implementation for {@link Device devices}.
      */
@@ -180,20 +180,8 @@
         private static final String ICON_ID_ONLINE = "deviceOnline";
         private static final String ICON_ID_OFFLINE = "deviceOffline";
 
-        // TODO: use in details pane
-//        private String getEgressLinks(Set<Link> links) {
-//            String formattedString = "";
-//
-//            for (Link l : links) {
-//                formattedString += l.dst().port().toString() + ", ";
-//            }
-//            return formattedString;
-//        }
-
-        // TODO: include "extra" backend information in device details pane
         public DeviceTableRow(DeviceService service,
                               MastershipService ms,
-                              LinkService ls,
                               Device d) {
             boolean available = service.isAvailable(d.id());
             String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE;
@@ -212,10 +200,6 @@
             add(MASTER_ID, ms.getMasterFor(d.id()).toString());
         }
 
-        private String getTypeIconId(Device d) {
-            return DEV_ICON_PREFIX + d.type().toString();
-        }
-
         @Override
         protected String[] columnIds() {
             return COL_IDS;
diff --git a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
index daa0473..9a09043 100644
--- a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
+++ b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
@@ -52,9 +52,9 @@
         }
         o.scope.sortCallback = sortCb;
 
-        function selCb(sel) {
+        function selCb($event, sel) {
             o.scope.sel = (o.scope.sel === sel) ? null : sel;
-            onSel && onSel(o.scope.sel);
+            onSel && onSel($event, o.scope.sel);
         }
         o.scope.selectCallback = selCb;
 
diff --git a/web/gui/src/main/webapp/app/view/app/app.html b/web/gui/src/main/webapp/app/view/app/app.html
index c484901..e86c34c 100644
--- a/web/gui/src/main/webapp/app/view/app/app.html
+++ b/web/gui/src/main/webapp/app/view/app/app.html
@@ -31,7 +31,7 @@
             </tr>
 
             <tr ng-repeat="app in ctrl.tableData"
-                ng-click="selectCallback(app)"
+                ng-click="selectCallback($event, app)"
                 ng-class="{selected: app === sel}"
                 ng-repeat-done>
                 <td class="table-icon">
diff --git a/web/gui/src/main/webapp/app/view/app/app.js b/web/gui/src/main/webapp/app/view/app/app.js
index 666b737..1d46471 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -21,12 +21,15 @@
 (function () {
     'use strict';
 
+    var selRow;
+
     angular.module('ovApp', [])
     .controller('OvAppCtrl',
         ['$log', '$scope', 'TableBuilderService',
 
     function ($log, $scope, tbs) {
-        function selCb(row) {
+        function selCb($event, row) {
+            selRow = angular.element($event.currentTarget);
             // adjust which toolbar buttons are selected
             $log.debug('Got a click on:', row);
         }
diff --git a/web/gui/src/main/webapp/app/view/device/device.css b/web/gui/src/main/webapp/app/view/device/device.css
index 4b11f21..09b729b 100644
--- a/web/gui/src/main/webapp/app/view/device/device.css
+++ b/web/gui/src/main/webapp/app/view/device/device.css
@@ -26,10 +26,10 @@
 }
 
 .light #device-details-panel.floatpanel {
-    background-color: rgb(226, 248, 255);
+    background-color: rgb(229, 234, 237);
 }
 .dark #device-details-panel.floatpanel {
-    background-color: #444;
+    background-color: #3A4042;
 }
 
 #device-details-panel .container {
@@ -40,13 +40,29 @@
     position: absolute;
     right: 10px;
     top: 0;
+    cursor: pointer;
 }
-.close-btn svg.embeddedIcon .icon.appPlus .glyph {
-    /* works for both dark and light themes */
+.light .close-btn svg.embeddedIcon .icon.appPlus .glyph {
+    fill: #aaa;
+}
+.dark .close-btn svg.embeddedIcon .icon.appPlus .glyph {
     fill: #ccc;
 }
 
+#device-details-panel .dev-icon {
+    display: inline-block;
+    padding: 0 6px 0 0;
+    vertical-align: middle;
+}
+.light .dev-icon svg.embeddedIcon .glyph {
+    fill: rgb(0, 172, 229);
+}
+.dark .dev-icon svg.embeddedIcon .glyph {
+    fill: #486D91;
+}
+
 #device-details-panel h2 {
+    display: inline-block;
     margin: 8px 0;
 }
 
@@ -78,11 +94,11 @@
 }
 
 .light #device-details-panel .bottom th {
-    background-color: #D0E1ED;
+    background-color: #CCC;
     /* default text color */
 }
 .dark #device-details-panel .bottom th {
-    background-color: #2b2b2b;
+    background-color: #131313;
     color: #ccc;
 }
 
@@ -101,3 +117,6 @@
 .dark #device-details-panel .bottom tr:nth-child(odd) {
     background-color: #333;
 }
+.dark #device-details-panel .bottom tr:nth-child(even) {
+    background-color: #555;
+}
diff --git a/web/gui/src/main/webapp/app/view/device/device.html b/web/gui/src/main/webapp/app/view/device/device.html
index 4cc1e3d..9cfa091 100644
--- a/web/gui/src/main/webapp/app/view/device/device.html
+++ b/web/gui/src/main/webapp/app/view/device/device.html
@@ -27,7 +27,7 @@
             </tr>
 
             <tr ng-repeat="dev in ctrl.tableData"
-                ng-click="selectCallback(dev)"
+                ng-click="selectCallback($event, dev)"
                 ng-class="{selected: dev === sel}"
                 ng-repeat-done>
                 <td class="table-icon">
diff --git a/web/gui/src/main/webapp/app/view/device/device.js b/web/gui/src/main/webapp/app/view/device/device.js
index fbe5dbb..29567bc 100644
--- a/web/gui/src/main/webapp/app/view/device/device.js
+++ b/web/gui/src/main/webapp/app/view/device/device.js
@@ -26,11 +26,13 @@
 
     // internal state
     var self,
-        detailsPane,
-        container, top, bottom, closeBtn;
+        detailsPanel,
+        container, top, bottom, iconDiv,
+        selRow;
 
     // constants
     // TODO: consider having a set y height that all tables start at
+    // to make calculations easier
     var h2Pdg = 40,
         mastPdg = 8,
         tbodyPdg = 5,
@@ -53,14 +55,26 @@
             'Enabled', 'ID', 'Speed', 'Type', 'Egress Links'
         ];
 
-    function setUpPanel() {
-        detailsPane.empty();
+    function addCloseBtn(div) {
+        is.loadEmbeddedIcon(div, 'appPlus', 30);
+        div.select('g').attr('transform', 'translate(25, 0) rotate(45)');
 
-        container = detailsPane.append('div').classed('container', true);
+        div.on('click', function () {
+            detailsPanel.hide();
+            selRow.removeClass('selected');
+        });
+    }
+
+    function setUpPanel() {
+        var closeBtn;
+        detailsPanel.empty();
+
+        container = detailsPanel.append('div').classed('container', true);
 
         top = container.append('div').classed('top', true);
         closeBtn = top.append('div').classed('close-btn', true);
         addCloseBtn(closeBtn);
+        iconDiv = top.append('div').classed('dev-icon', true);
         top.append('h2');
         top.append('table');
 
@@ -76,70 +90,20 @@
             panelTop = headerHeight + tbodyPdg + mast.mastHeight() + mastPdg,
             wSize = fs.windowSize(panelTop);
 
-        detailsPane = ps.createPanel(pName, {
+        detailsPanel = ps.createPanel(pName, {
             height: wSize.height,
-            width: wSize.width / 2,
             margin: 0,
             hideMargin: 0
         });
 
-        detailsPane.el().style({
+        detailsPanel.el().style({
             position: 'absolute',
             top: panelTop + 'px'
         });
 
         setUpPanel();
 
-        detailsPane.hide();
-    }
-
-    function addCloseBtn(div) {
-        is.loadEmbeddedIcon(div, 'appPlus', 30);
-        div.select('g').attr('transform', 'translate(25, 0) rotate(45)');
-        div.on('click', function () {
-            detailsPane.hide();
-            // TODO: deselect the table row when button is clicked
-            //$scope.sel = null;
-        });
-    }
-
-    function populateTopHalf(tbody, details) {
-        top.select('h2').text(details['id']);
-
-        propOrder.forEach(function (prop, i) {
-            addProp(tbody, i, details[prop]);
-        });
-    }
-
-    function populateBottomHalf(table, ports) {
-        var theader = table.append('thead').append('tr'),
-            tbody = table.append('tbody'),
-            tbWidth, tbHeight,
-            scrollSize = 20,
-            btmPdg = 50;
-
-        friendlyPortCols.forEach(function (header) {
-            theader.append('th').html(header);
-        });
-        ports.forEach(function (port) {
-            addPortRow(tbody, port);
-        });
-
-        tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
-        tbHeight = detailsPane.height()
-                    - (fs.noPxStyle(detailsPane.el().select('.top'), 'height')
-                    + fs.noPxStyle(detailsPane.el().select('hr'), 'height')
-                    + fs.noPxStyle(detailsPane.el().select('h2'), 'height')
-                    + btmPdg);
-
-        table.style({
-            height: tbHeight + 'px',
-            width: tbWidth + 'px',
-            overflow: 'auto',
-            display: 'block'
-        });
-
-        detailsPane.width(tbWidth + cntrPdg);
+        detailsPanel.hide();
     }
 
     function addProp(tbody, index, value) {
@@ -152,6 +116,15 @@
         addCell('value', value);
     }
 
+    function populateTop(tbody, details) {
+        is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
+        top.select('h2').text(details.id);
+
+        propOrder.forEach(function (prop, i) {
+            addProp(tbody, i, details[prop]);
+        });
+    }
+
     function addPortRow(tbody, port) {
         var tr = tbody.append('tr');
 
@@ -163,21 +136,52 @@
         });
     }
 
+    function populateBottom(table, ports) {
+        var theader = table.append('thead').append('tr'),
+            tbody = table.append('tbody'),
+            tbWidth, tbHeight,
+            scrollSize = 20,
+            padding = 55;
+
+        friendlyPortCols.forEach(function (col) {
+            theader.append('th').html(col);
+        });
+        ports.forEach(function (port) {
+            addPortRow(tbody, port);
+        });
+
+        tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
+        tbHeight = detailsPanel.height()
+                    - (fs.noPxStyle(detailsPanel.el().select('.top'), 'height')
+                    + fs.noPxStyle(detailsPanel.el().select('hr'), 'height')
+                    + fs.noPxStyle(detailsPanel.el().select('h2'), 'height')
+                    + padding);
+
+        table.style({
+            height: tbHeight + 'px',
+            width: tbWidth + 'px',
+            overflow: 'auto',
+            display: 'block'
+        });
+
+        detailsPanel.width(tbWidth + cntrPdg);
+    }
+
     function populateDetails(details) {
         setUpPanel();
 
-        var toptbody = top.select('table').append('tbody'),
-            btmTable = bottom.select('table'),
+        var topTb = top.select('table').append('tbody'),
+            btmTbl = bottom.select('table'),
             ports = details.ports;
 
-        populateTopHalf(toptbody, details);
-        populateBottomHalf(btmTable, ports);
+        populateTop(topTb, details);
+        populateBottom(btmTbl, ports);
     }
 
     function respDetailsCb(data) {
-        self.panelData = data['details'];
+        self.panelData = data.details;
         populateDetails(self.panelData);
-        detailsPane.show();
+        detailsPanel.show();
     }
 
     angular.module('ovDevice', [])
@@ -197,13 +201,13 @@
             var handlers = {};
             self.panelData = [];
 
-            function selCb(row) {
-                // request the server for more information
-                // get the id from the row to request details with
+            function selCb($event, row) {
+                selRow = angular.element($event.currentTarget);
+
                 if ($scope.sel) {
                     wss.sendEvent(detailsReq, { id: row.id });
                 } else {
-                    detailsPane.hide();
+                    detailsPanel.hide();
                 }
                 $log.debug('Got a click on:', row);
             }
@@ -217,7 +221,6 @@
 
             createDetailsPane();
 
-            // bind websocket handlers
             handlers[detailsResp] = respDetailsCb;
             wss.bindHandlers(handlers);