Bri Prebilic Cole

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
...@@ -84,11 +84,8 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler ...@@ -84,11 +84,8 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler
84 84
85 DeviceService service = get(DeviceService.class); 85 DeviceService service = get(DeviceService.class);
86 MastershipService mastershipService = get(MastershipService.class); 86 MastershipService mastershipService = get(MastershipService.class);
87 - LinkService linkService = get(LinkService.class);
88 87
89 - TableRow[] rows = generateTableRows(service, 88 + TableRow[] rows = generateTableRows(service, mastershipService);
90 - mastershipService,
91 - linkService);
92 RowComparator rc = 89 RowComparator rc =
93 new RowComparator(sortCol, RowComparator.direction(sortDir)); 90 new RowComparator(sortCol, RowComparator.direction(sortDir));
94 Arrays.sort(rows, rc); 91 Arrays.sort(rows, rc);
...@@ -111,6 +108,7 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler ...@@ -111,6 +108,7 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler
111 108
112 data.put(ID, deviceId.toString()); 109 data.put(ID, deviceId.toString());
113 data.put(TYPE, device.type().toString()); 110 data.put(TYPE, device.type().toString());
111 + data.put(TYPE_IID, getTypeIconId(device));
114 data.put(MFR, device.manufacturer()); 112 data.put(MFR, device.manufacturer());
115 data.put(HW, device.hwVersion()); 113 data.put(HW, device.hwVersion());
116 data.put(SW, device.swVersion()); 114 data.put(SW, device.swVersion());
...@@ -131,13 +129,11 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler ...@@ -131,13 +129,11 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler
131 } 129 }
132 130
133 private TableRow[] generateTableRows(DeviceService service, 131 private TableRow[] generateTableRows(DeviceService service,
134 - MastershipService mastershipService, 132 + MastershipService mastershipService) {
135 - LinkService linkService) {
136 List<TableRow> list = new ArrayList<>(); 133 List<TableRow> list = new ArrayList<>();
137 for (Device dev : service.getDevices()) { 134 for (Device dev : service.getDevices()) {
138 list.add(new DeviceTableRow(service, 135 list.add(new DeviceTableRow(service,
139 mastershipService, 136 mastershipService,
140 - linkService,
141 dev)); 137 dev));
142 } 138 }
143 return list.toArray(new TableRow[list.size()]); 139 return list.toArray(new TableRow[list.size()]);
...@@ -166,6 +162,10 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler ...@@ -166,6 +162,10 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler
166 return port; 162 return port;
167 } 163 }
168 164
165 + private static String getTypeIconId(Device d) {
166 + return DEV_ICON_PREFIX + d.type().toString();
167 + }
168 +
169 /** 169 /**
170 * TableRow implementation for {@link Device devices}. 170 * TableRow implementation for {@link Device devices}.
171 */ 171 */
...@@ -180,20 +180,8 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler ...@@ -180,20 +180,8 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler
180 private static final String ICON_ID_ONLINE = "deviceOnline"; 180 private static final String ICON_ID_ONLINE = "deviceOnline";
181 private static final String ICON_ID_OFFLINE = "deviceOffline"; 181 private static final String ICON_ID_OFFLINE = "deviceOffline";
182 182
183 - // TODO: use in details pane
184 -// private String getEgressLinks(Set<Link> links) {
185 -// String formattedString = "";
186 -//
187 -// for (Link l : links) {
188 -// formattedString += l.dst().port().toString() + ", ";
189 -// }
190 -// return formattedString;
191 -// }
192 -
193 - // TODO: include "extra" backend information in device details pane
194 public DeviceTableRow(DeviceService service, 183 public DeviceTableRow(DeviceService service,
195 MastershipService ms, 184 MastershipService ms,
196 - LinkService ls,
197 Device d) { 185 Device d) {
198 boolean available = service.isAvailable(d.id()); 186 boolean available = service.isAvailable(d.id());
199 String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE; 187 String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE;
...@@ -212,10 +200,6 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler ...@@ -212,10 +200,6 @@ public class DeviceViewMessageHandler extends AbstractTabularViewMessageHandler
212 add(MASTER_ID, ms.getMasterFor(d.id()).toString()); 200 add(MASTER_ID, ms.getMasterFor(d.id()).toString());
213 } 201 }
214 202
215 - private String getTypeIconId(Device d) {
216 - return DEV_ICON_PREFIX + d.type().toString();
217 - }
218 -
219 @Override 203 @Override
220 protected String[] columnIds() { 204 protected String[] columnIds() {
221 return COL_IDS; 205 return COL_IDS;
......
...@@ -52,9 +52,9 @@ ...@@ -52,9 +52,9 @@
52 } 52 }
53 o.scope.sortCallback = sortCb; 53 o.scope.sortCallback = sortCb;
54 54
55 - function selCb(sel) { 55 + function selCb($event, sel) {
56 o.scope.sel = (o.scope.sel === sel) ? null : sel; 56 o.scope.sel = (o.scope.sel === sel) ? null : sel;
57 - onSel && onSel(o.scope.sel); 57 + onSel && onSel($event, o.scope.sel);
58 } 58 }
59 o.scope.selectCallback = selCb; 59 o.scope.selectCallback = selCb;
60 60
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
31 </tr> 31 </tr>
32 32
33 <tr ng-repeat="app in ctrl.tableData" 33 <tr ng-repeat="app in ctrl.tableData"
34 - ng-click="selectCallback(app)" 34 + ng-click="selectCallback($event, app)"
35 ng-class="{selected: app === sel}" 35 ng-class="{selected: app === sel}"
36 ng-repeat-done> 36 ng-repeat-done>
37 <td class="table-icon"> 37 <td class="table-icon">
......
...@@ -21,12 +21,15 @@ ...@@ -21,12 +21,15 @@
21 (function () { 21 (function () {
22 'use strict'; 22 'use strict';
23 23
24 + var selRow;
25 +
24 angular.module('ovApp', []) 26 angular.module('ovApp', [])
25 .controller('OvAppCtrl', 27 .controller('OvAppCtrl',
26 ['$log', '$scope', 'TableBuilderService', 28 ['$log', '$scope', 'TableBuilderService',
27 29
28 function ($log, $scope, tbs) { 30 function ($log, $scope, tbs) {
29 - function selCb(row) { 31 + function selCb($event, row) {
32 + selRow = angular.element($event.currentTarget);
30 // adjust which toolbar buttons are selected 33 // adjust which toolbar buttons are selected
31 $log.debug('Got a click on:', row); 34 $log.debug('Got a click on:', row);
32 } 35 }
......
...@@ -26,10 +26,10 @@ ...@@ -26,10 +26,10 @@
26 } 26 }
27 27
28 .light #device-details-panel.floatpanel { 28 .light #device-details-panel.floatpanel {
29 - background-color: rgb(226, 248, 255); 29 + background-color: rgb(229, 234, 237);
30 } 30 }
31 .dark #device-details-panel.floatpanel { 31 .dark #device-details-panel.floatpanel {
32 - background-color: #444; 32 + background-color: #3A4042;
33 } 33 }
34 34
35 #device-details-panel .container { 35 #device-details-panel .container {
...@@ -40,13 +40,29 @@ ...@@ -40,13 +40,29 @@
40 position: absolute; 40 position: absolute;
41 right: 10px; 41 right: 10px;
42 top: 0; 42 top: 0;
43 + cursor: pointer;
43 } 44 }
44 -.close-btn svg.embeddedIcon .icon.appPlus .glyph { 45 +.light .close-btn svg.embeddedIcon .icon.appPlus .glyph {
45 - /* works for both dark and light themes */ 46 + fill: #aaa;
47 +}
48 +.dark .close-btn svg.embeddedIcon .icon.appPlus .glyph {
46 fill: #ccc; 49 fill: #ccc;
47 } 50 }
48 51
52 +#device-details-panel .dev-icon {
53 + display: inline-block;
54 + padding: 0 6px 0 0;
55 + vertical-align: middle;
56 +}
57 +.light .dev-icon svg.embeddedIcon .glyph {
58 + fill: rgb(0, 172, 229);
59 +}
60 +.dark .dev-icon svg.embeddedIcon .glyph {
61 + fill: #486D91;
62 +}
63 +
49 #device-details-panel h2 { 64 #device-details-panel h2 {
65 + display: inline-block;
50 margin: 8px 0; 66 margin: 8px 0;
51 } 67 }
52 68
...@@ -78,11 +94,11 @@ ...@@ -78,11 +94,11 @@
78 } 94 }
79 95
80 .light #device-details-panel .bottom th { 96 .light #device-details-panel .bottom th {
81 - background-color: #D0E1ED; 97 + background-color: #CCC;
82 /* default text color */ 98 /* default text color */
83 } 99 }
84 .dark #device-details-panel .bottom th { 100 .dark #device-details-panel .bottom th {
85 - background-color: #2b2b2b; 101 + background-color: #131313;
86 color: #ccc; 102 color: #ccc;
87 } 103 }
88 104
...@@ -101,3 +117,6 @@ ...@@ -101,3 +117,6 @@
101 .dark #device-details-panel .bottom tr:nth-child(odd) { 117 .dark #device-details-panel .bottom tr:nth-child(odd) {
102 background-color: #333; 118 background-color: #333;
103 } 119 }
120 +.dark #device-details-panel .bottom tr:nth-child(even) {
121 + background-color: #555;
122 +}
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
27 </tr> 27 </tr>
28 28
29 <tr ng-repeat="dev in ctrl.tableData" 29 <tr ng-repeat="dev in ctrl.tableData"
30 - ng-click="selectCallback(dev)" 30 + ng-click="selectCallback($event, dev)"
31 ng-class="{selected: dev === sel}" 31 ng-class="{selected: dev === sel}"
32 ng-repeat-done> 32 ng-repeat-done>
33 <td class="table-icon"> 33 <td class="table-icon">
......
...@@ -26,11 +26,13 @@ ...@@ -26,11 +26,13 @@
26 26
27 // internal state 27 // internal state
28 var self, 28 var self,
29 - detailsPane, 29 + detailsPanel,
30 - container, top, bottom, closeBtn; 30 + container, top, bottom, iconDiv,
31 + selRow;
31 32
32 // constants 33 // constants
33 // TODO: consider having a set y height that all tables start at 34 // TODO: consider having a set y height that all tables start at
35 + // to make calculations easier
34 var h2Pdg = 40, 36 var h2Pdg = 40,
35 mastPdg = 8, 37 mastPdg = 8,
36 tbodyPdg = 5, 38 tbodyPdg = 5,
...@@ -53,14 +55,26 @@ ...@@ -53,14 +55,26 @@
53 'Enabled', 'ID', 'Speed', 'Type', 'Egress Links' 55 'Enabled', 'ID', 'Speed', 'Type', 'Egress Links'
54 ]; 56 ];
55 57
58 + function addCloseBtn(div) {
59 + is.loadEmbeddedIcon(div, 'appPlus', 30);
60 + div.select('g').attr('transform', 'translate(25, 0) rotate(45)');
61 +
62 + div.on('click', function () {
63 + detailsPanel.hide();
64 + selRow.removeClass('selected');
65 + });
66 + }
67 +
56 function setUpPanel() { 68 function setUpPanel() {
57 - detailsPane.empty(); 69 + var closeBtn;
70 + detailsPanel.empty();
58 71
59 - container = detailsPane.append('div').classed('container', true); 72 + container = detailsPanel.append('div').classed('container', true);
60 73
61 top = container.append('div').classed('top', true); 74 top = container.append('div').classed('top', true);
62 closeBtn = top.append('div').classed('close-btn', true); 75 closeBtn = top.append('div').classed('close-btn', true);
63 addCloseBtn(closeBtn); 76 addCloseBtn(closeBtn);
77 + iconDiv = top.append('div').classed('dev-icon', true);
64 top.append('h2'); 78 top.append('h2');
65 top.append('table'); 79 top.append('table');
66 80
...@@ -76,61 +90,72 @@ ...@@ -76,61 +90,72 @@
76 panelTop = headerHeight + tbodyPdg + mast.mastHeight() + mastPdg, 90 panelTop = headerHeight + tbodyPdg + mast.mastHeight() + mastPdg,
77 wSize = fs.windowSize(panelTop); 91 wSize = fs.windowSize(panelTop);
78 92
79 - detailsPane = ps.createPanel(pName, { 93 + detailsPanel = ps.createPanel(pName, {
80 height: wSize.height, 94 height: wSize.height,
81 - width: wSize.width / 2,
82 margin: 0, 95 margin: 0,
83 hideMargin: 0 96 hideMargin: 0
84 }); 97 });
85 98
86 - detailsPane.el().style({ 99 + detailsPanel.el().style({
87 position: 'absolute', 100 position: 'absolute',
88 top: panelTop + 'px' 101 top: panelTop + 'px'
89 }); 102 });
90 103
91 setUpPanel(); 104 setUpPanel();
92 105
93 - detailsPane.hide(); 106 + detailsPanel.hide();
94 } 107 }
95 108
96 - function addCloseBtn(div) { 109 + function addProp(tbody, index, value) {
97 - is.loadEmbeddedIcon(div, 'appPlus', 30); 110 + var tr = tbody.append('tr');
98 - div.select('g').attr('transform', 'translate(25, 0) rotate(45)'); 111 +
99 - div.on('click', function () { 112 + function addCell(cls, txt) {
100 - detailsPane.hide(); 113 + tr.append('td').attr('class', cls).html(txt);
101 - // TODO: deselect the table row when button is clicked 114 + }
102 - //$scope.sel = null; 115 + addCell('label', friendlyProps[index] + ' :');
103 - }); 116 + addCell('value', value);
104 } 117 }
105 118
106 - function populateTopHalf(tbody, details) { 119 + function populateTop(tbody, details) {
107 - top.select('h2').text(details['id']); 120 + is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
121 + top.select('h2').text(details.id);
108 122
109 propOrder.forEach(function (prop, i) { 123 propOrder.forEach(function (prop, i) {
110 addProp(tbody, i, details[prop]); 124 addProp(tbody, i, details[prop]);
111 }); 125 });
112 } 126 }
113 127
114 - function populateBottomHalf(table, ports) { 128 + function addPortRow(tbody, port) {
129 + var tr = tbody.append('tr');
130 +
131 + portCols.forEach(function (col) {
132 + if (col === 'type' || col === 'id') {
133 + port[col] = fs.cap(port[col]);
134 + }
135 + tr.append('td').html(port[col]);
136 + });
137 + }
138 +
139 + function populateBottom(table, ports) {
115 var theader = table.append('thead').append('tr'), 140 var theader = table.append('thead').append('tr'),
116 tbody = table.append('tbody'), 141 tbody = table.append('tbody'),
117 tbWidth, tbHeight, 142 tbWidth, tbHeight,
118 scrollSize = 20, 143 scrollSize = 20,
119 - btmPdg = 50; 144 + padding = 55;
120 145
121 - friendlyPortCols.forEach(function (header) { 146 + friendlyPortCols.forEach(function (col) {
122 - theader.append('th').html(header); 147 + theader.append('th').html(col);
123 }); 148 });
124 ports.forEach(function (port) { 149 ports.forEach(function (port) {
125 addPortRow(tbody, port); 150 addPortRow(tbody, port);
126 }); 151 });
127 152
128 tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize; 153 tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
129 - tbHeight = detailsPane.height() 154 + tbHeight = detailsPanel.height()
130 - - (fs.noPxStyle(detailsPane.el().select('.top'), 'height') 155 + - (fs.noPxStyle(detailsPanel.el().select('.top'), 'height')
131 - + fs.noPxStyle(detailsPane.el().select('hr'), 'height') 156 + + fs.noPxStyle(detailsPanel.el().select('hr'), 'height')
132 - + fs.noPxStyle(detailsPane.el().select('h2'), 'height') 157 + + fs.noPxStyle(detailsPanel.el().select('h2'), 'height')
133 - + btmPdg); 158 + + padding);
134 159
135 table.style({ 160 table.style({
136 height: tbHeight + 'px', 161 height: tbHeight + 'px',
...@@ -139,45 +164,24 @@ ...@@ -139,45 +164,24 @@
139 display: 'block' 164 display: 'block'
140 }); 165 });
141 166
142 - detailsPane.width(tbWidth + cntrPdg); 167 + detailsPanel.width(tbWidth + cntrPdg);
143 - }
144 -
145 - function addProp(tbody, index, value) {
146 - var tr = tbody.append('tr');
147 -
148 - function addCell(cls, txt) {
149 - tr.append('td').attr('class', cls).html(txt);
150 - }
151 - addCell('label', friendlyProps[index] + ' :');
152 - addCell('value', value);
153 - }
154 -
155 - function addPortRow(tbody, port) {
156 - var tr = tbody.append('tr');
157 -
158 - portCols.forEach(function (col) {
159 - if (col === 'type' || col === 'id') {
160 - port[col] = fs.cap(port[col]);
161 - }
162 - tr.append('td').html(port[col]);
163 - });
164 } 168 }
165 169
166 function populateDetails(details) { 170 function populateDetails(details) {
167 setUpPanel(); 171 setUpPanel();
168 172
169 - var toptbody = top.select('table').append('tbody'), 173 + var topTb = top.select('table').append('tbody'),
170 - btmTable = bottom.select('table'), 174 + btmTbl = bottom.select('table'),
171 ports = details.ports; 175 ports = details.ports;
172 176
173 - populateTopHalf(toptbody, details); 177 + populateTop(topTb, details);
174 - populateBottomHalf(btmTable, ports); 178 + populateBottom(btmTbl, ports);
175 } 179 }
176 180
177 function respDetailsCb(data) { 181 function respDetailsCb(data) {
178 - self.panelData = data['details']; 182 + self.panelData = data.details;
179 populateDetails(self.panelData); 183 populateDetails(self.panelData);
180 - detailsPane.show(); 184 + detailsPanel.show();
181 } 185 }
182 186
183 angular.module('ovDevice', []) 187 angular.module('ovDevice', [])
...@@ -197,13 +201,13 @@ ...@@ -197,13 +201,13 @@
197 var handlers = {}; 201 var handlers = {};
198 self.panelData = []; 202 self.panelData = [];
199 203
200 - function selCb(row) { 204 + function selCb($event, row) {
201 - // request the server for more information 205 + selRow = angular.element($event.currentTarget);
202 - // get the id from the row to request details with 206 +
203 if ($scope.sel) { 207 if ($scope.sel) {
204 wss.sendEvent(detailsReq, { id: row.id }); 208 wss.sendEvent(detailsReq, { id: row.id });
205 } else { 209 } else {
206 - detailsPane.hide(); 210 + detailsPanel.hide();
207 } 211 }
208 $log.debug('Got a click on:', row); 212 $log.debug('Got a click on:', row);
209 } 213 }
...@@ -217,7 +221,6 @@ ...@@ -217,7 +221,6 @@
217 221
218 createDetailsPane(); 222 createDetailsPane();
219 223
220 - // bind websocket handlers
221 handlers[detailsResp] = respDetailsCb; 224 handlers[detailsResp] = respDetailsCb;
222 wss.bindHandlers(handlers); 225 wss.bindHandlers(handlers);
223 226
......