blob: af6e879282f1f320d34a31dac7a2084145462cda [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
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -070026 var $log, fs, ps, gs, flash, wss, bns;
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'),
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -070053 lab;
54 if (typeof label === 'string') {
Simon Hunte25c5a22015-04-02 14:37:12 -070055 lab = label.replace(/_/g, ' ');
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -070056 } else {
57 lab = label;
58 }
Simon Hunt4b668592015-01-29 17:33:53 -080059
60 function addCell(cls, txt) {
Simon Hunta36f03b2015-04-01 15:22:49 -070061 tr.append('td').attr('class', cls).html(txt);
Simon Hunt4b668592015-01-29 17:33:53 -080062 }
Simon Hunte25c5a22015-04-02 14:37:12 -070063 addCell('label', lab + ' :');
Simon Hunt4b668592015-01-29 17:33:53 -080064 addCell('value', value);
65 }
66
Simon Hunt08f841d02015-02-10 14:39:20 -080067 function listProps(tbody, data) {
68 data.propOrder.forEach(function(p) {
69 if (p === '-') {
70 addSep(tbody);
71 } else {
72 addProp(tbody, p, data.props[p]);
73 }
74 });
75 }
76
77 function dpa(x) {
78 return detailPanel.append(x);
79 }
80
81 function spa(x) {
82 return summaryPanel.append(x);
83 }
84
85 // === -----------------------------------------------------
86 // Functions for populating the summary panel
87
88 function populateSummary(data) {
89 summaryPanel.empty();
90
91 var svg = spa('svg'),
92 title = spa('h2'),
93 table = spa('table'),
94 tbody = table.append('tbody');
95
96 gs.addGlyph(svg, 'node', 40);
97 gs.addGlyph(svg, 'bird', 24, true, [8,12]);
98
99 title.text(data.id);
100 listProps(tbody, data);
101 }
102
103 // === -----------------------------------------------------
104 // Functions for populating the detail panel
105
106 function displaySingle(data) {
107 detailPanel.empty();
108
109 var svg = dpa('svg'),
110 title = dpa('h2'),
111 table = dpa('table'),
112 tbody = table.append('tbody');
113
114 gs.addGlyph(svg, (data.type || 'unknown'), 40);
115 title.text(data.id);
116 listProps(tbody, data);
117 dpa('hr');
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700118 dpa('div').classed('actionBtns', true);
Simon Hunt08f841d02015-02-10 14:39:20 -0800119 }
120
121 function displayMulti(ids) {
122 detailPanel.empty();
123
124 var title = dpa('h3'),
125 table = dpa('table'),
126 tbody = table.append('tbody');
127
128 title.text('Selected Nodes');
129 ids.forEach(function (d, i) {
130 addProp(tbody, i+1, d);
131 });
132 dpa('hr');
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700133 dpa('div').classed('actionBtns', true);
Simon Hunt08f841d02015-02-10 14:39:20 -0800134 }
135
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700136 function addAction(o) {
137 var btnDiv = d3.select('#' + idDet)
138 .select('.actionBtns')
139 .append('div')
140 .classed('actionBtn', true);
141 bns.button(btnDiv, idDet + o.id, o.gid, o.cb, o.tt);
Simon Hunt08f841d02015-02-10 14:39:20 -0800142 }
143
Simon Hunta36f03b2015-04-01 15:22:49 -0700144 var friendlyIndex = {
145 device: 1,
146 host: 0
147 };
148
149 function friendly(d) {
150 var i = friendlyIndex[d.class] || 0;
151 return (d.labels && d.labels[i]) || '';
152 }
153
154 function linkSummary(d) {
155 var o = d && d.online ? 'online' : 'offline';
156 return d ? d.type + ' / ' + o : '-';
157 }
158
Simon Hunte25c5a22015-04-02 14:37:12 -0700159 // provided to change presentation of internal type name
160 var linkTypePres = {
161 hostLink: 'edge link'
162 };
163
164 function linkType(d) {
165 return linkTypePres[d.type()] || d.type();
166 }
167
168 var coreOrder = [
169 'Type', '-',
170 'A_type', 'A_id', 'A_label', 'A_port', '-',
171 'B_type', 'B_id', 'B_label', 'B_port', '-'
172 ],
173 edgeOrder = [
174 'Type', '-',
175 'A_type', 'A_id', 'A_label', '-',
176 'B_type', 'B_id', 'B_label', 'B_port'
177 ];
178
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700179 function displayLink(data) {
180 detailPanel.empty();
181
182 var svg = dpa('svg'),
183 title = dpa('h2'),
184 table = dpa('table'),
Simon Hunte25c5a22015-04-02 14:37:12 -0700185 tbody = table.append('tbody'),
186 edgeLink = data.type() === 'hostLink',
187 order = edgeLink ? edgeOrder : coreOrder;
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700188
189 gs.addGlyph(svg, 'ports', 40);
190 title.text('Link');
Simon Hunta36f03b2015-04-01 15:22:49 -0700191
Simon Hunta36f03b2015-04-01 15:22:49 -0700192
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700193 listProps(tbody, {
Simon Hunta36f03b2015-04-01 15:22:49 -0700194 propOrder: order,
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700195 props: {
Simon Hunte25c5a22015-04-02 14:37:12 -0700196 Type: linkType(data),
Simon Hunta36f03b2015-04-01 15:22:49 -0700197
198 A_type: data.source.class,
199 A_id: data.source.id,
200 A_label: friendly(data.source),
201 A_port: data.srcPort,
202
203 B_type: data.target.class,
204 B_id: data.target.id,
205 B_label: friendly(data.target),
206 B_port: data.tgtPort
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700207 }
208 });
Simon Hunta36f03b2015-04-01 15:22:49 -0700209
Simon Hunte25c5a22015-04-02 14:37:12 -0700210 if (!edgeLink) {
211 addProp(tbody, 'A → B', linkSummary(data.fromSource));
212 addProp(tbody, 'B → A', linkSummary(data.fromTarget));
213 }
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700214 }
215
216 function displayNothing() {
217 haveDetails = false;
218 hideDetailPanel();
219 }
220
221 function displaySomething() {
222 haveDetails = true;
223 if (useDetails) {
224 showDetailPanel();
225 }
226 }
227
Simon Hunt08f841d02015-02-10 14:39:20 -0800228 // === -----------------------------------------------------
229 // Event Handlers
230
231 function showSummary(data) {
232 populateSummary(data);
233 showSummaryPanel();
234 }
235
Simon Hunt36a58c62015-04-08 11:00:07 -0700236 function toggleSummary(x) {
Simon Huntee7a3ce2015-04-09 13:28:37 -0700237 var kev = (x === 'keyev'),
238 on = kev ? !summaryPanel.isVisible() : !!x,
239 verb = on ? 'Show' : 'Hide';
Simon Hunt36a58c62015-04-08 11:00:07 -0700240
241 if (on) {
Simon Hunta0eb0a82015-02-11 12:30:06 -0800242 // ask server to start sending summary data.
Simon Hunt237676b52015-03-10 19:04:26 -0700243 wss.sendEvent('requestSummary');
Simon Hunta0eb0a82015-02-11 12:30:06 -0800244 // note: the summary panel will appear, once data arrives
Simon Hunt36a58c62015-04-08 11:00:07 -0700245 } else {
246 hideSummaryPanel();
Simon Hunt6036b192015-02-11 11:20:26 -0800247 }
Simon Huntee7a3ce2015-04-09 13:28:37 -0700248 flash.flash(verb + ' summary panel');
249 return on;
Simon Hunt6036b192015-02-11 11:20:26 -0800250 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800251
252 // === -----------------------------------------------------
253 // === LOGIC For showing/hiding summary and detail panels...
254
Simon Hunt626d2102015-01-29 11:54:50 -0800255 function showSummaryPanel() {
Simon Hunt6036b192015-02-11 11:20:26 -0800256 if (detailPanel.isVisible()) {
257 detailPanel.down(summaryPanel.show);
258 } else {
259 summaryPanel.show();
260 }
Simon Huntc252aa62015-02-10 16:45:39 -0800261 }
262
263 function hideSummaryPanel() {
Simon Hunta0eb0a82015-02-11 12:30:06 -0800264 // instruct server to stop sending summary data
Simon Hunt237676b52015-03-10 19:04:26 -0700265 wss.sendEvent("cancelSummary");
Simon Hunta0eb0a82015-02-11 12:30:06 -0800266 summaryPanel.hide(detailPanel.up);
Simon Hunt4b668592015-01-29 17:33:53 -0800267 }
Simon Hunt626d2102015-01-29 11:54:50 -0800268
Simon Hunt08f841d02015-02-10 14:39:20 -0800269 function showDetailPanel() {
Simon Hunt6036b192015-02-11 11:20:26 -0800270 if (summaryPanel.isVisible()) {
271 detailPanel.down(detailPanel.show);
272 } else {
273 detailPanel.up(detailPanel.show);
274 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800275 }
276
277 function hideDetailPanel() {
278 detailPanel.hide();
279 }
280
Simon Hunt6036b192015-02-11 11:20:26 -0800281 // ==========================
Simon Hunt08f841d02015-02-10 14:39:20 -0800282
Simon Hunt6036b192015-02-11 11:20:26 -0800283 function noop () {}
284
285 function augmentDetailPanel() {
286 var dp = detailPanel;
287 dp.ypos = { up: 64, down: 320, current: 320};
288
289 dp._move = function (y, cb) {
290 var endCb = fs.isF(cb) || noop,
291 yp = dp.ypos;
292 if (yp.current !== y) {
293 yp.current = y;
294 dp.el().transition().duration(300)
295 .each('end', endCb)
296 .style('top', yp.current + 'px');
297 } else {
298 endCb();
299 }
300 };
301
302 dp.down = function (cb) { dp._move(dp.ypos.down, cb); };
303 dp.up = function (cb) { dp._move(dp.ypos.up, cb); };
304 }
Simon Hunt08f841d02015-02-10 14:39:20 -0800305
Simon Hunt36a58c62015-04-08 11:00:07 -0700306 function toggleDetails(x) {
Simon Huntee7a3ce2015-04-09 13:28:37 -0700307 var kev = (x === 'keyev'),
308 verb;
309
310 useDetails = kev ? !useDetails : !!x;
311 verb = useDetails ? 'Enable' : 'Disable';
312
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700313 if (useDetails) {
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700314 if (haveDetails) {
315 showDetailPanel();
316 }
317 } else {
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700318 hideDetailPanel();
319 }
Simon Huntee7a3ce2015-04-09 13:28:37 -0700320 flash.flash(verb + ' details panel');
321 return useDetails;
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700322 }
323
Simon Hunt4b668592015-01-29 17:33:53 -0800324 // ==========================
325
Simon Hunt237676b52015-03-10 19:04:26 -0700326 function initPanels() {
Simon Hunt4b668592015-01-29 17:33:53 -0800327 summaryPanel = ps.createPanel(idSum, panelOpts);
328 detailPanel = ps.createPanel(idDet, panelOpts);
Simon Hunt08f841d02015-02-10 14:39:20 -0800329
330 summaryPanel.classed(pCls, true);
331 detailPanel.classed(pCls, true);
Simon Hunt6036b192015-02-11 11:20:26 -0800332
333 augmentDetailPanel();
Simon Hunt4b668592015-01-29 17:33:53 -0800334 }
335
336 function destroyPanels() {
337 ps.destroyPanel(idSum);
338 ps.destroyPanel(idDet);
339 summaryPanel = detailPanel = null;
Simon Hunt626d2102015-01-29 11:54:50 -0800340 }
341
342 // ==========================
343
Simon Huntb0ec1e52015-01-28 18:13:49 -0800344 angular.module('ovTopo')
345 .factory('TopoPanelService',
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700346 ['$log', 'FnService', 'PanelService', 'GlyphService',
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700347 'FlashService', 'WebSocketService', 'ButtonService',
Simon Huntb0ec1e52015-01-28 18:13:49 -0800348
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700349 function (_$log_, _fs_, _ps_, _gs_, _flash_, _wss_, _bns_) {
Simon Huntb0ec1e52015-01-28 18:13:49 -0800350 $log = _$log_;
Simon Hunt6036b192015-02-11 11:20:26 -0800351 fs = _fs_;
Simon Huntb0ec1e52015-01-28 18:13:49 -0800352 ps = _ps_;
Simon Huntc9b73162015-01-29 14:02:15 -0800353 gs = _gs_;
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700354 flash = _flash_;
Simon Hunt237676b52015-03-10 19:04:26 -0700355 wss = _wss_;
Bri Prebilic Colef5e48b12015-04-21 14:52:36 -0700356 bns = _bns_;
Simon Huntb0ec1e52015-01-28 18:13:49 -0800357
Simon Huntb0ec1e52015-01-28 18:13:49 -0800358 return {
359 initPanels: initPanels,
Simon Hunt626d2102015-01-29 11:54:50 -0800360 destroyPanels: destroyPanels,
Simon Hunt08f841d02015-02-10 14:39:20 -0800361
362 showSummary: showSummary,
Simon Hunt6036b192015-02-11 11:20:26 -0800363 toggleSummary: toggleSummary,
Simon Hunt08f841d02015-02-10 14:39:20 -0800364
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700365 toggleDetails: toggleDetails,
Simon Hunt08f841d02015-02-10 14:39:20 -0800366 displaySingle: displaySingle,
367 displayMulti: displayMulti,
368 addAction: addAction,
Simon Hunt0c6b2d32015-03-26 17:46:29 -0700369 displayLink: displayLink,
370 displayNothing: displayNothing,
371 displaySomething: displaySomething,
Simon Hunt08f841d02015-02-10 14:39:20 -0800372
Simon Huntc252aa62015-02-10 16:45:39 -0800373 hideSummaryPanel: hideSummaryPanel,
Simon Hunt08f841d02015-02-10 14:39:20 -0800374
375 detailVisible: function () { return detailPanel.isVisible(); },
376 summaryVisible: function () { return summaryPanel.isVisible(); }
Simon Huntb0ec1e52015-01-28 18:13:49 -0800377 };
378 }]);
379}());