blob: 71794bd14bb99d975138ed0e6daddab4e3e75ce7 [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
Simon Huntcaed0412017-08-12 13:49:17 -070025 var $log, $scope, $location, fs, tbs, ns, mast, ps, wss, is;
Viswanath KSP7bdc9172016-10-19 20:19:17 +053026
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 iconDiv,
Viswanath KSP7bdc9172016-10-19 20:19:17 +053038 wSize;
39
Viswanath KSP7bdc9172016-10-19 20:19:17 +053040 // constants
41 var topPdg = 28,
Viswanath KSP7bdc9172016-10-19 20:19:17 +053042 wtPdg = 532,
43
44 pName = 'flow-details-panel',
45 detailsReq = 'flowDetailsRequest',
Viswanath KSP70e0d142016-10-28 21:58:32 +053046 detailsResp = 'flowDetailsResponse',
47
48 propOrder = [
Simon Hunt9bff5952017-07-13 14:05:09 -070049 'flowId',
50 'state',
51
52 'bytes',
53 'packets',
54 'duration',
55
56 'priority',
Yi Tseng18177a52017-09-08 01:26:59 -070057 'tableName',
Simon Hunt36b658d2017-07-14 16:20:11 -070058 'appName',
Simon Hunt9bff5952017-07-13 14:05:09 -070059 'appId',
60
61 'groupId',
62 'timeout',
Steven Burrows1c2a9682017-07-14 16:52:46 +010063 'permanent',
Viswanath KSP70e0d142016-10-28 21:58:32 +053064 ],
65 friendlyProps = [
Simon Hunt9bff5952017-07-13 14:05:09 -070066 'Flow ID',
67 'State',
68
69 'Bytes',
70 'Packets',
71 'Duration',
72
73 'Flow Priority',
Yi Tseng18177a52017-09-08 01:26:59 -070074 'Table Name',
Simon Hunt36b658d2017-07-14 16:20:11 -070075 'App Name',
Simon Hunt9bff5952017-07-13 14:05:09 -070076 'App ID',
77
78 'Group ID',
79 'Timeout',
Steven Burrows1c2a9682017-07-14 16:52:46 +010080 'Permanent',
Viswanath KSP70e0d142016-10-28 21:58:32 +053081 ];
Viswanath KSP7bdc9172016-10-19 20:19:17 +053082
83 function closePanel() {
84 if (detailsPanel.isVisible()) {
85 $scope.selId = null;
86 detailsPanel.hide();
87 return true;
88 }
89 return false;
90 }
91
92 function addCloseBtn(div) {
93 is.loadEmbeddedIcon(div, 'close', 20);
94 div.on('click', closePanel);
95 }
96
Viswanath KSP70e0d142016-10-28 21:58:32 +053097 function handleEscape() {
98 return closePanel();
99 }
100
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530101 function setUpPanel() {
Simon Huntcaed0412017-08-12 13:49:17 -0700102 var container, closeBtn;
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530103 detailsPanel.empty();
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530104 container = detailsPanel.append('div').classed('container', true);
Simon Hunt8f057ee2017-07-19 14:05:26 -0700105
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530106 top = container.append('div').classed('top', true);
107 closeBtn = top.append('div').classed('close-btn', true);
108 addCloseBtn(closeBtn);
109 iconDiv = top.append('div').classed('dev-icon', true);
110 top.append('h2');
Viswanath KSP70e0d142016-10-28 21:58:32 +0530111 topTable = top.append('div').classed('top-content', true)
112 .append('table');
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530113 top.append('hr');
Simon Hunt9bff5952017-07-13 14:05:09 -0700114
Simon Hunt8f057ee2017-07-19 14:05:26 -0700115 selDiv = container.append('div').classed('top', true);
Simon Hunt239f09e2017-05-18 13:10:09 -0700116 selDiv.append('h2').text('Selector');
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530117 topSelTable = selDiv.append('div').classed('top-content', true)
118 .append('table');
Simon Hunt9bff5952017-07-13 14:05:09 -0700119 selDiv.append('hr');
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530120
Simon Hunt8f057ee2017-07-19 14:05:26 -0700121 trtDiv = container.append('div').classed('top', true);
122 trtDiv.append('h2').text('Treatment');
123 topTrtTable = trtDiv.append('div').classed('top-content', true)
Simon Hunt9bff5952017-07-13 14:05:09 -0700124 .append('table');
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530125 }
126
Simon Hunt8f057ee2017-07-19 14:05:26 -0700127 function addProp(tbody, label, value) {
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530128 var tr = tbody.append('tr');
129
130 function addCell(cls, txt) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700131 tr.append('td').attr('class', cls).text(txt);
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530132 }
133 addCell('label', label + ' :');
134 addCell('value', value);
135 }
136
Simon Hunt8f057ee2017-07-19 14:05:26 -0700137 // deferred fetching of user-visible strings, so that lion context is set
138 function getLionProps() {
139 // TODO: Localization... (see cluster.js for the pattern)
140 // var l = $scope.lion;
141 // return [
142 // l('flow_id'),
143 // ...
144 // ];
145 return friendlyProps;
146 }
147
148 function getLionClearDeferred() {
149 // TODO: Localization...
150 return 'Clear deferred';
151 }
152
Viswanath KSP70e0d142016-10-28 21:58:32 +0530153 function populateTop(details) {
154 is.loadEmbeddedIcon(iconDiv, 'flowTable', 40);
Simon Hunt239f09e2017-05-18 13:10:09 -0700155 top.select('h2').text(details.flowId);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530156
Simon Hunt8f057ee2017-07-19 14:05:26 -0700157 var tbody = topTable.append('tbody'),
158 tbodySel = topSelTable.append('tbody'),
159 tbodyTrt = topTrtTable.append('tbody'),
160 selArray = details.selector,
161 treat = details.treatment,
162 propLabels = getLionProps();
Viswanath KSP70e0d142016-10-28 21:58:32 +0530163
Simon Hunt8f057ee2017-07-19 14:05:26 -0700164 function addLabVal(tbody, lv) {
165 var bits = lv.match(/^([^:]*):(.*)/);
166 addProp(tbody, bits[1], bits[2]);
167 }
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530168
Simon Hunt8f057ee2017-07-19 14:05:26 -0700169 function popInstrList(items, tag) {
170 items.forEach(function (item) {
171 addLabVal(tbodyTrt, tag + item);
172 });
173 }
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530174
Simon Hunt8f057ee2017-07-19 14:05:26 -0700175 // basic flow properties
Viswanath KSP70e0d142016-10-28 21:58:32 +0530176 propOrder.forEach(function (prop, i) {
Simon Hunt8f057ee2017-07-19 14:05:26 -0700177 addProp(tbody, propLabels[i], details[prop]);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530178 });
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530179
Simon Hunt8f057ee2017-07-19 14:05:26 -0700180 // selection criteria
181 selArray.forEach(function (lv) {
182 addLabVal(tbodySel, lv);
Viswanath KSPed55ecf2016-12-22 18:15:45 +0530183 });
184
Simon Hunt8f057ee2017-07-19 14:05:26 -0700185 // traffic treatment
186 treat.immed && popInstrList(treat.immed, '[imm]');
187 treat.defer && popInstrList(treat.defer, '[def]');
188 treat.meter && addLabVal(tbodyTrt, treat.meter);
189 treat.table && addLabVal(tbodyTrt, treat.table);
190 treat.meta && addLabVal(tbodyTrt, treat.meta);
191 addProp(tbodyTrt, getLionClearDeferred(), treat.clearDef);
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530192 }
193
194 function createDetailsPane() {
195 detailsPanel = ps.createPanel(pName, {
196 width: wSize.width,
197 margin: 0,
Steven Burrows1c2a9682017-07-14 16:52:46 +0100198 hideMargin: 0,
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530199 });
200 detailsPanel.el().style({
201 position: 'absolute',
Steven Burrows1c2a9682017-07-14 16:52:46 +0100202 top: pStartY + 'px',
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530203 });
204 $scope.hidePanel = function () { detailsPanel.hide(); };
205 detailsPanel.hide();
206 }
207
208 function populateDetails(details) {
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530209 setUpPanel();
210 populateTop(details);
211
Steven Burrows1c2a9682017-07-14 16:52:46 +0100212 // ToDo add more details
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530213 detailsPanel.height(pHeight);
214 detailsPanel.width(wtPdg);
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530215 }
216
217 function respDetailsCb(data) {
Steven Burrows1c2a9682017-07-14 16:52:46 +0100218 $log.debug('Got response from server :', data);
Viswanath KSP70e0d142016-10-28 21:58:32 +0530219 $scope.panelData = data.details;
220 $scope.$apply();
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530221 }
Bri Prebilic Colecdc188d2015-04-24 16:40:11 -0700222
Simon Hunt1002cd82015-04-23 14:44:03 -0700223 angular.module('ovFlow', [])
Steven Burrows1c2a9682017-07-14 16:52:46 +0100224 .controller('OvFlowCtrl',
225 ['$log', '$scope', '$location',
226 'FnService', 'TableBuilderService', 'NavService',
227 'MastService', 'PanelService', 'KeyService', 'IconService',
228 'WebSocketService',
Simon Hunt1002cd82015-04-23 14:44:03 -0700229
Steven Burrows1c2a9682017-07-14 16:52:46 +0100230 function (_$log_, _$scope_, _$location_, _fs_, _tbs_, _ns_,
231 _mast_, _ps_, _ks_, _is_, _wss_) {
232 var params,
233 handlers = {};
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530234
Steven Burrows1c2a9682017-07-14 16:52:46 +0100235 $log = _$log_;
236 $scope = _$scope_;
237 $location = _$location_;
238 fs = _fs_;
239 tbs = _tbs_;
240 ns = _ns_;
241 is = _is_;
242 wss = _wss_;
243 mast = _mast_;
244 ps = _ps_;
245 $scope.deviceTip = 'Show device table';
246 $scope.portTip = 'Show port view for this device';
247 $scope.groupTip = 'Show group view for this device';
248 $scope.meterTip = 'Show meter view for selected device';
Yi Tsenga87b40c2017-09-10 00:59:03 -0700249 $scope.pipeconfTip = 'Show pipeconf view for selected device';
Steven Burrows1c2a9682017-07-14 16:52:46 +0100250 $scope.briefTip = 'Switch to brief view';
251 $scope.detailTip = 'Switch to detailed view';
Yi Tsenga87b40c2017-09-10 00:59:03 -0700252
Steven Burrows1c2a9682017-07-14 16:52:46 +0100253 $scope.brief = true;
254 params = $location.search();
255 if (params.hasOwnProperty('devId')) {
256 $scope.devId = params['devId'];
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530257 }
Viswanath KSP7bdc9172016-10-19 20:19:17 +0530258
Steven Burrows1c2a9682017-07-14 16:52:46 +0100259 tbs.buildTable({
260 scope: $scope,
261 tag: 'flow',
262 selCb: selCb,
263 query: params,
264 });
265
266 $scope.nav = function (path) {
267 if ($scope.devId) {
268 ns.navTo(path, { devId: $scope.devId });
269 }
270 };
271
272 // details panel handlers
273 handlers[detailsResp] = respDetailsCb;
274 wss.bindHandlers(handlers);
275
276 function selCb($event, row) {
277 if ($scope.selId) {
Simon Huntf257a962017-08-25 18:58:47 -0700278 wss.sendEvent(detailsReq, {
279 flowId: row.id,
280 appId: row.appId
281 });
Steven Burrows1c2a9682017-07-14 16:52:46 +0100282 } else {
283 $scope.hidePanel();
284 }
285 $log.debug('Got a click on:', row);
286 }
287
288 $scope.$on('$destroy', function () {
289 wss.unbindHandlers(handlers);
290 });
291
292 $scope.briefToggle = function () {
293 $scope.brief = !$scope.brief;
294 };
295
296 Object.defineProperty($scope, 'queryFilter', {
297 get: function () {
298 var out = {};
299 out[$scope.queryBy || '$'] = $scope.queryTxt;
300 return out;
301 },
302 });
303
304 $log.log('OvFlowCtrl has been created');
305 }])
306
307 .directive('flowDetailsPanel',
308 ['$rootScope', '$window', '$timeout', 'KeyService',
Simon Huntf257a962017-08-25 18:58:47 -0700309 function ($rootScope, $window, $timeout, ks) {
310 return function (scope) {
311 var unbindWatch;
Steven Burrows1c2a9682017-07-14 16:52:46 +0100312
Simon Huntf257a962017-08-25 18:58:47 -0700313 function heightCalc() {
314 var tabhead = d3.select('.tabular-header');
Steven Burrows1c2a9682017-07-14 16:52:46 +0100315
Simon Huntf257a962017-08-25 18:58:47 -0700316 pStartY = fs.noPxStyle(tabhead, 'height') +
317 mast.mastHeight() + topPdg;
318 wSize = fs.windowSize(pStartY);
319 pHeight = wSize.height;
320 }
Steven Burrows1c2a9682017-07-14 16:52:46 +0100321
Simon Huntf257a962017-08-25 18:58:47 -0700322 function initPanel() {
323 heightCalc();
324 createDetailsPane();
325 }
326
327 // Safari has a bug where it renders the fixed-layout
328 // table wrong 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();
Steven Burrows1c2a9682017-07-14 16:52:46 +0100348 }
Simon Huntf257a962017-08-25 18:58:47 -0700349 });
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 () {
Steven Burrows1c2a9682017-07-14 16:52:46 +0100358 if (!fs.isEmptyObject(scope.panelData)) {
Simon Huntf257a962017-08-25 18:58:47 -0700359 heightCalc();
Steven Burrows1c2a9682017-07-14 16:52:46 +0100360 populateDetails(scope.panelData);
Steven Burrows1c2a9682017-07-14 16:52:46 +0100361 }
Simon Huntf257a962017-08-25 18:58:47 -0700362 }
363 );
Steven Burrows1c2a9682017-07-14 16:52:46 +0100364
Simon Huntf257a962017-08-25 18:58:47 -0700365 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}());