blob: cca29dbd8f4584be0721b8635ce26797fc1a41c0 [file] [log] [blame]
Simon Hunt1002cd82015-04-23 14:44:03 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Simon Hunt1002cd82015-04-23 14:44:03 -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 -- Flow View Module
19 */
20
21(function () {
22 'use strict';
23
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -070024 // injected references
Viswanath KSP7bdc9172016-10-19 20:19:17 +053025 var $log, $scope, $location, fs, tbs, ns, mast, ps, wss, is, ks;
26
27 // internal state
28 var detailsPanel,
29 pStartY,
30 pHeight,
31 top,
Viswanath KSP70e0d142016-10-28 21:58:32 +053032 topTable,
Simon Hunt8f057ee2017-07-19 14:05:26 -070033 trtDiv,
Viswanath KSPed55ecf2016-12-22 18:15:45 +053034 selDiv,
35 topSelTable,
Simon Hunt8f057ee2017-07-19 14:05:26 -070036 topTrtTable,
Viswanath KSP7bdc9172016-10-19 20:19:17 +053037 bottom,
38 iconDiv,
39 nameDiv,
40 wSize;
41
42
43 // constants
44 var topPdg = 28,
45 ctnrPdg = 24,
46 scrollSize = 17,
47 portsTblPdg = 50,
48 htPdg = 479,
49 wtPdg = 532,
50
51 pName = 'flow-details-panel',
52 detailsReq = 'flowDetailsRequest',
Viswanath KSP70e0d142016-10-28 21:58:32 +053053 detailsResp = 'flowDetailsResponse',
54
55 propOrder = [
Simon Hunt9bff5952017-07-13 14:05:09 -070056 'flowId',
57 'state',
58
59 'bytes',
60 'packets',
61 'duration',
62
63 'priority',
64 'tableId',
Simon Hunt36b658d2017-07-14 16:20:11 -070065 'appName',
Simon Hunt9bff5952017-07-13 14:05:09 -070066 'appId',
67
68 'groupId',
69 'timeout',
Steven Burrows1c2a9682017-07-14 16:52:46 +010070 'permanent',
Viswanath KSP70e0d142016-10-28 21:58:32 +053071 ],
72 friendlyProps = [
Simon Hunt9bff5952017-07-13 14:05:09 -070073 'Flow ID',
74 'State',
75
76 'Bytes',
77 'Packets',
78 'Duration',
79
80 'Flow Priority',
81 'Table ID',
Simon Hunt36b658d2017-07-14 16:20:11 -070082 'App Name',
Simon Hunt9bff5952017-07-13 14:05:09 -070083 'App ID',
84
85 'Group ID',
86 'Timeout',
Steven Burrows1c2a9682017-07-14 16:52:46 +010087 'Permanent',
Viswanath KSP70e0d142016-10-28 21:58:32 +053088 ];
Viswanath KSP7bdc9172016-10-19 20:19:17 +053089
90 function closePanel() {
91 if (detailsPanel.isVisible()) {
92 $scope.selId = null;
93 detailsPanel.hide();
94 return true;
95 }
96 return false;
97 }
98
99 function addCloseBtn(div) {
100 is.loadEmbeddedIcon(div, 'close', 20);
101 div.on('click', closePanel);
102 }
103
Viswanath KSP70e0d142016-10-28 21:58:32 +0530104 function handleEscape() {
105 return closePanel();
106 }
107
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530108 function setUpPanel() {
109 var container, closeBtn, tblDiv;
110 detailsPanel.empty();
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530111 container = detailsPanel.append('div').classed('container', true);
Simon Hunt8f057ee2017-07-19 14:05:26 -0700112
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530113 top = container.append('div').classed('top', true);
114 closeBtn = top.append('div').classed('close-btn', true);
115 addCloseBtn(closeBtn);
116 iconDiv = top.append('div').classed('dev-icon', true);
117 top.append('h2');
Viswanath KSP70e0d142016-10-28 21:58:32 +0530118 topTable = top.append('div').classed('top-content', true)
119 .append('table');
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530120 top.append('hr');
Simon Hunt9bff5952017-07-13 14:05:09 -0700121
Simon Hunt8f057ee2017-07-19 14:05:26 -0700122 selDiv = container.append('div').classed('top', true);
Simon Hunt239f09e2017-05-18 13:10:09 -0700123 selDiv.append('h2').text('Selector');
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530124 topSelTable = selDiv.append('div').classed('top-content', true)
125 .append('table');
Simon Hunt9bff5952017-07-13 14:05:09 -0700126 selDiv.append('hr');
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530127
Simon Hunt8f057ee2017-07-19 14:05:26 -0700128 trtDiv = container.append('div').classed('top', true);
129 trtDiv.append('h2').text('Treatment');
130 topTrtTable = trtDiv.append('div').classed('top-content', true)
Simon Hunt9bff5952017-07-13 14:05:09 -0700131 .append('table');
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530132 }
133
Simon Hunt8f057ee2017-07-19 14:05:26 -0700134 function addProp(tbody, label, value) {
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530135 var tr = tbody.append('tr');
136
137 function addCell(cls, txt) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700138 tr.append('td').attr('class', cls).text(txt);
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530139 }
140 addCell('label', label + ' :');
141 addCell('value', value);
142 }
143
Simon Hunt8f057ee2017-07-19 14:05:26 -0700144 // deferred fetching of user-visible strings, so that lion context is set
145 function getLionProps() {
146 // TODO: Localization... (see cluster.js for the pattern)
147 // var l = $scope.lion;
148 // return [
149 // l('flow_id'),
150 // ...
151 // ];
152 return friendlyProps;
153 }
154
155 function getLionClearDeferred() {
156 // TODO: Localization...
157 return 'Clear deferred';
158 }
159
Viswanath KSP70e0d142016-10-28 21:58:32 +0530160 function populateTop(details) {
161 is.loadEmbeddedIcon(iconDiv, 'flowTable', 40);
Simon Hunt239f09e2017-05-18 13:10:09 -0700162 top.select('h2').text(details.flowId);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530163
Simon Hunt8f057ee2017-07-19 14:05:26 -0700164 var tbody = topTable.append('tbody'),
165 tbodySel = topSelTable.append('tbody'),
166 tbodyTrt = topTrtTable.append('tbody'),
167 selArray = details.selector,
168 treat = details.treatment,
169 propLabels = getLionProps();
Viswanath KSP70e0d142016-10-28 21:58:32 +0530170
Simon Hunt8f057ee2017-07-19 14:05:26 -0700171 function addLabVal(tbody, lv) {
172 var bits = lv.match(/^([^:]*):(.*)/);
173 addProp(tbody, bits[1], bits[2]);
174 }
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530175
Simon Hunt8f057ee2017-07-19 14:05:26 -0700176 function popInstrList(items, tag) {
177 items.forEach(function (item) {
178 addLabVal(tbodyTrt, tag + item);
179 });
180 }
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530181
Simon Hunt8f057ee2017-07-19 14:05:26 -0700182 // basic flow properties
Viswanath KSP70e0d142016-10-28 21:58:32 +0530183 propOrder.forEach(function (prop, i) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700184 addProp(tbody, propLabels[i], details[prop]);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530185 });
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530186
Simon Hunt8f057ee2017-07-19 14:05:26 -0700187 // selection criteria
188 selArray.forEach(function (lv) {
189 addLabVal(tbodySel, lv);
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530190 });
191
Simon Hunt8f057ee2017-07-19 14:05:26 -0700192 // traffic treatment
193 treat.immed && popInstrList(treat.immed, '[imm]');
194 treat.defer && popInstrList(treat.defer, '[def]');
195 treat.meter && addLabVal(tbodyTrt, treat.meter);
196 treat.table && addLabVal(tbodyTrt, treat.table);
197 treat.meta && addLabVal(tbodyTrt, treat.meta);
198 addProp(tbodyTrt, getLionClearDeferred(), treat.clearDef);
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530199 }
200
201 function createDetailsPane() {
202 detailsPanel = ps.createPanel(pName, {
203 width: wSize.width,
204 margin: 0,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100205 hideMargin: 0,
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530206 });
207 detailsPanel.el().style({
208 position: 'absolute',
Steven Burrows1c2a9682017-07-14 16:52:46 +0100209 top: pStartY + 'px',
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530210 });
211 $scope.hidePanel = function () { detailsPanel.hide(); };
212 detailsPanel.hide();
213 }
214
215 function populateDetails(details) {
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530216 setUpPanel();
217 populateTop(details);
218
Steven Burrows1c2a9682017-07-14 16:52:46 +0100219 // ToDo add more details
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530220 detailsPanel.height(pHeight);
221 detailsPanel.width(wtPdg);
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530222 }
223
224 function respDetailsCb(data) {
Steven Burrows1c2a9682017-07-14 16:52:46 +0100225 $log.debug('Got response from server :', data);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530226 $scope.panelData = data.details;
227 $scope.$apply();
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530228 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700229
Simon Hunt1002cd82015-04-23 14:44:03 -0700230 angular.module('ovFlow', [])
Steven Burrows1c2a9682017-07-14 16:52:46 +0100231 .controller('OvFlowCtrl',
232 ['$log', '$scope', '$location',
233 'FnService', 'TableBuilderService', 'NavService',
234 'MastService', 'PanelService', 'KeyService', 'IconService',
235 'WebSocketService',
Simon Hunt1002cd82015-04-23 14:44:03 -0700236
Steven Burrows1c2a9682017-07-14 16:52:46 +0100237 function (_$log_, _$scope_, _$location_, _fs_, _tbs_, _ns_,
238 _mast_, _ps_, _ks_, _is_, _wss_) {
239 var params,
240 handlers = {};
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530241
Steven Burrows1c2a9682017-07-14 16:52:46 +0100242 $log = _$log_;
243 $scope = _$scope_;
244 $location = _$location_;
245 fs = _fs_;
246 tbs = _tbs_;
247 ns = _ns_;
248 is = _is_;
249 wss = _wss_;
250 mast = _mast_;
251 ps = _ps_;
252 $scope.deviceTip = 'Show device table';
253 $scope.portTip = 'Show port view for this device';
254 $scope.groupTip = 'Show group view for this device';
255 $scope.meterTip = 'Show meter view for selected device';
256 $scope.briefTip = 'Switch to brief view';
257 $scope.detailTip = 'Switch to detailed view';
258 $scope.brief = true;
259 params = $location.search();
260 if (params.hasOwnProperty('devId')) {
261 $scope.devId = params['devId'];
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530262 }
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530263
Steven Burrows1c2a9682017-07-14 16:52:46 +0100264 tbs.buildTable({
265 scope: $scope,
266 tag: 'flow',
267 selCb: selCb,
268 query: params,
269 });
270
271 $scope.nav = function (path) {
272 if ($scope.devId) {
273 ns.navTo(path, { devId: $scope.devId });
274 }
275 };
276
277 // details panel handlers
278 handlers[detailsResp] = respDetailsCb;
279 wss.bindHandlers(handlers);
280
281 function selCb($event, row) {
282 if ($scope.selId) {
283 wss.sendEvent(detailsReq, { flowId: row.id, appId: row.appId });
284 } else {
285 $scope.hidePanel();
286 }
287 $log.debug('Got a click on:', row);
288 }
289
290 $scope.$on('$destroy', function () {
291 wss.unbindHandlers(handlers);
292 });
293
294 $scope.briefToggle = function () {
295 $scope.brief = !$scope.brief;
296 };
297
298 Object.defineProperty($scope, 'queryFilter', {
299 get: function () {
300 var out = {};
301 out[$scope.queryBy || '$'] = $scope.queryTxt;
302 return out;
303 },
304 });
305
306 $log.log('OvFlowCtrl has been created');
307 }])
308
309 .directive('flowDetailsPanel',
310 ['$rootScope', '$window', '$timeout', 'KeyService',
311 function ($rootScope, $window, $timeout, ks) {
312 return function (scope) {
313 var unbindWatch;
314
315 function heightCalc() {
316 pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
317 + mast.mastHeight() + topPdg;
318 wSize = fs.windowSize(pStartY);
319 pHeight = wSize.height;
320 }
321
322 function initPanel() {
323 heightCalc();
324 createDetailsPane();
325 }
326
327 // Safari has a bug where it renders the fixed-layout table wrong
328 // if you ask for the window's size too early
329 if (scope.onos.browser === 'safari') {
330 $timeout(initPanel);
331 } else {
332 initPanel();
333 }
334 // create key bindings to handle panel
335 ks.keyBindings({
336 esc: [handleEscape, 'Close the details panel'],
337 _helpFormat: ['esc'],
338 });
339 ks.gestureNotes([
340 ['click', 'Select a row to show cluster node details'],
341 ['scroll down', 'See available cluster nodes'],
342 ]);
343 // if the panelData changes
344 scope.$watch('panelData', function () {
345 if (!fs.isEmptyObject(scope.panelData)) {
346 populateDetails(scope.panelData);
347 detailsPanel.show();
348 }
349 });
350 // if the window size changes
351 unbindWatch = $rootScope.$watchCollection(
352 function () {
353 return {
354 h: $window.innerHeight,
355 w: $window.innerWidth,
356 };
357 }, function () {
358 if (!fs.isEmptyObject(scope.panelData)) {
359 heightCalc();
360 populateDetails(scope.panelData);
361 }
362 }
363 );
364
365 scope.$on('$destroy', function () {
366 unbindWatch();
367 ps.destroyPanel(pName);
368 });
369 };
370 }]);
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530371
Simon Hunt1002cd82015-04-23 14:44:03 -0700372}());