blob: 31c88861da887959d5cfa0322e49772f7f53d44e [file] [log] [blame]
Steven Burrows57e24e92016-08-04 18:38:24 +01001(function () {
2 'use strict';
3
4 // injected refs
5 var $log,
6 ps,
7 sus,
8 gs,
9 ts,
10 fs,
11 flash;
12
13 // api from topo
14 var api;
15
16 // configuration
17 var showLogicErrors = true,
18 idIns = 'topo-p-instance',
19 instOpts = {
20 edge: 'left',
21 width: 20
22 };
23
24 // internal state
25 var onosInstances,
26 onosOrder,
27 oiShowMaster,
28 oiBox;
29
30
31 function addInstance(data) {
32 var id = data.id;
33
34 if (onosInstances[id]) {
35 updateInstance(data);
36 return;
37 }
38 onosInstances[id] = data;
39 onosOrder.push(data);
40 updateInstances();
41 }
42
43 function updateInstance(data) {
44 var id = data.id,
45 d = onosInstances[id];
46 if (d) {
47 angular.extend(d, data);
48 updateInstances();
49 } else {
50 logicError('updateInstance: lookup fail: ID = "' + id + '"');
51 }
52 }
53
54 function removeInstance(data) {
55 var id = data.id,
56 d = onosInstances[id];
57 if (d) {
58 var idx = fs.find(id, onosOrder);
59 if (idx >= 0) {
60 onosOrder.splice(idx, 1);
61 }
62 delete onosInstances[id];
63 updateInstances();
64 } else {
65 logicError('removeInstance lookup fail. ID = "' + id + '"');
66 }
67 }
68
69 // ==========================
70
71 function clickInst(d) {
72 var el = d3.select(this),
73 aff = el.classed('affinity');
74 if (!aff) {
75 setAffinity(el, d);
76 } else {
77 cancelAffinity();
78 }
79 }
80
81 function setAffinity(el, d) {
82 d3.selectAll('.onosInst')
83 .classed('mastership', true)
84 .classed('affinity', false);
85 el.classed('affinity', true);
86
87 // suppress all elements except nodes whose master is this instance
88 api.showMastership(d.id);
89 oiShowMaster = true;
90 }
91
92 function cancelAffinity() {
93 d3.selectAll('.onosInst')
94 .classed('mastership affinity', false);
95
96 api.showMastership(null);
97 oiShowMaster = false;
98 }
99
100 function attachUiBadge(svg) {
101 gs.addGlyph(svg, 'uiAttached', 24, true, [14, 54])
102 .classed('badgeIcon uiBadge', true);
103 }
104
105 function attachReadyBadge(svg) {
106 gs.addGlyph(svg, 'checkMark', 16, true, [18, 40])
107 .classed('badgeIcon readyBadge', true);
108 }
109
110 function instColor(id, online) {
111 return sus.cat7().getColor(id, !online, ts.theme());
112 }
113
114 // ==============================
115
116 function updateInstances() {
117 var rox = 5,
118 roy = 5,
119 rw = 160,
120 rhh = 30,
121 rbh = 45,
122 tx = 48,
123 instSvg = {
124 width: 170,
125 height: 85,
126 viewBox: '0 0 170 85'
127 },
128 headRect = {
129 x: rox,
130 y: roy,
131 width: rw,
132 height: rhh
133 },
134 bodyRect = {
135 x: rox,
136 y: roy + rhh,
137 width: rw,
138 height: rbh
139 },
140 titleAttr = {
141 class: 'instTitle',
142 x: tx,
143 y: 27
144 };
145
146 var onoses = oiBox.el().selectAll('.onosInst')
147 .data(onosOrder, function (d) { return d.id; });
148
149 function nSw(n) {
150 return 'Devices: ' + n;
151 }
152
153 // operate on existing onos instances if necessary
154 onoses.each(function (d) {
155 var el = d3.select(this),
156 svg = el.select('svg');
157
158 // update online state
159 el.classed('online', d.online);
160 el.classed('ready', d.ready);
161
162 // update ui-attached state
163 svg.select('use.uiBadge').remove();
164 if (d.uiAttached) {
165 attachUiBadge(svg);
166 }
167
168 function updAttr(id, value) {
169 svg.select('text.instLabel.' + id).text(value);
170 }
171
172 updAttr('ip', d.ip);
173 updAttr('ns', nSw(d.switches));
174 });
175
176
177 // operate on new onos instances
178 var entering = onoses.enter()
179 .append('div')
180 .classed('onosInst', true)
181 .classed('online', function (d) { return d.online; })
182 .classed('ready', function (d) { return d.ready; })
183 .on('click', clickInst);
184
185 entering.each(function (d) {
186 var el = d3.select(this),
187 svg = el.append('svg').attr(instSvg);
188
189 svg.append('rect').attr(headRect);
190 svg.append('rect').attr(bodyRect);
191
192 gs.addGlyph(svg, 'bird', 20, false, [15, 10])
193 .classed('badgeIcon bird', true);
194
195 attachReadyBadge(svg);
196
197 if (d.uiAttached) {
198 attachUiBadge(svg);
199 }
200
201 svg.append('text')
202 .attr(titleAttr)
203 .text(d.id);
204
205 var ty = 55;
206 function addAttr(id, label) {
207 svg.append('text').attr({
208 class: 'instLabel ' + id,
209 x: tx,
210 y: ty
211 }).text(label);
212 ty += 18;
213 }
214
215 addAttr('ip', d.ip);
216 addAttr('ns', nSw(d.switches));
217 });
218
219 // operate on existing + new onoses here
220 // set the affinity colors...
221 onoses.each(function (d) {
222
223 var el = d3.select(this),
224 rect = el.select('svg').select('rect'),
225 col = instColor(d.id, d.online);
226
227 rect.style('fill', col);
228 });
229
230 // adjust the panel size appropriately...
231 oiBox.width(instSvg.width * onosOrder.length);
232 oiBox.height(instSvg.height);
233
234 // remove any outgoing instances
235 onoses.exit().remove();
236 }
237
238
239 // ==========================
240
241 function logicError(msg) {
242 if (showLogicErrors) {
243 $log.warn('TopoInstService: ' + msg);
244 }
245 }
246
247 function initInst(_api_) {
248 api = _api_;
249 oiBox = ps.createPanel(idIns, instOpts);
250 oiBox.show();
251
252 onosInstances = {};
253 onosOrder = [];
254 oiShowMaster = false;
255
256 // we want to update the instances, each time the theme changes
257 ts.addListener(updateInstances);
258 }
259
260 function destroyInst() {
261 ts.removeListener(updateInstances);
262
263 ps.destroyPanel(idIns);
264 oiBox = null;
265
266 onosInstances = {};
267 onosOrder = [];
268 oiShowMaster = false;
269 }
270
271 function allInstances(data) {
272 $log.debug('Update all instances', data);
273
274 var members = data.members;
275
276 members.forEach(function (member) {
277 addInstance(member);
278 });
279 }
280
281 angular.module('ovTopo2')
282 .factory('Topo2InstanceService',
283 ['$log', 'PanelService', 'SvgUtilService', 'GlyphService',
284 'ThemeService', 'FnService', 'FlashService',
285
286 function (_$log_, _ps_, _sus_, _gs_, _ts_, _fs_, _flash_) {
287 $log = _$log_;
288 ps = _ps_;
289 sus = _sus_;
290 gs = _gs_;
291 ts = _ts_;
292 fs = _fs_;
293 flash = _flash_;
294
295 return {
296 initInst: initInst,
297 allInstances: allInstances
298 };
299 }]);
300
301}());