Bri Prebilic Cole

GUI -- Buttons added to topo and device views that navigate to new flows table view.

Change-Id: Ibea4415d3c1fc717e609aebcd2205d0bba01c96d
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
21 'use strict'; 21 'use strict';
22 22
23 // injected dependencies 23 // injected dependencies
24 - var $log; 24 + var $log, $location, $window, fs;
25 25
26 // internal state 26 // internal state
27 var navShown = false; 27 var navShown = false;
...@@ -52,9 +52,29 @@ ...@@ -52,9 +52,29 @@
52 return false; 52 return false;
53 } 53 }
54 54
55 + function navTo(path, params) {
56 + var url;
57 + if (!path) {
58 + $log.warn('Not a valid navigation path');
59 + return null;
60 + }
61 + $location.url('/' + path);
62 +
63 + if (fs.isO(params)) {
64 + $location.search(params);
65 + } else if (params !== undefined) {
66 + $log.warn('Query params not an object', params);
67 + }
68 +
69 + url = $location.absUrl();
70 + $log.log('Navigating to ', url);
71 + $window.location.href = url;
72 + }
73 +
55 angular.module('onosNav', []) 74 angular.module('onosNav', [])
56 - .controller('NavCtrl', [ 75 + .controller('NavCtrl', ['$log',
57 - '$log', function (_$log_) { 76 +
77 + function (_$log_) {
58 var self = this; 78 var self = this;
59 $log = _$log_; 79 $log = _$log_;
60 80
...@@ -62,15 +82,22 @@ ...@@ -62,15 +82,22 @@
62 $log.log('NavCtrl has been created'); 82 $log.log('NavCtrl has been created');
63 } 83 }
64 ]) 84 ])
65 - .factory('NavService', ['$log', function (_$log_) { 85 + .factory('NavService',
66 - $log = _$log_; 86 + ['$log', '$location', '$window', 'FnService',
87 +
88 + function (_$log_, _$location_, _$window_, _fs_) {
89 + $log = _$log_;
90 + $location = _$location_;
91 + $window = _$window_;
92 + fs = _fs_;
67 93
68 - return { 94 + return {
69 - showNav: showNav, 95 + showNav: showNav,
70 - hideNav: hideNav, 96 + hideNav: hideNav,
71 - toggleNav: toggleNav, 97 + toggleNav: toggleNav,
72 - hideIfShown: hideIfShown 98 + hideIfShown: hideIfShown,
73 - }; 99 + navTo: navTo
100 + };
74 }]); 101 }]);
75 102
76 }()); 103 }());
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
22 'use strict'; 22 'use strict';
23 23
24 // injected references 24 // injected references
25 - var $log, $timeout, fs; 25 + var $log, fs;
26 26
27 // constants 27 // constants
28 var hoverHeight = 35, 28 var hoverHeight = 35,
29 - hoverDelay = 500, 29 + hoverDelay = 100,
30 exitDelay = 100; 30 exitDelay = 100;
31 31
32 // internal state 32 // internal state
...@@ -104,19 +104,23 @@ ...@@ -104,19 +104,23 @@
104 } 104 }
105 } 105 }
106 106
107 + function resetTooltip() {
108 + tooltip.style('display', 'none').text('');
109 + }
110 +
107 angular.module('onosWidget') 111 angular.module('onosWidget')
108 - .factory('TooltipService', ['$log', '$timeout', 'FnService', 112 + .factory('TooltipService', ['$log', 'FnService',
109 113
110 - function (_$log_, _$timeout_, _fs_) { 114 + function (_$log_, _fs_) {
111 $log = _$log_; 115 $log = _$log_;
112 - $timeout = _$timeout_;
113 fs = _fs_; 116 fs = _fs_;
114 117
115 init(); 118 init();
116 119
117 return { 120 return {
118 showTooltip: showTooltip, 121 showTooltip: showTooltip,
119 - cancelTooltip: cancelTooltip 122 + cancelTooltip: cancelTooltip,
123 + resetTooltip: resetTooltip
120 }; 124 };
121 }]); 125 }]);
122 }()); 126 }());
......
...@@ -66,6 +66,14 @@ ...@@ -66,6 +66,14 @@
66 margin: 8px 0; 66 margin: 8px 0;
67 } 67 }
68 68
69 +#device-details-panel .top div.left {
70 + float: left;
71 + padding: 0 18px 0 0;
72 +}
73 +#device-details-panel .top div.right {
74 + display: inline-block;
75 +}
76 +
69 #device-details-panel td.label { 77 #device-details-panel td.label {
70 font-style: italic; 78 font-style: italic;
71 padding-right: 12px; 79 padding-right: 12px;
...@@ -73,8 +81,12 @@ ...@@ -73,8 +81,12 @@
73 color: #777; 81 color: #777;
74 } 82 }
75 83
76 -#device-details-panel hr { 84 +#device-details-panel .actionBtns div {
77 - margin: 12px 0; 85 + padding: 12px 0;
86 +}
87 +#device-details-panel .top hr {
88 + width: 95%;
89 + margin: 0 auto;
78 } 90 }
79 91
80 .light #device-details-panel hr { 92 .light #device-details-panel hr {
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
22 'use strict'; 22 'use strict';
23 23
24 // injected refs 24 // injected refs
25 - var $log, $scope, fs, mast, ps, wss, is; 25 + var $log, $scope, fs, mast, ps, wss, is, bns, ns, ttip;
26 26
27 // internal state 27 // internal state
28 var self, 28 var self,
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
36 ctnrPdg = 24, 36 ctnrPdg = 24,
37 scrollSize = 17, 37 scrollSize = 17,
38 portsTblPdg = 50, 38 portsTblPdg = 50,
39 + flowPath = 'flow',
39 40
40 pName = 'device-details-panel', 41 pName = 'device-details-panel',
41 detailsReq = 'deviceDetailsRequest', 42 detailsReq = 'deviceDetailsRequest',
...@@ -67,7 +68,7 @@ ...@@ -67,7 +68,7 @@
67 } 68 }
68 69
69 function setUpPanel() { 70 function setUpPanel() {
70 - var container, closeBtn; 71 + var container, closeBtn, tblDiv;
71 detailsPanel.empty(); 72 detailsPanel.empty();
72 73
73 container = detailsPanel.append('div').classed('container', true); 74 container = detailsPanel.append('div').classed('container', true);
...@@ -77,7 +78,12 @@ ...@@ -77,7 +78,12 @@
77 addCloseBtn(closeBtn); 78 addCloseBtn(closeBtn);
78 iconDiv = top.append('div').classed('dev-icon', true); 79 iconDiv = top.append('div').classed('dev-icon', true);
79 top.append('h2'); 80 top.append('h2');
80 - top.append('table'); 81 +
82 + tblDiv = top.append('div').classed('top-tables', true);
83 + tblDiv.append('div').classed('left', true).append('table');
84 + tblDiv.append('div').classed('right', true).append('table');
85 +
86 + top.append('div').classed('actionBtns', true);
81 top.append('hr'); 87 top.append('hr');
82 88
83 bottom = container.append('div').classed('bottom', true); 89 bottom = container.append('div').classed('bottom', true);
...@@ -95,13 +101,29 @@ ...@@ -95,13 +101,29 @@
95 addCell('value', value); 101 addCell('value', value);
96 } 102 }
97 103
98 - function populateTop(tbody, details) { 104 + function populateTop(tblDiv, btnsDiv, details) {
105 + var leftTbl = tblDiv.select('.left')
106 + .select('table')
107 + .append('tbody'),
108 + rightTbl = tblDiv.select('.right')
109 + .select('table')
110 + .append('tbody');
111 +
99 is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40); 112 is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
100 top.select('h2').html(details.id); 113 top.select('h2').html(details.id);
101 114
102 propOrder.forEach(function (prop, i) { 115 propOrder.forEach(function (prop, i) {
103 - addProp(tbody, i, details[prop]); 116 + // properties are split into two tables
117 + addProp(i < 3 ? leftTbl : rightTbl, i, details[prop]);
104 }); 118 });
119 +
120 + bns.button(btnsDiv,
121 + 'dev-dets-p-flows',
122 + 'flowsTable',
123 + function () {
124 + ns.navTo(flowPath, { devId: details.id });
125 + },
126 + 'Show flows for this device');
105 } 127 }
106 128
107 function addPortRow(tbody, port) { 129 function addPortRow(tbody, port) {
...@@ -146,14 +168,15 @@ ...@@ -146,14 +168,15 @@
146 } 168 }
147 169
148 function populateDetails(details) { 170 function populateDetails(details) {
149 - var topTb, btmTbl, ports; 171 + var topTbs, btnsDiv, btmTbl, ports;
150 setUpPanel(); 172 setUpPanel();
151 173
152 - topTb = top.select('table').append('tbody'); 174 + topTbs = top.select('.top-tables');
175 + btnsDiv = top.select('.actionBtns');
153 btmTbl = bottom.select('table'); 176 btmTbl = bottom.select('table');
154 ports = details.ports; 177 ports = details.ports;
155 178
156 - populateTop(topTb, details); 179 + populateTop(topTbs, btnsDiv, details);
157 populateBottom(btmTbl, ports); 180 populateBottom(btmTbl, ports);
158 181
159 detailsPanel.height(pHeight); 182 detailsPanel.height(pHeight);
...@@ -182,8 +205,10 @@ ...@@ -182,8 +205,10 @@
182 .controller('OvDeviceCtrl', 205 .controller('OvDeviceCtrl',
183 ['$log', '$scope', 'TableBuilderService', 'FnService', 206 ['$log', '$scope', 'TableBuilderService', 'FnService',
184 'MastService', 'PanelService', 'WebSocketService', 'IconService', 207 'MastService', 'PanelService', 'WebSocketService', 'IconService',
208 + 'ButtonService', 'NavService', 'TooltipService',
185 209
186 - function (_$log_, _$scope_, tbs, _fs_, _mast_, _ps_, _wss_, _is_) { 210 + function (_$log_, _$scope_,
211 + tbs, _fs_, _mast_, _ps_, _wss_, _is_, _bns_, _ns_, _ttip_) {
187 $log = _$log_; 212 $log = _$log_;
188 $scope = _$scope_; 213 $scope = _$scope_;
189 fs = _fs_; 214 fs = _fs_;
...@@ -191,6 +216,9 @@ ...@@ -191,6 +216,9 @@
191 ps = _ps_; 216 ps = _ps_;
192 wss = _wss_; 217 wss = _wss_;
193 is = _is_; 218 is = _is_;
219 + bns = _bns_;
220 + ns = _ns_;
221 + ttip = _ttip_;
194 self = this; 222 self = this;
195 var handlers = {}; 223 var handlers = {};
196 self.panelData = []; 224 self.panelData = [];
...@@ -217,12 +245,14 @@ ...@@ -217,12 +245,14 @@
217 }); 245 });
218 createDetailsPane(); 246 createDetailsPane();
219 247
248 + // details panel handlers
220 handlers[detailsResp] = respDetailsCb; 249 handlers[detailsResp] = respDetailsCb;
221 wss.bindHandlers(handlers); 250 wss.bindHandlers(handlers);
222 251
223 $scope.$on('$destroy', function () { 252 $scope.$on('$destroy', function () {
224 ps.destroyPanel(pName); 253 ps.destroyPanel(pName);
225 wss.unbindHandlers(handlers); 254 wss.unbindHandlers(handlers);
255 + ttip.resetTooltip();
226 }); 256 });
227 257
228 $log.log('OvDeviceCtrl has been created'); 258 $log.log('OvDeviceCtrl has been created');
......
...@@ -85,9 +85,6 @@ ...@@ -85,9 +85,6 @@
85 top: 320px; 85 top: 320px;
86 } 86 }
87 87
88 -#topo-p-detail .actionBtns {
89 - text-align: center;
90 -}
91 #topo-p-detail .actionBtns .actionBtn { 88 #topo-p-detail .actionBtns .actionBtn {
92 display: inline-block; 89 display: inline-block;
93 } 90 }
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
30 30
31 // references to injected services etc. 31 // references to injected services etc.
32 var $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps, 32 var $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps,
33 - tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs; 33 + tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs, ttip;
34 34
35 // DOM elements 35 // DOM elements
36 var ovtopo, svg, defs, zoomLayer, mapG, spriteG, forceG, noDevsLayer; 36 var ovtopo, svg, defs, zoomLayer, mapG, spriteG, forceG, noDevsLayer;
...@@ -319,11 +319,12 @@ ...@@ -319,11 +319,12 @@
319 'TopoEventService', 'TopoForceService', 'TopoPanelService', 319 'TopoEventService', 'TopoForceService', 'TopoPanelService',
320 'TopoInstService', 'TopoSelectService', 'TopoLinkService', 320 'TopoInstService', 'TopoSelectService', 'TopoLinkService',
321 'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService', 321 'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService',
322 - 'TopoToolbarService', 'TopoSpriteService', 322 + 'TopoToolbarService', 'TopoSpriteService', 'TooltipService',
323 323
324 function ($scope, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_, 324 function ($scope, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_,
325 _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, 325 _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_,
326 - _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr) { 326 + _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr,
327 + _ttip_) {
327 var self = this, 328 var self = this,
328 projection, 329 projection,
329 dim, 330 dim,
...@@ -360,6 +361,7 @@ ...@@ -360,6 +361,7 @@
360 tos = _tos_; 361 tos = _tos_;
361 fltr = _fltr_; 362 fltr = _fltr_;
362 ttbs = _ttbs_; 363 ttbs = _ttbs_;
364 + ttip = _ttip_;
363 365
364 self.notifyResize = function () { 366 self.notifyResize = function () {
365 svgResized(fs.windowSize(mast.mastHeight())); 367 svgResized(fs.windowSize(mast.mastHeight()));
...@@ -373,6 +375,7 @@ ...@@ -373,6 +375,7 @@
373 tis.destroyInst(); 375 tis.destroyInst();
374 tfs.destroyForce(); 376 tfs.destroyForce();
375 ttbs.destroyToolbar(); 377 ttbs.destroyToolbar();
378 + ttip.resetTooltip();
376 }); 379 });
377 380
378 // svg layer and initialization of components 381 // svg layer and initialization of components
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
23 'use strict'; 23 'use strict';
24 24
25 // injected refs 25 // injected refs
26 - var $log, fs, wss, tps, tts; 26 + var $log, fs, wss, tps, tts, ns;
27 27
28 // api to topoForce 28 // api to topoForce
29 var api; 29 var api;
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
40 selectOrder = [], // the order in which we made selections 40 selectOrder = [], // the order in which we made selections
41 consumeClick = false; // used to coordinate with SVG click handler 41 consumeClick = false; // used to coordinate with SVG click handler
42 42
43 + // constants
44 + var flowPath = 'flow';
45 +
43 // ========================== 46 // ==========================
44 47
45 function nSel() { 48 function nSel() {
...@@ -240,6 +243,18 @@ ...@@ -240,6 +243,18 @@
240 tt: 'Show Device Flows' 243 tt: 'Show Device Flows'
241 }); 244 });
242 } 245 }
246 + // TODO: have the server return explicit class and ID of each node
247 + // for now, we assume the node is a device if it has a URI
248 + if ((data.props).hasOwnProperty('URI')) {
249 + tps.addAction({
250 + id: 'flows-table-btn',
251 + gid: 'flowsTable',
252 + cb: function () {
253 + ns.navTo(flowPath, { devId: data.id });
254 + },
255 + tt: 'Show flows for this device'
256 + });
257 + }
243 258
244 tps.displaySomething(); 259 tps.displaySomething();
245 } 260 }
...@@ -264,14 +279,15 @@ ...@@ -264,14 +279,15 @@
264 angular.module('ovTopo') 279 angular.module('ovTopo')
265 .factory('TopoSelectService', 280 .factory('TopoSelectService',
266 ['$log', 'FnService', 'WebSocketService', 281 ['$log', 'FnService', 'WebSocketService',
267 - 'TopoPanelService', 'TopoTrafficService', 282 + 'TopoPanelService', 'TopoTrafficService', 'NavService',
268 283
269 - function (_$log_, _fs_, _wss_, _tps_, _tts_) { 284 + function (_$log_, _fs_, _wss_, _tps_, _tts_, _ns_) {
270 $log = _$log_; 285 $log = _$log_;
271 fs = _fs_; 286 fs = _fs_;
272 wss = _wss_; 287 wss = _wss_;
273 tps = _tps_; 288 tps = _tps_;
274 tts = _tts_; 289 tts = _tts_;
290 + ns = _ns_;
275 291
276 function initSelect(_api_) { 292 function initSelect(_api_) {
277 api = _api_; 293 api = _api_;
......
...@@ -19,21 +19,18 @@ ...@@ -19,21 +19,18 @@
19 */ 19 */
20 describe('Controller: MastCtrl', function () { 20 describe('Controller: MastCtrl', function () {
21 // instantiate the masthead module 21 // instantiate the masthead module
22 - beforeEach(module('onosMast')); 22 + beforeEach(module('onosMast', 'onosUtil'));
23 23
24 - var $log, ctrl, ms; 24 + var $log, ctrl, ms, fs;
25 25
26 // we need an instance of the controller 26 // we need an instance of the controller
27 - beforeEach(inject(function(_$log_, $controller, MastService) { 27 + beforeEach(inject(function(_$log_, $controller, MastService, FnService) {
28 $log = _$log_; 28 $log = _$log_;
29 ctrl = $controller('MastCtrl'); 29 ctrl = $controller('MastCtrl');
30 ms = MastService; 30 ms = MastService;
31 + fs = FnService;
31 })); 32 }));
32 33
33 - it('should start with no radio buttons', function () {
34 - expect(ctrl.radio).toBeNull();
35 - });
36 -
37 it('should declare height to be 36', function () { 34 it('should declare height to be 36', function () {
38 expect(ms.mastHeight()).toBe(36); 35 expect(ms.mastHeight()).toBe(36);
39 }) 36 })
......
...@@ -18,14 +18,29 @@ ...@@ -18,14 +18,29 @@
18 ONOS GUI -- Util -- Theme Service - Unit Tests 18 ONOS GUI -- Util -- Theme Service - Unit Tests
19 */ 19 */
20 describe('factory: fw/nav/nav.js', function() { 20 describe('factory: fw/nav/nav.js', function() {
21 - var ns, $log, fs; 21 + var $log, $location, $window, ns, fs;
22 var d3Elem; 22 var d3Elem;
23 23
24 beforeEach(module('onosNav', 'onosUtil')); 24 beforeEach(module('onosNav', 'onosUtil'));
25 25
26 - beforeEach(inject(function (NavService, _$log_, FnService) { 26 + var mockWindow = {
27 - ns = NavService; 27 + location: {
28 + href: 'http://server/#/mock/url'
29 + }
30 + };
31 +
32 + beforeEach(function () {
33 + module(function ($provide) {
34 + $provide.value('$window', mockWindow);
35 + });
36 + });
37 +
38 + beforeEach(inject(function (_$log_, _$location_, _$window_,
39 + NavService, FnService) {
28 $log = _$log_; 40 $log = _$log_;
41 + $location = _$location_;
42 + $window = _$window_;
43 + ns = NavService;
29 fs = FnService; 44 fs = FnService;
30 d3Elem = d3.select('body').append('div').attr('id', 'nav'); 45 d3Elem = d3.select('body').append('div').attr('id', 'nav');
31 ns.hideNav(); 46 ns.hideNav();
...@@ -41,7 +56,7 @@ describe('factory: fw/nav/nav.js', function() { ...@@ -41,7 +56,7 @@ describe('factory: fw/nav/nav.js', function() {
41 56
42 it('should define api functions', function () { 57 it('should define api functions', function () {
43 expect(fs.areFunctions(ns, [ 58 expect(fs.areFunctions(ns, [
44 - 'showNav', 'hideNav', 'toggleNav', 'hideIfShown' 59 + 'showNav', 'hideNav', 'toggleNav', 'hideIfShown', 'navTo'
45 ])).toBeTruthy(); 60 ])).toBeTruthy();
46 }); 61 });
47 62
...@@ -95,4 +110,56 @@ describe('factory: fw/nav/nav.js', function() { ...@@ -95,4 +110,56 @@ describe('factory: fw/nav/nav.js', function() {
95 checkHidden(true); 110 checkHidden(true);
96 }); 111 });
97 112
113 + it('should take correct navTo parameters', function () {
114 + spyOn($log, 'warn');
115 +
116 + ns.navTo('foo');
117 + expect($log.warn).not.toHaveBeenCalled();
118 +
119 + ns.navTo('bar', { q1: 'thing', q2: 'thing2' });
120 + expect($log.warn).not.toHaveBeenCalled();
121 +
122 + });
123 +
124 + it('should check navTo parameter warnings', function () {
125 + spyOn($log, 'warn');
126 +
127 + expect(ns.navTo()).toBeNull();
128 + expect($log.warn).toHaveBeenCalledWith('Not a valid navigation path');
129 +
130 + ns.navTo('baz', [1, 2, 3]);
131 + expect($log.warn).toHaveBeenCalledWith(
132 + 'Query params not an object', [1, 2, 3]
133 + );
134 +
135 + ns.navTo('zoom', 'not a query param');
136 + expect($log.warn).toHaveBeenCalledWith(
137 + 'Query params not an object', 'not a query param'
138 + );
139 + });
140 +
141 + it('should verify where the window is navigating', function () {
142 + ns.navTo('foo');
143 + expect($window.location.href).toBe('http://server/#/foo');
144 +
145 + ns.navTo('bar');
146 + expect($window.location.href).toBe('http://server/#/bar');
147 +
148 + ns.navTo('baz', { q1: 'thing1', q2: 'thing2' });
149 + expect($window.location.href).toBe(
150 + 'http://server/#/baz?q1=thing1&q2=thing2'
151 + );
152 +
153 + ns.navTo('zip', { q3: 'thing3' });
154 + expect($window.location.href).toBe(
155 + 'http://server/#/zip?q3=thing3'
156 + );
157 +
158 + ns.navTo('zoom', {});
159 + expect($window.location.href).toBe('http://server/#/zoom');
160 +
161 + ns.navTo('roof', [1, 2, 3]);
162 + expect($window.location.href).toBe('http://server/#/roof');
163 + });
164 +
98 }); 165 });
......
...@@ -42,7 +42,7 @@ describe('factory: fw/widget/tooltip.js', function () { ...@@ -42,7 +42,7 @@ describe('factory: fw/widget/tooltip.js', function () {
42 42
43 it('should define api functions', function () { 43 it('should define api functions', function () {
44 expect(fs.areFunctions(tts, [ 44 expect(fs.areFunctions(tts, [
45 - 'showTooltip', 'cancelTooltip' 45 + 'showTooltip', 'cancelTooltip', 'resetTooltip'
46 ])).toBeTruthy(); 46 ])).toBeTruthy();
47 }); 47 });
48 48
......