GUI -- Re-instated Packet / Optical Layer filters.
- Adding ONOS instance fly-in pane. Note: still WIP. - refactored onos.ui.addFloatingPanel to allow TL vs. TR. - added instance pane to topo view. - implemented addInstance() event. - refactored event tracing. - added instances test scenario. Change-Id: I58d9769afa8aee9079ec778496cbc47bef329608
Showing
21 changed files
with
494 additions
and
56 deletions
1 | +{ | ||
2 | + "event": "addLink", | ||
3 | + "payload": { | ||
4 | + "id": "of:0000ffffffff0003/4-of:0000ffffffffff03/1", | ||
5 | + "type": "pktopt", | ||
6 | + "linkWidth": 2, | ||
7 | + "src": "of:0000ffffffff0003", | ||
8 | + "srcPort": "4", | ||
9 | + "dst": "of:0000ffffffffff03", | ||
10 | + "dstPort": "1", | ||
11 | + "props" : { | ||
12 | + "BW": "90 Gb" | ||
13 | + } | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "event": "addLink", | ||
3 | + "payload": { | ||
4 | + "id": "of:0000ffffffff0003/9-of:0000ffffffff0007/2", | ||
5 | + "type": "direct", | ||
6 | + "linkWidth": 2, | ||
7 | + "src": "of:0000ffffffff0003", | ||
8 | + "srcPort": "9", | ||
9 | + "dst": "of:0000ffffffff0007", | ||
10 | + "dstPort": "2", | ||
11 | + "props" : { | ||
12 | + "BW": "120 Gb" | ||
13 | + } | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "event": "addLink", | ||
3 | + "payload": { | ||
4 | + "id": "of:0000ffffffff0008/2-of:0000ffffffff0003/1", | ||
5 | + "type": "direct", | ||
6 | + "linkWidth": 2, | ||
7 | + "src": "of:0000ffffffff0008", | ||
8 | + "srcPort": "2", | ||
9 | + "dst": "of:0000ffffffff0003", | ||
10 | + "dstPort": "1", | ||
11 | + "props" : { | ||
12 | + "BW": "70 Gb" | ||
13 | + } | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "event": "addLink", | ||
3 | + "payload": { | ||
4 | + "id": "of:0000ffffffff0008/4-of:0000ffffffff0007/1", | ||
5 | + "type": "direct", | ||
6 | + "linkWidth": 2, | ||
7 | + "src": "of:0000ffffffff0008", | ||
8 | + "srcPort": "4", | ||
9 | + "dst": "of:0000ffffffff0007", | ||
10 | + "dstPort": "1", | ||
11 | + "props" : { | ||
12 | + "BW": "90 Gb" | ||
13 | + } | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "event": "addLink", | ||
3 | + "payload": { | ||
4 | + "id": "of:0000ffffffffff08/4-of:0000ffffffffff03/1", | ||
5 | + "type": "optical", | ||
6 | + "linkWidth": 2, | ||
7 | + "src": "of:0000ffffffffff08", | ||
8 | + "srcPort": "4", | ||
9 | + "dst": "of:0000ffffffffff03", | ||
10 | + "dstPort": "1", | ||
11 | + "props" : { | ||
12 | + "BW": "90 Gb" | ||
13 | + } | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "event": "addHost", | ||
3 | + "payload": { | ||
4 | + "id": "0E:2A:69:30:13:aa/-1", | ||
5 | + "ingress": "0E:2A:69:30:13:aa/-1/0-of:0000ffffffff0008/101", | ||
6 | + "egress": "of:0000ffffffff0008/101-0E:2A:69:30:13:aa/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000ffffffff0008", | ||
9 | + "port": 101 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "12.13.14.15", | ||
13 | + "0E:2A:69:30:13:aa" | ||
14 | + ], | ||
15 | + "props": {} | ||
16 | + } | ||
17 | +} |
1 | +{ | ||
2 | + "event": "addHost", | ||
3 | + "payload": { | ||
4 | + "id": "0E:2A:69:30:13:88/-1", | ||
5 | + "ingress": "0E:2A:69:30:13:88/-1/0-of:0000ffffffff0007/101", | ||
6 | + "egress": "of:0000ffffffff0007/101-0E:2A:69:30:13:86/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000ffffffff0007", | ||
9 | + "port": 101 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "4.5.7.6", | ||
13 | + "0E:2A:69:30:13:88" | ||
14 | + ], | ||
15 | + "props": {} | ||
16 | + } | ||
17 | +} |
1 | +{ | ||
2 | + "event": "addHost", | ||
3 | + "payload": { | ||
4 | + "id": "0E:2A:69:30:13:86/-1", | ||
5 | + "ingress": "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/101", | ||
6 | + "egress": "of:0000ffffffff0003/101-0E:2A:69:30:13:86/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000ffffffff0003", | ||
9 | + "port": 101 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "1.2.3.4", | ||
13 | + "0E:2A:69:30:13:86" | ||
14 | + ], | ||
15 | + "props": {} | ||
16 | + } | ||
17 | +} |
1 | +{ | ||
2 | + "event": "addLink", | ||
3 | + "payload": { | ||
4 | + "id": "of:0000ffffffff0008/4-of:0000ffffffffff08/1", | ||
5 | + "type": "pktopt", | ||
6 | + "linkWidth": 2, | ||
7 | + "src": "of:0000ffffffff0008", | ||
8 | + "srcPort": "4", | ||
9 | + "dst": "of:0000ffffffffff08", | ||
10 | + "dstPort": "1", | ||
11 | + "props" : { | ||
12 | + "BW": "90 Gb" | ||
13 | + } | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "comments": [ | ||
3 | + "Developing ONOS instance visualization" | ||
4 | + ], | ||
5 | + "title": "ONOS Instance Scenario", | ||
6 | + "params": { | ||
7 | + "lastAuto": 17 | ||
8 | + }, | ||
9 | + "description": [ | ||
10 | + "Visualizing ONOS instances.", | ||
11 | + "", | ||
12 | + "Press 'S' to load initial events.", | ||
13 | + "", | ||
14 | + "Press spacebar to complete the scenario..." | ||
15 | + ] | ||
16 | +} |
... | @@ -699,6 +699,16 @@ | ... | @@ -699,6 +699,16 @@ |
699 | // .......................................................... | 699 | // .......................................................... |
700 | // UI API | 700 | // UI API |
701 | 701 | ||
702 | + var fpConfig = { | ||
703 | + TR: { | ||
704 | + side: 'right' | ||
705 | + | ||
706 | + }, | ||
707 | + TL: { | ||
708 | + side: 'left' | ||
709 | + } | ||
710 | + }; | ||
711 | + | ||
702 | uiApi = { | 712 | uiApi = { |
703 | addLib: function (libName, api) { | 713 | addLib: function (libName, api) { |
704 | // TODO: validation of args | 714 | // TODO: validation of args |
... | @@ -713,6 +723,7 @@ | ... | @@ -713,6 +723,7 @@ |
713 | */ | 723 | */ |
714 | addFloatingPanel: function (id, position) { | 724 | addFloatingPanel: function (id, position) { |
715 | var pos = position || 'TR', | 725 | var pos = position || 'TR', |
726 | + cfg = fpConfig[pos], | ||
716 | el, | 727 | el, |
717 | fp; | 728 | fp; |
718 | 729 | ||
... | @@ -723,22 +734,37 @@ | ... | @@ -723,22 +734,37 @@ |
723 | 734 | ||
724 | el = $floatPanels.append('div') | 735 | el = $floatPanels.append('div') |
725 | .attr('id', id) | 736 | .attr('id', id) |
726 | - .attr('class', 'fpanel'); | 737 | + .attr('class', 'fpanel') |
738 | + .style('opacity', 0); | ||
739 | + | ||
740 | + // has to be called after el is set. | ||
741 | + el.style(cfg.side, pxHide()); | ||
742 | + | ||
743 | + function pxShow() { | ||
744 | + return '20px'; | ||
745 | + } | ||
746 | + function pxHide() { | ||
747 | + return (-20 - widthVal()) + 'px'; | ||
748 | + } | ||
749 | + function widthVal() { | ||
750 | + return el.style('width').replace(/px$/, ''); | ||
751 | + } | ||
727 | 752 | ||
728 | fp = { | 753 | fp = { |
729 | id: id, | 754 | id: id, |
730 | el: el, | 755 | el: el, |
731 | pos: pos, | 756 | pos: pos, |
757 | + | ||
732 | show: function () { | 758 | show: function () { |
733 | console.log('show pane: ' + id); | 759 | console.log('show pane: ' + id); |
734 | el.transition().duration(750) | 760 | el.transition().duration(750) |
735 | - .style('right', '20px') | 761 | + .style(cfg.side, pxShow()) |
736 | .style('opacity', 1); | 762 | .style('opacity', 1); |
737 | }, | 763 | }, |
738 | hide: function () { | 764 | hide: function () { |
739 | console.log('hide pane: ' + id); | 765 | console.log('hide pane: ' + id); |
740 | el.transition().duration(750) | 766 | el.transition().duration(750) |
741 | - .style('right', '-320px') | 767 | + .style(cfg.side, pxHide()) |
742 | .style('opacity', 0); | 768 | .style('opacity', 0); |
743 | }, | 769 | }, |
744 | empty: function () { | 770 | empty: function () { |
... | @@ -746,6 +772,12 @@ | ... | @@ -746,6 +772,12 @@ |
746 | }, | 772 | }, |
747 | append: function (what) { | 773 | append: function (what) { |
748 | return el.append(what); | 774 | return el.append(what); |
775 | + }, | ||
776 | + width: function (w) { | ||
777 | + if (w === undefined) { | ||
778 | + return widthVal(); | ||
779 | + } | ||
780 | + el.style('width', w); | ||
749 | } | 781 | } |
750 | }; | 782 | }; |
751 | fpanels[id] = fp; | 783 | fpanels[id] = fp; | ... | ... |
... | @@ -197,6 +197,39 @@ | ... | @@ -197,6 +197,39 @@ |
197 | border: 0; | 197 | border: 0; |
198 | } | 198 | } |
199 | 199 | ||
200 | +/* ONOS instance stuff */ | ||
201 | + | ||
202 | +#topo-oibox { | ||
203 | + width: 80px; | ||
204 | +} | ||
205 | + | ||
206 | +#topo-oibox .onosInst { | ||
207 | + margin: 6px 0; | ||
208 | + padding: 3px; | ||
209 | + width: 80%; | ||
210 | + left: 10%; | ||
211 | + height: 40px; | ||
212 | + cursor: pointer; | ||
213 | + | ||
214 | + /* theme-related */ | ||
215 | + color: #444; | ||
216 | + background-color: #ccc; | ||
217 | + border: 2px dashed #aaa; | ||
218 | +} | ||
219 | + | ||
220 | + | ||
221 | +#topo-oibox .onosInst.online { | ||
222 | + /* theme-related */ | ||
223 | + color: #113; | ||
224 | + background-color: #bbf; | ||
225 | + border: 2px solid #555; | ||
226 | +} | ||
227 | + | ||
228 | +#topo svg .suppressed, | ||
229 | +#topo-oibox .suppressed { | ||
230 | + opacity: 0.2; | ||
231 | +} | ||
232 | + | ||
200 | /* Web Socket Closed Mask (starts hidden) */ | 233 | /* Web Socket Closed Mask (starts hidden) */ |
201 | 234 | ||
202 | #topo-mask { | 235 | #topo-mask { | ... | ... |
... | @@ -155,11 +155,14 @@ | ... | @@ -155,11 +155,14 @@ |
155 | sid = 0, | 155 | sid = 0, |
156 | deviceLabelIndex = 0, | 156 | deviceLabelIndex = 0, |
157 | hostLabelIndex = 0, | 157 | hostLabelIndex = 0, |
158 | - detailPane, | ||
159 | - selectOrder = [], | ||
160 | selections = {}, | 158 | selections = {}, |
159 | + selectOrder = [], | ||
161 | hovered = null, | 160 | hovered = null, |
161 | + detailPane, | ||
162 | antTimer = null, | 162 | antTimer = null, |
163 | + onosInstances = {}, | ||
164 | + onosOrder = [], | ||
165 | + oiBox, | ||
163 | 166 | ||
164 | viewMode = 'showAll', | 167 | viewMode = 'showAll', |
165 | portLabelsOn = false; | 168 | portLabelsOn = false; |
... | @@ -198,11 +201,19 @@ | ... | @@ -198,11 +201,19 @@ |
198 | } | 201 | } |
199 | } | 202 | } |
200 | 203 | ||
204 | + function evTrace(data) { | ||
205 | + fnTrace(data.event, data.payload.id); | ||
206 | + } | ||
207 | + | ||
201 | // ============================== | 208 | // ============================== |
202 | // Key Callbacks | 209 | // Key Callbacks |
203 | 210 | ||
204 | function testMe(view) { | 211 | function testMe(view) { |
205 | - view.alert('test'); | 212 | + //view.alert('test'); |
213 | + detailPane.show(); | ||
214 | + setTimeout(detailPane.hide, 2000); | ||
215 | + oiBox.show(); | ||
216 | + setTimeout(oiBox.hide, 2000); | ||
206 | } | 217 | } |
207 | 218 | ||
208 | function abortIfLive() { | 219 | function abortIfLive() { |
... | @@ -303,25 +314,61 @@ | ... | @@ -303,25 +314,61 @@ |
303 | // ============================== | 314 | // ============================== |
304 | // Radio Button Callbacks | 315 | // Radio Button Callbacks |
305 | 316 | ||
317 | + var layerLookup = { | ||
318 | + host: { | ||
319 | + endstation: 'pkt', // default, if host event does not define type | ||
320 | + bgpSpeaker: 'pkt' | ||
321 | + }, | ||
322 | + device: { | ||
323 | + switch: 'pkt', | ||
324 | + roadm: 'opt' | ||
325 | + }, | ||
326 | + link: { | ||
327 | + hostLink: 'pkt', | ||
328 | + direct: 'pkt', | ||
329 | + optical: 'opt' | ||
330 | + } | ||
331 | + }; | ||
332 | + | ||
333 | + function inLayer(d, layer) { | ||
334 | + var look = layerLookup[d.class], | ||
335 | + lyr = look && look[d.type]; | ||
336 | + return lyr === layer; | ||
337 | + } | ||
338 | + | ||
339 | + function unsuppressLayer(which) { | ||
340 | + node.each(function (d) { | ||
341 | + var node = d.el; | ||
342 | + if (inLayer(d, which)) { | ||
343 | + node.classed('suppressed', false); | ||
344 | + } | ||
345 | + }); | ||
346 | + | ||
347 | + link.each(function (d) { | ||
348 | + var link = d.el; | ||
349 | + if (inLayer(d, which)) { | ||
350 | + link.classed('suppressed', false); | ||
351 | + } | ||
352 | + }); | ||
353 | + } | ||
354 | + | ||
306 | function showAllLayers() { | 355 | function showAllLayers() { |
307 | -// network.node.classed('inactive', false); | 356 | + node.classed('suppressed', false); |
308 | -// network.link.classed('inactive', false); | 357 | + link.classed('suppressed', false); |
309 | // d3.selectAll('svg .port').classed('inactive', false); | 358 | // d3.selectAll('svg .port').classed('inactive', false); |
310 | // d3.selectAll('svg .portText').classed('inactive', false); | 359 | // d3.selectAll('svg .portText').classed('inactive', false); |
311 | - // TODO ... | ||
312 | - network.view.alert('showAllLayers() callback'); | ||
313 | } | 360 | } |
314 | 361 | ||
315 | function showPacketLayer() { | 362 | function showPacketLayer() { |
316 | - showAllLayers(); | 363 | + node.classed('suppressed', true); |
317 | - // TODO ... | 364 | + link.classed('suppressed', true); |
318 | - network.view.alert('showPacketLayer() callback'); | 365 | + unsuppressLayer('pkt'); |
319 | } | 366 | } |
320 | 367 | ||
321 | function showOpticalLayer() { | 368 | function showOpticalLayer() { |
322 | - showAllLayers(); | 369 | + node.classed('suppressed', true); |
323 | - // TODO ... | 370 | + link.classed('suppressed', true); |
324 | - network.view.alert('showOpticalLayer() callback'); | 371 | + unsuppressLayer('opt'); |
325 | } | 372 | } |
326 | 373 | ||
327 | // ============================== | 374 | // ============================== |
... | @@ -351,7 +398,7 @@ | ... | @@ -351,7 +398,7 @@ |
351 | } | 398 | } |
352 | 399 | ||
353 | var eventDispatch = { | 400 | var eventDispatch = { |
354 | - addInstance: stillToImplement, | 401 | + addInstance: addInstance, |
355 | addDevice: addDevice, | 402 | addDevice: addDevice, |
356 | addLink: addLink, | 403 | addLink: addLink, |
357 | addHost: addHost, | 404 | addHost: addHost, |
... | @@ -371,8 +418,21 @@ | ... | @@ -371,8 +418,21 @@ |
371 | showTraffic: showTraffic | 418 | showTraffic: showTraffic |
372 | }; | 419 | }; |
373 | 420 | ||
421 | + function addInstance(data) { | ||
422 | + evTrace(data); | ||
423 | + var inst = data.payload, | ||
424 | + id = inst.id; | ||
425 | + if (onosInstances[id]) { | ||
426 | + logicError('ONOS instance already added: ' + id); | ||
427 | + return; | ||
428 | + } | ||
429 | + onosInstances[id] = inst; | ||
430 | + onosOrder.push(inst); | ||
431 | + updateInstances(); | ||
432 | + } | ||
433 | + | ||
374 | function addDevice(data) { | 434 | function addDevice(data) { |
375 | - fnTrace('addDevice', data.payload.id); | 435 | + evTrace(data); |
376 | var device = data.payload, | 436 | var device = data.payload, |
377 | nodeData = createDeviceNode(device); | 437 | nodeData = createDeviceNode(device); |
378 | network.nodes.push(nodeData); | 438 | network.nodes.push(nodeData); |
... | @@ -382,7 +442,7 @@ | ... | @@ -382,7 +442,7 @@ |
382 | } | 442 | } |
383 | 443 | ||
384 | function addLink(data) { | 444 | function addLink(data) { |
385 | - fnTrace('addLink', data.payload.id); | 445 | + evTrace(data); |
386 | var link = data.payload, | 446 | var link = data.payload, |
387 | lnk = createLink(link); | 447 | lnk = createLink(link); |
388 | if (lnk) { | 448 | if (lnk) { |
... | @@ -394,7 +454,7 @@ | ... | @@ -394,7 +454,7 @@ |
394 | } | 454 | } |
395 | 455 | ||
396 | function addHost(data) { | 456 | function addHost(data) { |
397 | - fnTrace('addHost', data.payload.id); | 457 | + evTrace(data); |
398 | var host = data.payload, | 458 | var host = data.payload, |
399 | node = createHostNode(host), | 459 | node = createHostNode(host), |
400 | lnk; | 460 | lnk; |
... | @@ -415,7 +475,7 @@ | ... | @@ -415,7 +475,7 @@ |
415 | 475 | ||
416 | // TODO: fold updateX(...) methods into one base method; remove duplication | 476 | // TODO: fold updateX(...) methods into one base method; remove duplication |
417 | function updateDevice(data) { | 477 | function updateDevice(data) { |
418 | - fnTrace('updateDevice', data.payload.id); | 478 | + evTrace(data); |
419 | var device = data.payload, | 479 | var device = data.payload, |
420 | id = device.id, | 480 | id = device.id, |
421 | nodeData = network.lookup[id]; | 481 | nodeData = network.lookup[id]; |
... | @@ -428,7 +488,7 @@ | ... | @@ -428,7 +488,7 @@ |
428 | } | 488 | } |
429 | 489 | ||
430 | function updateLink(data) { | 490 | function updateLink(data) { |
431 | - fnTrace('updateLink', data.payload.id); | 491 | + evTrace(data); |
432 | var link = data.payload, | 492 | var link = data.payload, |
433 | id = link.id, | 493 | id = link.id, |
434 | linkData = network.lookup[id]; | 494 | linkData = network.lookup[id]; |
... | @@ -441,7 +501,7 @@ | ... | @@ -441,7 +501,7 @@ |
441 | } | 501 | } |
442 | 502 | ||
443 | function updateHost(data) { | 503 | function updateHost(data) { |
444 | - fnTrace('updateHost', data.payload.id); | 504 | + evTrace(data); |
445 | var host = data.payload, | 505 | var host = data.payload, |
446 | id = host.id, | 506 | id = host.id, |
447 | hostData = network.lookup[id]; | 507 | hostData = network.lookup[id]; |
... | @@ -455,7 +515,7 @@ | ... | @@ -455,7 +515,7 @@ |
455 | 515 | ||
456 | // TODO: fold removeX(...) methods into base method - remove dup code | 516 | // TODO: fold removeX(...) methods into base method - remove dup code |
457 | function removeLink(data) { | 517 | function removeLink(data) { |
458 | - fnTrace('removeLink', data.payload.id); | 518 | + evTrace(data); |
459 | var link = data.payload, | 519 | var link = data.payload, |
460 | id = link.id, | 520 | id = link.id, |
461 | linkData = network.lookup[id]; | 521 | linkData = network.lookup[id]; |
... | @@ -467,7 +527,7 @@ | ... | @@ -467,7 +527,7 @@ |
467 | } | 527 | } |
468 | 528 | ||
469 | function removeHost(data) { | 529 | function removeHost(data) { |
470 | - fnTrace('removeHost', data.payload.id); | 530 | + evTrace(data); |
471 | var host = data.payload, | 531 | var host = data.payload, |
472 | id = host.id, | 532 | id = host.id, |
473 | hostData = network.lookup[id]; | 533 | hostData = network.lookup[id]; |
... | @@ -479,14 +539,14 @@ | ... | @@ -479,14 +539,14 @@ |
479 | } | 539 | } |
480 | 540 | ||
481 | function showDetails(data) { | 541 | function showDetails(data) { |
482 | - fnTrace('showDetails', data.payload.id); | 542 | + evTrace(data); |
483 | populateDetails(data.payload); | 543 | populateDetails(data.payload); |
484 | detailPane.show(); | 544 | detailPane.show(); |
485 | } | 545 | } |
486 | 546 | ||
487 | function showPath(data) { | 547 | function showPath(data) { |
488 | // TODO: review - making sure we are handling the payload correctly. | 548 | // TODO: review - making sure we are handling the payload correctly. |
489 | - fnTrace('showPath', data.payload.id); | 549 | + evTrace(data); |
490 | var links = data.payload.links, | 550 | var links = data.payload.links, |
491 | s = [ data.event + "\n" + links.length ]; | 551 | s = [ data.event + "\n" + links.length ]; |
492 | links.forEach(function (d, i) { | 552 | links.forEach(function (d, i) { |
... | @@ -503,7 +563,7 @@ | ... | @@ -503,7 +563,7 @@ |
503 | } | 563 | } |
504 | 564 | ||
505 | function showTraffic(data) { | 565 | function showTraffic(data) { |
506 | - fnTrace('showTraffic', data.payload.id); | 566 | + evTrace(data); |
507 | var paths = data.payload.paths; | 567 | var paths = data.payload.paths; |
508 | 568 | ||
509 | // Revert any links hilighted previously. | 569 | // Revert any links hilighted previously. |
... | @@ -602,6 +662,30 @@ | ... | @@ -602,6 +662,30 @@ |
602 | 662 | ||
603 | 663 | ||
604 | // ============================== | 664 | // ============================== |
665 | + // onos instance panel functions | ||
666 | + | ||
667 | + function updateInstances() { | ||
668 | + var onoses = oiBox.el.selectAll('.onosInst') | ||
669 | + .data(onosOrder, function (d) { return d.id; }); | ||
670 | + | ||
671 | + // operate on existing onoses if necessary | ||
672 | + | ||
673 | + var entering = onoses.enter() | ||
674 | + .append('div') | ||
675 | + .attr('class', 'onosInst') | ||
676 | + .classed('online', function (d) { return d.online; }) | ||
677 | + .text(function (d) { return d.id; }); | ||
678 | + | ||
679 | + // operate on existing + new onoses here | ||
680 | + | ||
681 | + // the departed... | ||
682 | + var exiting = onoses.exit() | ||
683 | + .transition() | ||
684 | + .style('opacity', 0) | ||
685 | + .remove(); | ||
686 | + } | ||
687 | + | ||
688 | + // ============================== | ||
605 | // force layout modification functions | 689 | // force layout modification functions |
606 | 690 | ||
607 | function translate(x, y) { | 691 | function translate(x, y) { |
... | @@ -760,11 +844,9 @@ | ... | @@ -760,11 +844,9 @@ |
760 | // Augment as needed... | 844 | // Augment as needed... |
761 | node.class = 'host'; | 845 | node.class = 'host'; |
762 | if (!node.type) { | 846 | if (!node.type) { |
763 | - // TODO: perhaps type would be: {phone, tablet, laptop, endstation} ? | ||
764 | node.type = 'endstation'; | 847 | node.type = 'endstation'; |
765 | } | 848 | } |
766 | node.svgClass = 'node host'; | 849 | node.svgClass = 'node host'; |
767 | - // TODO: consider placing near its switch, if [x,y] not defined | ||
768 | positionNode(node); | 850 | positionNode(node); |
769 | 851 | ||
770 | // cache label array length | 852 | // cache label array length |
... | @@ -1352,21 +1434,21 @@ | ... | @@ -1352,21 +1434,21 @@ |
1352 | function addSingleSelectActions() { | 1434 | function addSingleSelectActions() { |
1353 | detailPane.append('hr'); | 1435 | detailPane.append('hr'); |
1354 | // always want to allow 'show traffic' | 1436 | // always want to allow 'show traffic' |
1355 | - addAction('Show Traffic', showTrafficAction); | 1437 | + addAction(detailPane, 'Show Traffic', showTrafficAction); |
1356 | } | 1438 | } |
1357 | 1439 | ||
1358 | function addMultiSelectActions() { | 1440 | function addMultiSelectActions() { |
1359 | detailPane.append('hr'); | 1441 | detailPane.append('hr'); |
1360 | // always want to allow 'show traffic' | 1442 | // always want to allow 'show traffic' |
1361 | - addAction('Show Traffic', showTrafficAction); | 1443 | + addAction(detailPane, 'Show Traffic', showTrafficAction); |
1362 | // if exactly two hosts are selected, also want 'add host intent' | 1444 | // if exactly two hosts are selected, also want 'add host intent' |
1363 | if (nSel() === 2 && allSelectionsClass('host')) { | 1445 | if (nSel() === 2 && allSelectionsClass('host')) { |
1364 | - addAction('Add Host Intent', addIntentAction); | 1446 | + addAction(detailPane, 'Add Host Intent', addIntentAction); |
1365 | } | 1447 | } |
1366 | } | 1448 | } |
1367 | 1449 | ||
1368 | - function addAction(text, cb) { | 1450 | + function addAction(panel, text, cb) { |
1369 | - detailPane.append('div') | 1451 | + panel.append('div') |
1370 | .classed('actionBtn', true) | 1452 | .classed('actionBtn', true) |
1371 | .text(text) | 1453 | .text(text) |
1372 | .on('click', cb); | 1454 | .on('click', cb); |
... | @@ -1441,40 +1523,53 @@ | ... | @@ -1441,40 +1523,53 @@ |
1441 | // TODO: toggle button (and other widgets in the masthead) should be provided | 1523 | // TODO: toggle button (and other widgets in the masthead) should be provided |
1442 | // by the framework; not generated by the view. | 1524 | // by the framework; not generated by the view. |
1443 | 1525 | ||
1444 | - var showTrafficOnHover, | 1526 | + var showInstances, |
1445 | - doPanZoom; | 1527 | + doPanZoom, |
1528 | + showTrafficOnHover; | ||
1446 | 1529 | ||
1447 | function addButtonBar(view) { | 1530 | function addButtonBar(view) { |
1448 | var bb = d3.select('#mast') | 1531 | var bb = d3.select('#mast') |
1449 | .append('span').classed('right', true).attr('id', 'bb'); | 1532 | .append('span').classed('right', true).attr('id', 'bb'); |
1450 | 1533 | ||
1451 | - doPanZoom = bb.append('span') | 1534 | + function mkTogBtn(text, cb) { |
1452 | - .classed('btn', true) | 1535 | + return bb.append('span') |
1453 | - .text('Pan/Zoom') | 1536 | + .classed('btn', true) |
1454 | - .on('click', togglePanZoom); | 1537 | + .text(text) |
1538 | + .on('click', cb); | ||
1539 | + } | ||
1455 | 1540 | ||
1456 | - showTrafficOnHover = bb.append('span') | 1541 | + showInstances = mkTogBtn('Show Instances', toggleInst); |
1457 | - .classed('btn', true) | 1542 | + doPanZoom = mkTogBtn('Pan/Zoom', togglePanZoom); |
1458 | - .text('Show traffic on hover') | 1543 | + showTrafficOnHover = mkTogBtn('Show traffic on hover', toggleTrafficHover); |
1459 | - .on('click', toggleTrafficHover); | ||
1460 | } | 1544 | } |
1461 | 1545 | ||
1462 | - function toggleTrafficHover() { | 1546 | + function instShown() { |
1463 | - showTrafficOnHover.classed('active', !trafficHover()); | 1547 | + return showInstances.classed('active'); |
1464 | } | 1548 | } |
1465 | - | 1549 | + function toggleInst() { |
1466 | - function trafficHover() { | 1550 | + showInstances.classed('active', !instShown()); |
1467 | - return showTrafficOnHover.classed('active'); | 1551 | + if (instShown()) { |
1552 | + oiBox.show(); | ||
1553 | + } else { | ||
1554 | + oiBox.hide(); | ||
1555 | + } | ||
1468 | } | 1556 | } |
1469 | 1557 | ||
1558 | + function panZoom() { | ||
1559 | + return doPanZoom.classed('active'); | ||
1560 | + } | ||
1470 | function togglePanZoom() { | 1561 | function togglePanZoom() { |
1471 | doPanZoom.classed('active', !panZoom()); | 1562 | doPanZoom.classed('active', !panZoom()); |
1472 | } | 1563 | } |
1473 | 1564 | ||
1474 | - function panZoom() { | 1565 | + function trafficHover() { |
1475 | - return doPanZoom.classed('active'); | 1566 | + return showTrafficOnHover.classed('active'); |
1567 | + } | ||
1568 | + function toggleTrafficHover() { | ||
1569 | + showTrafficOnHover.classed('active', !trafficHover()); | ||
1476 | } | 1570 | } |
1477 | 1571 | ||
1572 | + | ||
1478 | // ============================== | 1573 | // ============================== |
1479 | // View life-cycle callbacks | 1574 | // View life-cycle callbacks |
1480 | 1575 | ||
... | @@ -1485,16 +1580,12 @@ | ... | @@ -1485,16 +1580,12 @@ |
1485 | fpad = fcfg.pad, | 1580 | fpad = fcfg.pad, |
1486 | forceDim = [w - 2*fpad, h - 2*fpad]; | 1581 | forceDim = [w - 2*fpad, h - 2*fpad]; |
1487 | 1582 | ||
1488 | - // TODO: set trace api | ||
1489 | - //trace = onos.exported.webSockTrace; | ||
1490 | - | ||
1491 | // NOTE: view.$div is a D3 selection of the view's div | 1583 | // NOTE: view.$div is a D3 selection of the view's div |
1492 | var viewBox = '0 0 ' + config.logicalSize + ' ' + config.logicalSize; | 1584 | var viewBox = '0 0 ' + config.logicalSize + ' ' + config.logicalSize; |
1493 | svg = view.$div.append('svg').attr('viewBox', viewBox); | 1585 | svg = view.$div.append('svg').attr('viewBox', viewBox); |
1494 | setSize(svg, view); | 1586 | setSize(svg, view); |
1495 | 1587 | ||
1496 | zoomPanContainer = svg.append('g').attr('id', 'zoomPanContainer'); | 1588 | zoomPanContainer = svg.append('g').attr('id', 'zoomPanContainer'); |
1497 | - | ||
1498 | setupZoomPan(); | 1589 | setupZoomPan(); |
1499 | 1590 | ||
1500 | // add blue glow filter to svg layer | 1591 | // add blue glow filter to svg layer |
... | @@ -1566,6 +1657,7 @@ | ... | @@ -1566,6 +1657,7 @@ |
1566 | selectCb, atDragEnd, panZoom); | 1657 | selectCb, atDragEnd, panZoom); |
1567 | 1658 | ||
1568 | // create mask layer for when we lose connection to server. | 1659 | // create mask layer for when we lose connection to server. |
1660 | + // TODO: this should be part of the framework | ||
1569 | mask = view.$div.append('div').attr('id','topo-mask'); | 1661 | mask = view.$div.append('div').attr('id','topo-mask'); |
1570 | para(mask, 'Oops!'); | 1662 | para(mask, 'Oops!'); |
1571 | para(mask, 'Web-socket connection to server closed...'); | 1663 | para(mask, 'Web-socket connection to server closed...'); |
... | @@ -1707,5 +1799,6 @@ | ... | @@ -1707,5 +1799,6 @@ |
1707 | }); | 1799 | }); |
1708 | 1800 | ||
1709 | detailPane = onos.ui.addFloatingPanel('topo-detail'); | 1801 | detailPane = onos.ui.addFloatingPanel('topo-detail'); |
1802 | + oiBox = onos.ui.addFloatingPanel('topo-oibox', 'TL'); | ||
1710 | 1803 | ||
1711 | }(ONOS)); | 1804 | }(ONOS)); | ... | ... |
-
Please register or login to post a comment