blob: 579ebde5eeef2f87e056c17931836cc484752ae1 [file] [log] [blame]
Simon Huntb0ec1e52015-01-28 18:13:49 -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/*
18 ONOS GUI -- Topology Panel Module.
19 Defines functions for manipulating the summary, detail, and instance panels.
20 */
21
22(function () {
23 'use strict';
24
25 // injected refs
Simon Hunt0c6b2d32015-03-26 17:46:29 -070026 var $log, fs, ps, gs, flash, wss;
Simon Huntb0ec1e52015-01-28 18:13:49 -080027
Simon Hunt626d2102015-01-29 11:54:50 -080028 // constants
Simon Hunt08f841d02015-02-10 14:39:20 -080029 var pCls = 'topo-p',
30 idSum = 'topo-p-summary',
Simon Hunt626d2102015-01-29 11:54:50 -080031 idDet = 'topo-p-detail',
Simon Hunt626d2102015-01-29 11:54:50 -080032 panelOpts = {
33 width: 260
34 };
35
Simon Hunt4b668592015-01-29 17:33:53 -080036 // panels
Simon Huntb0ec1e52015-01-28 18:13:49 -080037 var summaryPanel,
Simon Hunt4b668592015-01-29 17:33:53 -080038 detailPanel;
Simon Huntb0ec1e52015-01-28 18:13:49 -080039
Simon Hunt0c6b2d32015-03-26 17:46:29 -070040 // internal state
41 var useDetails = true, // should we show details if we have 'em?
42 haveDetails = false; // do we have details that we could show?
Simon Huntb0ec1e52015-01-28 18:13:49 -080043
Simon Hunt08f841d02015-02-10 14:39:20 -080044 // === -----------------------------------------------------
45 // Utility functions
Simon Hunt626d2102015-01-29 11:54:50 -080046
Simon Hunt4b668592015-01-29 17:33:53 -080047 function addSep(tbody) {
48 tbody.append('tr').append('td').attr('colspan', 2).append('hr');
49 }
50
51 function addProp(tbody, label, value) {
Simon Hunte25c5a22015-04-02 14:37:12 -070052 var tr = tbody.append('tr'),
53 lab = label.replace(/_/g, ' ');
Simon Hunt4b668592015-01-29 17:33:53 -080054
55 function addCell(cls, txt) {
Simon Hunta36f03b2015-04-01 15:22:49 -070056 tr.append('td').attr('class', cls).html(txt);
Simon Hunt4b668592015-01-29 17:33:53 -080057 }
Simon Hunte25c5a22015-04-02 14:37:12 -070058 addCell('label', lab + ' :');
Simon Hunt4b668592015-01-29 17:33:53 -080059 addCell('value', value);
60 }
61
Simon Hunt08f841d02015-02-10 14:39:20 -080062 function listProps(tbody, data) {
63 data.propOrder.forEach(function(p) {
64 if (p === '-') {
65 addSep(tbody);
66 } else {
67 addProp(tbody, p, data.props[p]);
68 }
69 });
70 }
71
72 function dpa(x) {
73 return detailPanel.append(x);
74 }
75
76 function spa(x) {
77 return summaryPanel.append(x);
78 }
79
80 // === -----------------------------------------------------
81 // Functions for populating the summary panel
82
83 function populateSummary(data) {
84 summaryPanel.empty();
85
86 var svg = spa('svg'),
87 title = spa('h2'),
88 table = spa('table'),
89 tbody = table.append('tbody');
90
91 gs.addGlyph(svg, 'node', 40);
92 gs.addGlyph(svg, 'bird', 24, true, [8,12]);
93
94 title.text(data.id);
95 listProps(tbody, data);
96 }
97
98 // === -----------------------------------------------------
99 // Functions for populating the detail panel
100
101 function displaySingle(data) {
102 detailPanel.empty();
103
104 var svg = dpa('svg'),
105 title = dpa('h2'),
106 table = dpa('table'),
107 tbody = table.append('tbody');
108
109 gs.addGlyph(svg, (data.type || 'unknown'), 40);
110 title.text(data.id);
111 listProps(tbody, data);
112 dpa('hr');
113 }
114
115 function displayMulti(ids) {
116 detailPanel.empty();
117
118 var title = dpa('h3'),
119 table = dpa('table'),
120 tbody = table.append('tbody');
121
122 title.text('Selected Nodes');
123 ids.forEach(function (d, i) {
124 addProp(tbody, i+1, d);
125 });
126 dpa('hr');
127 }
128
129 function addAction(text, cb) {
130 dpa('div')
131 .classed('actionBtn', true)
132 .text(text)
133 .on('click', cb);
134 }
135
Simon Hunta36f03b2015-04-01 15:22:49 -0700136 var friendlyIndex = {
137 device: 1,
138 host: 0
139 };
140
141 function friendly(d) {
142 var i = friendlyIndex[d.class] || 0;
143 return (d.labels && d.labels[i]) || '';
144 }
145
146 function linkSummary(d) {
147 var o = d && d.online ? 'online' : 'offline';
148 return d ? d.type + ' / ' + o : '-';
149 }
150
Simon Hunte25c5a22015-04-02 14:37:12 -0700151 // provided to change presentation of internal type name
152 var linkTypePres = {
153 hostLink: 'edge link'
154 };
155
156 function linkType(d) {
157 return linkTypePres[d.type()] || d.type();
158 }
159
160 var coreOrder = [
161 'Type', '-',
162 'A_type', 'A_id', 'A_label', 'A_port', '-',
163 'B_type', 'B_id', 'B_label', 'B_port', '-'
164 ],
165 edgeOrder = [
166 'Type', '-',
167 'A_type', 'A_id', 'A_label', '-',
168 'B_type', 'B_id', 'B_label', 'B_port'
169 ];
170
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700171 function displayLink(data) {
172 detailPanel.empty();
173
174 var svg = dpa('svg'),
175 title = dpa('h2'),
176 table = dpa('table'),
Simon Hunte25c5a22015-04-02 14:37:12 -0700177 tbody = table.append('tbody'),
178 edgeLink = data.type() === 'hostLink',
179 order = edgeLink ? edgeOrder : coreOrder;
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700180
181 gs.addGlyph(svg, 'ports', 40);
182 title.text('Link');
Simon Hunta36f03b2015-04-01 15:22:49 -0700183
Simon Hunta36f03b2015-04-01 15:22:49 -0700184
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700185 listProps(tbody, {
Simon Hunta36f03b2015-04-01 15:22:49 -0700186 propOrder: order,
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700187 props: {
Simon Hunte25c5a22015-04-02 14:37:12 -0700188 Type: linkType(data),
Simon Hunta36f03b2015-04-01 15:22:49 -0700189
190 A_type: data.source.class,
191 A_id: data.source.id,
192 A_label: friendly(data.source),
193 A_port: data.srcPort,
194
195 B_type: data.target.class,
196 B_id: data.target.id,
197 B_label: friendly(data.target),
198 B_port: data.tgtPort
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700199 }
200 });
Simon Hunta36f03b2015-04-01 15:22:49 -0700201
Simon Hunte25c5a22015-04-02 14:37:12 -0700202 if (!edgeLink) {
203 addProp(tbody, 'A → B', linkSummary(data.fromSource));
204 addProp(tbody, 'B → A', linkSummary(data.fromTarget));
205 }
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700206 }
207
208 function displayNothing() {
209 haveDetails = false;
210 hideDetailPanel();
211 }
212
213 function displaySomething() {
214 haveDetails = true;
215 if (useDetails) {
216 showDetailPanel();
217 }
218 }
219
Simon Hunt08f841d02015-02-10 14:39:20 -0800220 // === -----------------------------------------------------
221 // Event Handlers
222
223 function showSummary(data) {
224 populateSummary(data);
225 showSummaryPanel();
226 }
227
Simon Hunt36a58c62015-04-08 11:00:07 -0700228 function toggleSummary(x) {
Simon Huntee7a3ce2015-04-09 13:28:37 -0700229 var kev = (x === 'keyev'),
230 on = kev ? !summaryPanel.isVisible() : !!x,
231 verb = on ? 'Show' : 'Hide';
Simon Hunt36a58c62015-04-08 11:00:07 -0700232
233 if (on) {
Simon Hunta0eb0a82015-02-11 12:30:06 -0800234 // ask server to start sending summary data.
Simon Hunt237676b52015-03-10 19:04:26 -0700235 wss.sendEvent('requestSummary');
Simon Hunta0eb0a82015-02-11 12:30:06 -0800236 // note: the summary panel will appear, once data arrives
Simon Hunt36a58c62015-04-08 11:00:07 -0700237 } else {
238 hideSummaryPanel();
Simon Hunt6036b192015-02-11 11:20:26 -0800239 }
Simon Huntee7a3ce2015-04-09 13:28:37 -0700240 flash.flash(verb + ' summary panel');
241 return on;
Simon Hunt6036b192015-02-11 11:20:26 -0800242 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800243
244 // === -----------------------------------------------------
245 // === LOGIC For showing/hiding summary and detail panels...
246
Simon Hunt626d2102015-01-29 11:54:50 -0800247 function showSummaryPanel() {
Simon Hunt6036b192015-02-11 11:20:26 -0800248 if (detailPanel.isVisible()) {
249 detailPanel.down(summaryPanel.show);
250 } else {
251 summaryPanel.show();
252 }
Simon Huntc252aa62015-02-10 16:45:39 -0800253 }
254
255 function hideSummaryPanel() {
Simon Hunta0eb0a82015-02-11 12:30:06 -0800256 // instruct server to stop sending summary data
Simon Hunt237676b52015-03-10 19:04:26 -0700257 wss.sendEvent("cancelSummary");
Simon Hunta0eb0a82015-02-11 12:30:06 -0800258 summaryPanel.hide(detailPanel.up);
Simon Hunt4b668592015-01-29 17:33:53 -0800259 }
Simon Hunt626d2102015-01-29 11:54:50 -0800260
Simon Hunt08f841d02015-02-10 14:39:20 -0800261 function showDetailPanel() {
Simon Hunt6036b192015-02-11 11:20:26 -0800262 if (summaryPanel.isVisible()) {
263 detailPanel.down(detailPanel.show);
264 } else {
265 detailPanel.up(detailPanel.show);
266 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800267 }
268
269 function hideDetailPanel() {
270 detailPanel.hide();
271 }
272
Simon Hunt6036b192015-02-11 11:20:26 -0800273 // ==========================
Simon Hunt08f841d02015-02-10 14:39:20 -0800274
Simon Hunt6036b192015-02-11 11:20:26 -0800275 function noop () {}
276
277 function augmentDetailPanel() {
278 var dp = detailPanel;
279 dp.ypos = { up: 64, down: 320, current: 320};
280
281 dp._move = function (y, cb) {
282 var endCb = fs.isF(cb) || noop,
283 yp = dp.ypos;
284 if (yp.current !== y) {
285 yp.current = y;
286 dp.el().transition().duration(300)
287 .each('end', endCb)
288 .style('top', yp.current + 'px');
289 } else {
290 endCb();
291 }
292 };
293
294 dp.down = function (cb) { dp._move(dp.ypos.down, cb); };
295 dp.up = function (cb) { dp._move(dp.ypos.up, cb); };
296 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800297
Simon Hunt36a58c62015-04-08 11:00:07 -0700298 function toggleDetails(x) {
Simon Huntee7a3ce2015-04-09 13:28:37 -0700299 var kev = (x === 'keyev'),
300 verb;
301
302 useDetails = kev ? !useDetails : !!x;
303 verb = useDetails ? 'Enable' : 'Disable';
304
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700305 if (useDetails) {
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700306 if (haveDetails) {
307 showDetailPanel();
308 }
309 } else {
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700310 hideDetailPanel();
311 }
Simon Huntee7a3ce2015-04-09 13:28:37 -0700312 flash.flash(verb + ' details panel');
313 return useDetails;
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700314 }
315
Simon Hunt4b668592015-01-29 17:33:53 -0800316 // ==========================
317
Simon Hunt237676b52015-03-10 19:04:26 -0700318 function initPanels() {
Simon Hunt4b668592015-01-29 17:33:53 -0800319 summaryPanel = ps.createPanel(idSum, panelOpts);
320 detailPanel = ps.createPanel(idDet, panelOpts);
Simon Hunt08f841d02015-02-10 14:39:20 -0800321
322 summaryPanel.classed(pCls, true);
323 detailPanel.classed(pCls, true);
Simon Hunt6036b192015-02-11 11:20:26 -0800324
325 augmentDetailPanel();
Simon Hunt4b668592015-01-29 17:33:53 -0800326 }
327
328 function destroyPanels() {
329 ps.destroyPanel(idSum);
330 ps.destroyPanel(idDet);
331 summaryPanel = detailPanel = null;
Simon Hunt626d2102015-01-29 11:54:50 -0800332 }
333
334 // ==========================
335
Simon Huntb0ec1e52015-01-28 18:13:49 -0800336 angular.module('ovTopo')
337 .factory('TopoPanelService',
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700338 ['$log', 'FnService', 'PanelService', 'GlyphService',
339 'FlashService', 'WebSocketService',
Simon Huntb0ec1e52015-01-28 18:13:49 -0800340
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700341 function (_$log_, _fs_, _ps_, _gs_, _flash_, _wss_) {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800342 $log = _$log_;
Simon Hunt6036b192015-02-11 11:20:26 -0800343 fs = _fs_;
Simon Huntb0ec1e52015-01-28 18:13:49 -0800344 ps = _ps_;
Simon Huntc9b73162015-01-29 14:02:15 -0800345 gs = _gs_;
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700346 flash = _flash_;
Simon Hunt237676b52015-03-10 19:04:26 -0700347 wss = _wss_;
Simon Huntb0ec1e52015-01-28 18:13:49 -0800348
Simon Huntb0ec1e52015-01-28 18:13:49 -0800349 return {
350 initPanels: initPanels,
Simon Hunt626d2102015-01-29 11:54:50 -0800351 destroyPanels: destroyPanels,
Simon Hunt08f841d02015-02-10 14:39:20 -0800352
353 showSummary: showSummary,
Simon Hunt6036b192015-02-11 11:20:26 -0800354 toggleSummary: toggleSummary,
Simon Hunt08f841d02015-02-10 14:39:20 -0800355
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700356 toggleDetails: toggleDetails,
Simon Hunt08f841d02015-02-10 14:39:20 -0800357 displaySingle: displaySingle,
358 displayMulti: displayMulti,
359 addAction: addAction,
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700360 displayLink: displayLink,
361 displayNothing: displayNothing,
362 displaySomething: displaySomething,
Simon Hunt08f841d02015-02-10 14:39:20 -0800363
Simon Huntc252aa62015-02-10 16:45:39 -0800364 hideSummaryPanel: hideSummaryPanel,
Simon Hunt08f841d02015-02-10 14:39:20 -0800365
366 detailVisible: function () { return detailPanel.isVisible(); },
367 summaryVisible: function () { return summaryPanel.isVisible(); }
Simon Huntb0ec1e52015-01-28 18:13:49 -0800368 };
369 }]);
370}());