blob: 76c0d03ed286c863b49b0153a3c4d01d1247d9d4 [file] [log] [blame]
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
Bri Prebilic Coleaa0f0882015-02-04 15:27:55 -080018 ONOS GUI -- Device View Module
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -080019 */
20
21(function () {
22 'use strict';
23
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070024 // injected refs
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -070025 var $log, $scope, $location, fs, mast, ps, wss, is, ns;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070026
27 // internal state
Bri Prebilic Colee568ead2015-05-01 09:51:28 -070028 var detailsPanel,
Simon Huntd766c312015-10-06 11:46:32 -070029 pStartY,
30 pHeight,
31 top,
32 bottom,
33 iconDiv,
34 wSize,
35 editingName = false;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070036
37 // constants
Bri Prebilic Cole45069382015-04-14 15:21:38 -070038 var topPdg = 13,
39 ctnrPdg = 24,
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -070040 scrollSize = 17,
Bri Prebilic Cole45069382015-04-14 15:21:38 -070041 portsTblPdg = 50,
42
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070043 pName = 'device-details-panel',
44 detailsReq = 'deviceDetailsRequest',
45 detailsResp = 'deviceDetailsResponse',
Bri Prebilic Cole45069382015-04-14 15:21:38 -070046
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070047 propOrder = [
48 'type', 'masterid', 'chassisid',
49 'mfr', 'hw', 'sw', 'protocol', 'serial'
50 ],
51 friendlyProps = [
52 'Type', 'Master ID', 'Chassis ID',
53 'Vendor', 'H/W Version', 'S/W Version', 'Protocol', 'Serial #'
54 ],
55 portCols = [
Thomas Vachuskab52a0142015-04-21 17:48:15 -070056 'enabled', 'id', 'speed', 'type', 'elinks_dest', 'name'
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070057 ],
58 friendlyPortCols = [
Thomas Vachuskab52a0142015-04-21 17:48:15 -070059 'Enabled', 'ID', 'Speed', 'Type', 'Egress Links', 'Name'
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070060 ];
61
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070062 function closePanel() {
63 if (detailsPanel.isVisible()) {
64 $scope.selId = null;
65 detailsPanel.hide();
Simon Huntd766c312015-10-06 11:46:32 -070066 return true;
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070067 }
Simon Huntd766c312015-10-06 11:46:32 -070068 return false;
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070069 }
70
Bri Prebilic Coleb699a162015-04-13 12:01:39 -070071 function addCloseBtn(div) {
Bri Prebilic Coleab582b82015-04-14 15:08:22 -070072 is.loadEmbeddedIcon(div, 'plus', 30);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -070073 div.select('g').attr('transform', 'translate(25, 0) rotate(45)');
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070074 div.on('click', closePanel);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -070075 }
76
Simon Huntd766c312015-10-06 11:46:32 -070077 function getNameSpan() {
78 return top.select('.name-div').select('.value');
79 }
80
81 function nameValid(name) {
82 // TODO: guard against empty strings etc.
83 return true;
84 }
85
86 function editNameSave() {
87 var span = getNameSpan(),
88 newVal;
89 if (editingName) {
90 newVal = span.select('input').property('value');
91
92 $log.debug("TODO: Saving name change... to '" + newVal + "'");
93 if (!nameValid(newVal)) {
94 return editNameCancel();
95 }
96
97 // TODO: send event to server to set friendly name for device
98 $scope.panelData.name = newVal;
99
100 span.html(newVal);
101 span.classed('editable', true);
102 editingName = false;
103 }
104 }
105
106 function editNameCancel() {
107 var span = getNameSpan();
108 if (editingName) {
109 $log.debug("Canceling name change...");
110 span.html($scope.panelData.name);
111 span.classed('editable', true);
112 editingName = false;
113 return true;
114 }
115 return false;
116 }
117
118 function editName() {
119 $log.log('editName() .. editing=' + editingName);
120 var span = getNameSpan();
121 if (!editingName) {
122 editingName = true;
123 span.classed('editable', false);
124 span.html('');
125 span.append('input').classed('name-input', true)
126 .attr('type', 'text')
127 .attr('value', $scope.panelData.name);
128 }
129 }
130
131 function handleEscape() {
132 return editNameCancel() || closePanel();
133 }
134
135 function setUpEditableName(top) {
136 var div = top.append('div').classed('name-div', true);
137
138 div.append('span').classed('label', true);
139 div.append('span').classed('value editable', true)
140 .on('click', editName);
141 }
142
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700143 function setUpPanel() {
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700144 var container, closeBtn, tblDiv;
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700145 detailsPanel.empty();
146
147 container = detailsPanel.append('div').classed('container', true);
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700148
149 top = container.append('div').classed('top', true);
150 closeBtn = top.append('div').classed('close-btn', true);
151 addCloseBtn(closeBtn);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700152 iconDiv = top.append('div').classed('dev-icon', true);
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700153 top.append('h2');
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700154
Simon Huntd766c312015-10-06 11:46:32 -0700155 setUpEditableName(top);
156
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700157 tblDiv = top.append('div').classed('top-tables', true);
158 tblDiv.append('div').classed('left', true).append('table');
159 tblDiv.append('div').classed('right', true).append('table');
160
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700161 top.append('hr');
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700162
163 bottom = container.append('div').classed('bottom', true);
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700164 bottom.append('h2').classed('ports-title', true).html('Ports');
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700165 bottom.append('table');
166 }
167
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700168 function addProp(tbody, index, value) {
169 var tr = tbody.append('tr');
170
171 function addCell(cls, txt) {
172 tr.append('td').attr('class', cls).html(txt);
173 }
174 addCell('label', friendlyProps[index] + ' :');
175 addCell('value', value);
176 }
177
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700178 function populateTop(tblDiv, details) {
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700179 var leftTbl = tblDiv.select('.left')
180 .select('table')
181 .append('tbody'),
182 rightTbl = tblDiv.select('.right')
183 .select('table')
184 .append('tbody');
185
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700186 is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700187 top.select('h2').html(details.id);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700188
189 propOrder.forEach(function (prop, i) {
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700190 // properties are split into two tables
191 addProp(i < 3 ? leftTbl : rightTbl, i, details[prop]);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700192 });
193 }
194
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700195 function addPortRow(tbody, port) {
196 var tr = tbody.append('tr');
197
198 portCols.forEach(function (col) {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700199 tr.append('td').html(port[col]);
200 });
201 }
202
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700203 function populateBottom(table, ports) {
204 var theader = table.append('thead').append('tr'),
205 tbody = table.append('tbody'),
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700206 tbWidth, tbHeight;
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700207
208 friendlyPortCols.forEach(function (col) {
209 theader.append('th').html(col);
210 });
211 ports.forEach(function (port) {
212 addPortRow(tbody, port);
213 });
214
215 tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700216 tbHeight = pHeight
217 - (fs.noPxStyle(detailsPanel.el()
218 .select('.top'), 'height')
219 + fs.noPxStyle(detailsPanel.el()
220 .select('.ports-title'), 'height')
221 + portsTblPdg);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700222
223 table.style({
224 height: tbHeight + 'px',
225 width: tbWidth + 'px',
226 overflow: 'auto',
227 display: 'block'
228 });
229
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700230 detailsPanel.width(tbWidth + ctnrPdg);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700231 }
232
Simon Huntd766c312015-10-06 11:46:32 -0700233 function populateName(div, name) {
234 var lab = div.select('.label'),
235 val = div.select('.value');
236 lab.html('Friendly Name:');
237 val.html(name);
238 }
239
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700240 function populateDetails(details) {
Simon Huntd766c312015-10-06 11:46:32 -0700241 var nameDiv, topTbs, btmTbl, ports;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700242 setUpPanel();
243
Simon Huntd766c312015-10-06 11:46:32 -0700244 nameDiv = top.select('.name-div');
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700245 topTbs = top.select('.top-tables');
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700246 btmTbl = bottom.select('table');
247 ports = details.ports;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700248
Simon Huntd766c312015-10-06 11:46:32 -0700249 populateName(nameDiv, details.name);
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700250 populateTop(topTbs, details);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700251 populateBottom(btmTbl, ports);
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700252
253 detailsPanel.height(pHeight);
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700254 }
255
256 function respDetailsCb(data) {
Bri Prebilic Colee568ead2015-05-01 09:51:28 -0700257 $scope.panelData = data.details;
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700258 $scope.$apply();
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700259 }
260
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700261 function createDetailsPane() {
262 detailsPanel = ps.createPanel(pName, {
263 width: wSize.width,
264 margin: 0,
265 hideMargin: 0
266 });
267 detailsPanel.el().style({
268 position: 'absolute',
269 top: pStartY + 'px'
270 });
Bri Prebilic Cole68844ba2015-07-22 15:41:37 -0700271 $scope.hidePanel = function () { detailsPanel.hide(); };
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700272 detailsPanel.hide();
273 }
274
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -0800275 angular.module('ovDevice', [])
Simon Hunta89f0f92015-02-26 16:47:12 -0800276 .controller('OvDeviceCtrl',
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700277 ['$log', '$scope', '$location', 'TableBuilderService', 'FnService',
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700278 'MastService', 'PanelService', 'WebSocketService', 'IconService',
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700279 'NavService',
Simon Hunta89f0f92015-02-26 16:47:12 -0800280
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700281 function (_$log_, _$scope_, _$location_,
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700282 tbs, _fs_, _mast_, _ps_, _wss_, _is_, _ns_) {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700283 $log = _$log_;
284 $scope = _$scope_;
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700285 $location = _$location_;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700286 fs = _fs_;
287 mast = _mast_;
288 ps = _ps_;
289 wss = _wss_;
290 is = _is_;
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700291 ns = _ns_;
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700292 var params = $location.search(),
293 handlers = {};
Bri Prebilic Cole68844ba2015-07-22 15:41:37 -0700294 $scope.panelData = {};
Bri Prebilic Coleeef67ae2015-07-01 16:26:59 -0700295 $scope.flowTip = 'Show flow view for selected device';
296 $scope.portTip = 'Show port view for selected device';
297 $scope.groupTip = 'Show group view for selected device';
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700298
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700299 // details panel handlers
300 handlers[detailsResp] = respDetailsCb;
301 wss.bindHandlers(handlers);
302
303 // query for if a certain device needs to be highlighted
304 if (params.hasOwnProperty('devId')) {
305 $scope.selId = params['devId'];
306 wss.sendEvent(detailsReq, { id: $scope.selId });
307 }
308
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700309 function selCb($event, row) {
Bri Prebilic Colebfab9c72015-06-01 14:33:18 -0700310 if ($scope.selId) {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700311 wss.sendEvent(detailsReq, { id: row.id });
312 } else {
Bri Prebilic Cole68844ba2015-07-22 15:41:37 -0700313 $scope.hidePanel();
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700314 }
315 $log.debug('Got a click on:', row);
316 }
317
Bri Prebilic Cole864cdd62015-04-02 15:46:47 -0700318 tbs.buildTable({
Bri Prebilic Cole864cdd62015-04-02 15:46:47 -0700319 scope: $scope,
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700320 tag: 'device',
321 selCb: selCb
322 });
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700323
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700324 $scope.nav = function (path) {
325 if ($scope.selId) {
326 ns.navTo(path, { devId: $scope.selId });
327 }
328 };
329
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700330 $scope.$on('$destroy', function () {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700331 wss.unbindHandlers(handlers);
Simon Hunta89f0f92015-02-26 16:47:12 -0800332 });
333
Bri Prebilic Cole72eb6db2015-03-30 16:58:53 -0700334 $log.log('OvDeviceCtrl has been created');
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700335 }])
336
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700337 .directive('deviceDetailsPanel',
338 ['$rootScope', '$window', '$timeout', 'KeyService',
339 function ($rootScope, $window, $timeout, ks) {
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700340 return function (scope) {
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700341 var unbindWatch;
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700342
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700343 function heightCalc() {
344 pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
345 + mast.mastHeight() + topPdg;
346 wSize = fs.windowSize(pStartY);
347 pHeight = wSize.height;
348 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700349
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700350 function initPanel() {
351 heightCalc();
352 createDetailsPane();
353 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700354
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700355 // Safari has a bug where it renders the fixed-layout table wrong
356 // if you ask for the window's size too early
357 if (scope.onos.browser === 'safari') {
358 $timeout(initPanel);
359 } else {
360 initPanel();
361 }
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700362 // create key bindings to handle panel
363 ks.keyBindings({
Simon Huntd766c312015-10-06 11:46:32 -0700364 enter: editNameSave,
365 esc: [handleEscape, 'Close the details panel'],
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700366 _helpFormat: ['esc']
367 });
368 ks.gestureNotes([
369 ['click', 'Select a row to show device details'],
370 ['scroll down', 'See more devices']
371 ]);
372
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700373 // if the panelData changes
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700374 scope.$watch('panelData', function () {
375 if (!fs.isEmptyObject(scope.panelData)) {
376 populateDetails(scope.panelData);
377 detailsPanel.show();
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700378 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700379 });
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700380
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700381 // if the window size changes
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700382 unbindWatch = $rootScope.$watchCollection(
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700383 function () {
384 return {
385 h: $window.innerHeight,
386 w: $window.innerWidth
387 };
388 }, function () {
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700389 if (!fs.isEmptyObject(scope.panelData)) {
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700390 heightCalc();
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700391 populateDetails(scope.panelData);
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700392 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700393 }
394 );
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700395
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700396 scope.$on('$destroy', function () {
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700397 unbindWatch();
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700398 ks.unbindKeys();
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700399 ps.destroyPanel(pName);
400 });
401 };
402 }]);
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -0800403}());