blob: 4e8153c32a42517fea74b5611ec43ce48e790384 [file] [log] [blame]
Thomas Vachuskae586b792015-03-26 13:59:38 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuskae586b792015-03-26 13:59:38 -07003 *
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/*
18 ONOS GUI -- Host View Module
19 */
20
21(function () {
22 'use strict';
23
Simon Hunte408af72017-06-14 18:32:06 -070024 // injected refs
25 var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks;
26
27 // internal state
28 var detailsPanel,
29 pStartY,
30 pHeight,
31 top,
Simon Hunte408af72017-06-14 18:32:06 -070032 iconDiv,
33 wSize,
34 editingName = false,
35 host;
36
37 // constants
38 var topPdg = 28,
Simon Hunte408af72017-06-14 18:32:06 -070039 pName = 'host-details-panel',
40 detailsReq = 'hostDetailsRequest',
41 detailsResp = 'hostDetailsResponse',
42 nameChangeReq = 'hostNameChangeRequest',
43 nameChangeResp = 'hostNameChangeResponse';
44
Simon Hunt10618f62017-06-15 19:30:52 -070045 var propOrder = [
46 'id', 'ip', 'mac', 'vlan', 'configured', 'location'
47 ],
48 friendlyProps = [
49 'Host ID', 'IP Address', 'MAC Address', 'VLAN',
50 'Configured', 'Location'
51 ];
Simon Hunte408af72017-06-14 18:32:06 -070052
53 function closePanel() {
54 if (detailsPanel.isVisible()) {
55 $scope.selId = null;
56 detailsPanel.hide();
57 return true;
58 }
59 return false;
60 }
61
62 function addCloseBtn(div) {
63 is.loadEmbeddedIcon(div, 'close', 20);
64 div.on('click', closePanel);
65 }
66
67 function exitEditMode(nameH2, name) {
68 nameH2.text(name);
69 nameH2.classed('editable clickable', true);
70 editingName = false;
71 ks.enableGlobalKeys(true);
72 }
73
74 function editNameSave() {
75 var nameH2 = top.select('h2'),
76 id = $scope.panelData.id,
Simon Hunt10618f62017-06-15 19:30:52 -070077 ip = $scope.panelData.ip,
Simon Hunte408af72017-06-14 18:32:06 -070078 val,
79 newVal;
80
81 if (editingName) {
82 val = nameH2.select('input').property('value').trim();
Simon Hunt10618f62017-06-15 19:30:52 -070083 newVal = val || ip;
Simon Hunte408af72017-06-14 18:32:06 -070084
85 exitEditMode(nameH2, newVal);
86 $scope.panelData.name = newVal;
87 wss.sendEvent(nameChangeReq, { id: id, name: val });
88 }
89 }
90
91 function editNameCancel() {
92 if (editingName) {
93 exitEditMode(top.select('h2'), $scope.panelData.name);
94 return true;
95 }
96 return false;
97 }
98
99 function editName() {
100 var nameH2 = top.select('h2'),
101 tf, el;
102
103 if (!editingName) {
104 nameH2.classed('editable clickable', false);
105 nameH2.text('');
106 tf = nameH2.append('input').classed('name-input', true)
107 .attr('type', 'text')
108 .attr('value', $scope.panelData.name);
109 el = tf[0][0];
110 el.focus();
111 el.select();
112 editingName = true;
113 ks.enableGlobalKeys(false);
114 }
115 }
116
117 function handleEscape() {
118 return editNameCancel() || closePanel();
119 }
120
121 function setUpPanel() {
Simon Hunt10618f62017-06-15 19:30:52 -0700122 var container, closeBtn;
Simon Hunte408af72017-06-14 18:32:06 -0700123 detailsPanel.empty();
124
125 container = detailsPanel.append('div').classed('container', true);
126
127 top = container.append('div').classed('top', true);
128 closeBtn = top.append('div').classed('close-btn', true);
129 addCloseBtn(closeBtn);
130 iconDiv = top.append('div').classed('host-icon', true);
131 top.append('h2').classed('editable clickable', true).on('click', editName);
132
Simon Hunt10618f62017-06-15 19:30:52 -0700133 top.append('div').classed('top-tables', true);
Simon Hunte408af72017-06-14 18:32:06 -0700134 top.append('hr');
Simon Hunt10618f62017-06-15 19:30:52 -0700135 }
Simon Hunte408af72017-06-14 18:32:06 -0700136
Simon Hunt10618f62017-06-15 19:30:52 -0700137 function addProp(tbody, index, value) {
138 var tr = tbody.append('tr');
139
140 function addCell(cls, txt) {
141 tr.append('td').attr('class', cls).text(txt);
142 }
143 addCell('label', friendlyProps[index] + ' :');
144 addCell('value', value);
Simon Hunte408af72017-06-14 18:32:06 -0700145 }
146
147 function populateTop(details) {
Simon Hunt10618f62017-06-15 19:30:52 -0700148 var tab = top.select('.top-tables').append('tbody');
149
Simon Hunte408af72017-06-14 18:32:06 -0700150 is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
151 top.select('h2').text(details.name);
152
Simon Hunt10618f62017-06-15 19:30:52 -0700153 propOrder.forEach(function (prop, i) {
154 addProp(tab, i, details[prop]);
155 });
Simon Hunte408af72017-06-14 18:32:06 -0700156 }
157
158 function populateDetails(details) {
159 setUpPanel();
160 populateTop(details);
161 detailsPanel.height(pHeight);
Simon Hunt86943082017-06-15 13:18:42 -0700162 // configure width based on content.. for now hardcoded
Simon Hunt10618f62017-06-15 19:30:52 -0700163 detailsPanel.width(400);
Simon Hunte408af72017-06-14 18:32:06 -0700164 }
165
166 function respDetailsCb(data) {
167 $scope.panelData = data.details;
168 host = data.host;
169 $scope.$apply();
170 }
171
172 function respNameCb(data) {
173 if (data.warn) {
174 $log.warn(data.warn, data.id);
175 top.select('h2').text(data.id);
176 }
177 }
178
179 function createDetailsPane() {
180 detailsPanel = ps.createPanel(pName, {
181 width: wSize.width,
182 margin: 0,
183 hideMargin: 0
184 });
185 detailsPanel.el().style({
186 position: 'absolute',
187 top: pStartY + 'px'
188 });
189 $scope.hidePanel = function () { detailsPanel.hide(); };
190 detailsPanel.hide();
191 }
192
193
194 // Defines the Host View controller...
Thomas Vachuskae586b792015-03-26 13:59:38 -0700195 angular.module('ovHost', [])
196 .controller('OvHostCtrl',
Simon Hunte408af72017-06-14 18:32:06 -0700197 ['$log', '$scope',
198 '$location',
199 'TableBuilderService',
200 'FnService', 'MastService', 'PanelService', 'WebSocketService',
201 'IconService', 'NavService', 'KeyService',
Thomas Vachuskae586b792015-03-26 13:59:38 -0700202
Simon Hunte408af72017-06-14 18:32:06 -0700203 function (_$log_, _$scope_, _$location_,
204 tbs,
205 _fs_, _mast_, _ps_, _wss_,
206 _is_, _ns_, _ks_) {
207
208 var params,
209 handlers = {};
210
211 $log = _$log_;
212 $scope = _$scope_;
213 $loc = _$location_;
214 fs = _fs_;
215 mast = _mast_;
216 ps = _ps_;
217 wss = _wss_;
218 is = _is_;
219 ns = _ns_;
220 ks = _ks_;
221
222 params = $loc.search();
223
224 $scope.panelData = {};
225
226 // details panel handlers
227 handlers[detailsResp] = respDetailsCb;
228 handlers[nameChangeResp] = respNameCb;
229 wss.bindHandlers(handlers);
230
231 // query for if a certain host needs to be highlighted
232 if (params.hasOwnProperty('hostId')) {
233 $scope.selId = params['hostId'];
234 wss.sendEvent(detailsReq, { id: $scope.selId });
235 }
236
237 function selCb($event, row) {
238 if ($scope.selId) {
239 wss.sendEvent(detailsReq, { id: row.id });
240 } else {
241 $scope.hidePanel();
242 }
243 $log.debug('Got a click on:', row);
244 }
245
Bri Prebilic Cole864cdd62015-04-02 15:46:47 -0700246 tbs.buildTable({
Bri Prebilic Cole864cdd62015-04-02 15:46:47 -0700247 scope: $scope,
Simon Hunte408af72017-06-14 18:32:06 -0700248 tag: 'host',
249 selCb: selCb
250 });
251
252 $scope.nav = function (path) {
253 if ($scope.selId) {
254 ns.navTo(path, { hostId: $scope.selId });
255 }
256 };
257
258 $scope.$on('$destroy', function () {
259 wss.unbindHandlers(handlers);
Thomas Vachuskae586b792015-03-26 13:59:38 -0700260 });
Bri Prebilic Cole3d4d01c2015-04-30 13:48:36 -0700261
Bri Prebilic Cole19a32dd2015-03-26 18:00:03 -0700262 $log.log('OvHostCtrl has been created');
Simon Hunte408af72017-06-14 18:32:06 -0700263 }])
264
265 .directive('hostDetailsPanel',
266 ['$rootScope', '$window', '$timeout', 'KeyService',
267 function ($rootScope, $window, $timeout, ks) {
268 return function (scope) {
269 var unbindWatch;
270
271 function heightCalc() {
272 pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
273 + mast.mastHeight() + topPdg;
274 wSize = fs.windowSize(pStartY);
275 pHeight = wSize.height;
276 }
277
278 function initPanel() {
279 heightCalc();
280 createDetailsPane();
281 }
282
283 // Safari has a bug where it renders the fixed-layout table wrong
284 // if you ask for the window's size too early
285 if (scope.onos.browser === 'safari') {
286 $timeout(initPanel);
287 } else {
288 initPanel();
289 }
290 // create key bindings to handle panel
291 ks.keyBindings({
292 enter: editNameSave,
293 esc: [handleEscape, 'Close the details panel'],
294 _helpFormat: ['esc']
295 });
296 ks.gestureNotes([
297 ['click', 'Select a row to show device details'],
298 ['scroll down', 'See more devices']
299 ]);
300
301 // if the panelData changes
302 scope.$watch('panelData', function () {
303 if (!fs.isEmptyObject(scope.panelData)) {
304 populateDetails(scope.panelData);
305 detailsPanel.show();
306 }
307 });
308
309 // if the window size changes
310 unbindWatch = $rootScope.$watchCollection(
311 function () {
312 return {
313 h: $window.innerHeight,
314 w: $window.innerWidth
315 };
316 }, function () {
317 if (!fs.isEmptyObject(scope.panelData)) {
318 heightCalc();
319 populateDetails(scope.panelData);
320 }
321 }
322 );
323
324 scope.$on('$destroy', function () {
325 unbindWatch();
326 ks.unbindKeys();
327 ps.destroyPanel(pName);
328 });
329 };
330 }]);
Thomas Vachuskae586b792015-03-26 13:59:38 -0700331}());