blob: 99d381c89e168c9b56f00ecfdea0960f0feabb4d [file] [log] [blame]
Simon Hunt4b668592015-01-29 17:33:53 -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 Instances Module.
19 Defines modeling of ONOS instances.
20 */
21
22(function () {
23 'use strict';
24
25 // injected refs
Simon Huntee7a3ce2015-04-09 13:28:37 -070026 var $log, ps, sus, gs, ts, fs, flash;
Simon Hunt4b668592015-01-29 17:33:53 -080027
Simon Hunta142dd22015-02-12 22:07:51 -080028 // api from topo
29 var api;
30 /*
31 showMastership( id )
32 */
33
Simon Hunt4b668592015-01-29 17:33:53 -080034 // configuration
35 var instCfg = {
36 rectPad: 8,
37 nodeOx: 9,
38 nodeOy: 9,
39 nodeDim: 40,
40 birdOx: 19,
41 birdOy: 21,
42 birdDim: 21,
43 uiDy: 45,
44 titleDy: 30,
45 textYOff: 20,
46 textYSpc: 15
47 },
48 showLogicErrors = true,
49 idIns = 'topo-p-instance',
50 instOpts = {
51 edge: 'left',
52 width: 20
53 };
54
55 // internal state
56 var onosInstances,
57 onosOrder,
58 oiShowMaster,
Simon Hunt245a88e2015-02-02 13:26:04 -080059 oiBox,
60 themeListener;
Simon Hunt4b668592015-01-29 17:33:53 -080061
62
63 // ==========================
Simon Hunt4b668592015-01-29 17:33:53 -080064
65 function addInstance(data) {
66 var id = data.id;
67
68 if (onosInstances[id]) {
69 updateInstance(data);
70 return;
71 }
72 onosInstances[id] = data;
73 onosOrder.push(data);
74 updateInstances();
75 }
76
77 function updateInstance(data) {
78 var id = data.id,
79 d = onosInstances[id];
80 if (d) {
81 angular.extend(d, data);
82 updateInstances();
83 } else {
84 logicError('updateInstance: lookup fail: ID = "' + id + '"');
85 }
86 }
87
Simon Hunt48e61672015-01-30 14:48:25 -080088 function removeInstance(data) {
89 var id = data.id,
90 d = onosInstances[id];
91 if (d) {
92 var idx = fs.find(id, onosOrder);
93 if (idx >= 0) {
94 onosOrder.splice(idx, 1);
95 }
96 delete onosInstances[id];
97 updateInstances();
98 } else {
99 logicError('removeInstance lookup fail. ID = "' + id + '"');
100 }
101 }
102
103 // ==========================
104
Simon Hunt4b668592015-01-29 17:33:53 -0800105 function computeDim(self) {
106 var css = window.getComputedStyle(self);
107 return {
108 w: sus.stripPx(css.width),
109 h: sus.stripPx(css.height)
110 };
111 }
112
113 function clickInst(d) {
114 var el = d3.select(this),
115 aff = el.classed('affinity');
116 if (!aff) {
117 setAffinity(el, d);
118 } else {
119 cancelAffinity();
120 }
121 }
122
123 function setAffinity(el, d) {
124 d3.selectAll('.onosInst')
125 .classed('mastership', true)
126 .classed('affinity', false);
127 el.classed('affinity', true);
128
Simon Hunta142dd22015-02-12 22:07:51 -0800129 // suppress all elements except nodes whose master is this instance
130 api.showMastership(d.id);
Simon Hunt4b668592015-01-29 17:33:53 -0800131 oiShowMaster = true;
132 }
133
134 function cancelAffinity() {
135 d3.selectAll('.onosInst')
136 .classed('mastership affinity', false);
137
Simon Hunta142dd22015-02-12 22:07:51 -0800138 api.showMastership(null);
Simon Hunt4b668592015-01-29 17:33:53 -0800139 oiShowMaster = false;
140 }
141
142 function instRectAttr(dim) {
143 var pad = instCfg.rectPad;
144 return {
145 x: pad,
146 y: pad,
147 width: dim.w - pad*2,
148 height: dim.h - pad*2,
149 rx: 6
150 };
151 }
152
153 function viewBox(dim) {
154 return '0 0 ' + dim.w + ' ' + dim.h;
155 }
156
157 function attachUiBadge(svg) {
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700158 gs.addGlyph(svg, 'uiAttached', 24, true, [28, instCfg.uiDy])
Simon Hunt4b668592015-01-29 17:33:53 -0800159 .classed('badgeIcon uiBadge', true);
160 }
161
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700162 function attachReadyBadge(svg) {
163 gs.addGlyph(svg, 'checkMark', 16, true, [12, instCfg.uiDy + 4])
164 .classed('badgeIcon readyBadge', true);
165 }
166
Simon Hunt4b668592015-01-29 17:33:53 -0800167 function instColor(id, online) {
Simon Hunt48e61672015-01-30 14:48:25 -0800168 return sus.cat7().getColor(id, !online, ts.theme());
Simon Hunt4b668592015-01-29 17:33:53 -0800169 }
170
171 // ==============================
172
173 function updateInstances() {
174 var onoses = oiBox.el().selectAll('.onosInst')
175 .data(onosOrder, function (d) { return d.id; }),
176 instDim = {w:0,h:0},
177 c = instCfg;
178
179 function nSw(n) {
180 return '# Switches: ' + n;
181 }
182
183 // operate on existing onos instances if necessary
184 onoses.each(function (d) {
185 var el = d3.select(this),
186 svg = el.select('svg');
187 instDim = computeDim(this);
188
189 // update online state
190 el.classed('online', d.online);
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700191 el.classed('notReady', !d.ready);
Simon Hunt4b668592015-01-29 17:33:53 -0800192
193 // update ui-attached state
194 svg.select('use.uiBadge').remove();
195 if (d.uiAttached) {
196 attachUiBadge(svg);
197 }
198
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700199 attachReadyBadge(svg, d.ready);
200
Simon Hunt4b668592015-01-29 17:33:53 -0800201 function updAttr(id, value) {
202 svg.select('text.instLabel.'+id).text(value);
203 }
204
205 updAttr('ip', d.ip);
206 updAttr('ns', nSw(d.switches));
207 });
208
209
210 // operate on new onos instances
211 var entering = onoses.enter()
212 .append('div')
213 .attr('class', 'onosInst')
214 .classed('online', function (d) { return d.online; })
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700215 .classed('notReady', function (d) { return !d.ready; })
Simon Hunt4b668592015-01-29 17:33:53 -0800216 .on('click', clickInst);
217
218 entering.each(function (d) {
219 var el = d3.select(this),
220 rectAttr,
221 svg;
222 instDim = computeDim(this);
223 rectAttr = instRectAttr(instDim);
224
225 svg = el.append('svg').attr({
226 width: instDim.w,
227 height: instDim.h,
228 viewBox: viewBox(instDim)
229 });
230
231 svg.append('rect').attr(rectAttr);
232
233 gs.addGlyph(svg, 'bird', 28, true, [14, 14])
234 .classed('badgeIcon', true);
235
236 if (d.uiAttached) {
237 attachUiBadge(svg);
238 }
239
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700240 attachReadyBadge(svg);
241
Simon Hunt4b668592015-01-29 17:33:53 -0800242 var left = c.nodeOx + c.nodeDim,
243 len = rectAttr.width - left,
244 hlen = len / 2,
245 midline = hlen + left;
246
247 // title
248 svg.append('text')
249 .attr({
250 class: 'instTitle',
251 x: midline,
252 y: c.titleDy
253 })
254 .text(d.id);
255
256 // a couple of attributes
257 var ty = c.titleDy + c.textYOff;
258
259 function addAttr(id, label) {
260 svg.append('text').attr({
261 class: 'instLabel ' + id,
262 x: midline,
263 y: ty
264 }).text(label);
265 ty += c.textYSpc;
266 }
267
268 addAttr('ip', d.ip);
269 addAttr('ns', nSw(d.switches));
270 });
271
272 // operate on existing + new onoses here
273 // set the affinity colors...
274 onoses.each(function (d) {
275 var el = d3.select(this),
276 rect = el.select('svg').select('rect'),
277 col = instColor(d.id, d.online);
278 rect.style('fill', col);
279 });
280
281 // adjust the panel size appropriately...
282 oiBox.width(instDim.w * onosOrder.length);
283 oiBox.height(instDim.h);
284
285 // remove any outgoing instances
286 onoses.exit().remove();
287 }
288
289
290 // ==========================
291
292 function logicError(msg) {
293 if (showLogicErrors) {
294 $log.warn('TopoInstService: ' + msg);
295 }
296 }
297
Simon Hunta142dd22015-02-12 22:07:51 -0800298 function initInst(_api_) {
299 api = _api_;
Simon Hunt4b668592015-01-29 17:33:53 -0800300 oiBox = ps.createPanel(idIns, instOpts);
301 oiBox.show();
302
303 onosInstances = {};
304 onosOrder = [];
305 oiShowMaster = false;
Simon Hunt245a88e2015-02-02 13:26:04 -0800306
307 // we want to update the instances, each time the theme changes
308 themeListener = ts.addListener(updateInstances);
Simon Hunt4b668592015-01-29 17:33:53 -0800309 }
310
311 function destroyInst() {
Simon Hunt245a88e2015-02-02 13:26:04 -0800312 ts.removeListener(themeListener);
313 themeListener = null;
314
Simon Hunt4b668592015-01-29 17:33:53 -0800315 ps.destroyPanel(idIns);
316 oiBox = null;
Simon Hunt3ab20282015-02-26 20:32:19 -0800317
318 onosInstances = {};
319 onosOrder = [];
320 oiShowMaster = false;
Simon Hunt4b668592015-01-29 17:33:53 -0800321 }
322
Simon Huntee7a3ce2015-04-09 13:28:37 -0700323 function showInsts() {
324 oiBox.show();
325 }
326
327 function hideInsts() {
328 oiBox.hide();
329 }
330
331 function toggleInsts(x) {
332 var kev = (x === 'keyev'),
333 on,
334 verb;
335
336 if (kev) {
337 on = oiBox.toggle();
338 } else {
339 on = !!x;
340 if (on) {
341 showInsts();
342 } else {
343 hideInsts();
344 }
345 }
346 verb = on ? 'Show' : 'Hide';
347 flash.flash(verb + ' instances panel');
348 return on;
349 }
350
Simon Hunt4b668592015-01-29 17:33:53 -0800351 // ==========================
352
353 angular.module('ovTopo')
354 .factory('TopoInstService',
355 ['$log', 'PanelService', 'SvgUtilService', 'GlyphService',
Simon Huntee7a3ce2015-04-09 13:28:37 -0700356 'ThemeService', 'FnService', 'FlashService',
Simon Hunt4b668592015-01-29 17:33:53 -0800357
Simon Huntee7a3ce2015-04-09 13:28:37 -0700358 function (_$log_, _ps_, _sus_, _gs_, _ts_, _fs_, _flash_) {
Simon Hunt4b668592015-01-29 17:33:53 -0800359 $log = _$log_;
360 ps = _ps_;
361 sus = _sus_;
362 gs = _gs_;
Simon Hunt48e61672015-01-30 14:48:25 -0800363 ts = _ts_;
364 fs = _fs_;
Simon Huntee7a3ce2015-04-09 13:28:37 -0700365 flash = _flash_;
Simon Hunt4b668592015-01-29 17:33:53 -0800366
367 return {
368 initInst: initInst,
369 destroyInst: destroyInst,
Simon Hunt1894d792015-02-04 17:09:20 -0800370
Simon Hunt48e61672015-01-30 14:48:25 -0800371 addInstance: addInstance,
372 updateInstance: updateInstance,
Simon Huntac4c6f72015-02-03 19:50:53 -0800373 removeInstance: removeInstance,
Simon Hunt1894d792015-02-04 17:09:20 -0800374
Simon Hunta142dd22015-02-12 22:07:51 -0800375 cancelAffinity: cancelAffinity,
376
Simon Huntac4c6f72015-02-03 19:50:53 -0800377 isVisible: function () { return oiBox.isVisible(); },
Simon Huntee7a3ce2015-04-09 13:28:37 -0700378 show: showInsts,
379 hide: hideInsts,
380 toggle: toggleInsts,
Simon Hunta142dd22015-02-12 22:07:51 -0800381 showMaster: function () { return oiShowMaster; }
Simon Hunt4b668592015-01-29 17:33:53 -0800382 };
383 }]);
384}());