GUI -- Added updateDevice event handling.
- Display offline devices as grey. - Tracing web socket messages (for now, in console; in future, to trace view). - Captured sample events for use with test scenarios - both from and to the server. - Added description to scenario file. Change-Id: I7825b32d63496ebea2ab5789519fb0c6af6c5257
Showing
36 changed files
with
592 additions
and
102 deletions
... | @@ -44,6 +44,7 @@ | ... | @@ -44,6 +44,7 @@ |
44 | <!-- This is where contributed stylesheets get INJECTED --> | 44 | <!-- This is where contributed stylesheets get INJECTED --> |
45 | <!-- TODO: replace with template marker and inject refs server-side --> | 45 | <!-- TODO: replace with template marker and inject refs server-side --> |
46 | <link rel="stylesheet" href="topo2.css"> | 46 | <link rel="stylesheet" href="topo2.css"> |
47 | + <link rel="stylesheet" href="webSockTrace.css"> | ||
47 | 48 | ||
48 | 49 | ||
49 | <!-- General library modules included here--> | 50 | <!-- General library modules included here--> |
... | @@ -97,6 +98,7 @@ | ... | @@ -97,6 +98,7 @@ |
97 | 98 | ||
98 | <!-- Contributed (application) views injected here --> | 99 | <!-- Contributed (application) views injected here --> |
99 | <!-- TODO: replace with template marker and inject refs server-side --> | 100 | <!-- TODO: replace with template marker and inject refs server-side --> |
101 | + <script src="webSockTrace.js"></script> | ||
100 | <script src="topo2.js"></script> | 102 | <script src="topo2.js"></script> |
101 | 103 | ||
102 | <!-- finally, build the UI--> | 104 | <!-- finally, build the UI--> | ... | ... |
1 | +{ | ||
2 | + "event": "addHost", | ||
3 | + "payload": { | ||
4 | + "id": "6A:40:24:F7:9C:2C/-1", | ||
5 | + "ingress": "6A:40:24:F7:9C:2C/-1/0-of:0000000000000003/2", | ||
6 | + "egress": "of:0000000000000003/2-6A:40:24:F7:9C:2C/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000000000000003", | ||
9 | + "port": 2 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "unknown", | ||
13 | + "6A:40:24:F7:9C:2C" | ||
14 | + ], | ||
15 | + "props": {} | ||
16 | + } | ||
17 | +} |
1 | +{ | ||
2 | + "__comments__": [ | ||
3 | + "fabricated event", | ||
4 | + "not sure if this is the actual format", | ||
5 | + "but we really only care about 'id' being in the payload" | ||
6 | + ], | ||
7 | + "event": "removeDevice", | ||
8 | + "payload": { | ||
9 | + "id": "of:0000000000000002", | ||
10 | + "type": "switch", | ||
11 | + "online": true, | ||
12 | + "labels": [ | ||
13 | + "of:0000000000000002", | ||
14 | + "2", | ||
15 | + "", | ||
16 | + null | ||
17 | + ], | ||
18 | + "props": {} | ||
19 | + } | ||
20 | +} |
1 | +{ | ||
2 | + "__comments__": [ | ||
3 | + "fabricated event", | ||
4 | + "not sure if this is the actual format", | ||
5 | + "but we really only care about 'id' being in the payload" | ||
6 | + ], | ||
7 | + "event": "removeHost", | ||
8 | + "payload": { | ||
9 | + "id": "6A:40:24:F7:9C:2C/-1", | ||
10 | + "ingress": "6A:40:24:F7:9C:2C/-1/0-of:0000000000000003/2", | ||
11 | + "egress": "of:0000000000000003/2-6A:40:24:F7:9C:2C/-1/0", | ||
12 | + "cp": { | ||
13 | + "device": "of:0000000000000003", | ||
14 | + "port": 2 | ||
15 | + }, | ||
16 | + "labels": [ | ||
17 | + "unknown", | ||
18 | + "6A:40:24:F7:9C:2C" | ||
19 | + ], | ||
20 | + "props": {} | ||
21 | + } | ||
22 | +} |
1 | +{ | ||
2 | + "event": "showPath", | ||
3 | + "sid": 15, | ||
4 | + "payload": { | ||
5 | + "links": [ | ||
6 | + "62:4F:65:BF:FF:B3/-1/0-of:000000000000000b/1", | ||
7 | + "of:000000000000000b/4-of:000000000000000a/1", | ||
8 | + "of:000000000000000a/4-of:0000000000000001/3", | ||
9 | + "of:0000000000000001/1-of:0000000000000002/4", | ||
10 | + "of:0000000000000002/1-of:0000000000000003/4", | ||
11 | + "of:0000000000000003/1-CA:4B:EE:A4:B0:33/-1/0" | ||
12 | + ], | ||
13 | + "intentId": "0x52a914f9" | ||
14 | + } | ||
15 | +} |
1 | +{ | ||
2 | + "event": "updateHost", | ||
3 | + "payload": { | ||
4 | + "id": "AA:C2:74:3F:B8:06/-1", | ||
5 | + "ingress": "AA:C2:74:3F:B8:06/-1/0-of:0000000000000005/3", | ||
6 | + "egress": "of:0000000000000005/3-AA:C2:74:3F:B8:06/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000000000000005", | ||
9 | + "port": 3 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "10.0.0.9", | ||
13 | + "AA:C2:74:3F:B8:06" | ||
14 | + ], | ||
15 | + "props":{} | ||
16 | + } | ||
17 | +} |
1 | { | 1 | { |
2 | - "event": "addLink", | 2 | + "event": "updateDevice", |
3 | "payload": { | 3 | "payload": { |
4 | - "id": "of:0000ffffffff0003/21-of:0000ffffffff0008/20", | 4 | + "id": "of:0000ffffffff0008", |
5 | - "type": "direct", | 5 | + "type": "switch", |
6 | - "linkWidth": 2, | 6 | + "online": true, |
7 | - "src": "of:0000ffffffff0003", | 7 | + "labels": [ |
8 | - "srcPort": "21", | 8 | + "0000ffffffff0008", |
9 | - "dst": "of:0000ffffffff0008", | 9 | + "FF:FF:FF:FF:00:08", |
10 | - "dstPort": "20", | 10 | + "sw-8-yo", |
11 | - "props" : { | 11 | + "" |
12 | - "BW": "70 G" | 12 | + ], |
13 | + "metaUi": { | ||
14 | + "x": 400, | ||
15 | + "y": 280 | ||
13 | } | 16 | } |
14 | } | 17 | } |
15 | } | 18 | } | ... | ... |
1 | { | 1 | { |
2 | - "event": "addHost", | 2 | + "event": "updateDevice", |
3 | "payload": { | 3 | "payload": { |
4 | - "id": "0E:2A:69:30:13:86/-1", | 4 | + "id": "of:0000ffffffff0003", |
5 | - "ingress": "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/2", | 5 | + "type": "switch", |
6 | - "egress": "of:0000ffffffff0003/2-0E:2A:69:30:13:86/-1/0", | 6 | + "online": true, |
7 | - "cp": { | ||
8 | - "device": "of:0000ffffffff0003", | ||
9 | - "port": 2 | ||
10 | - }, | ||
11 | "labels": [ | 7 | "labels": [ |
12 | - "unknown", | 8 | + "0000ffffffff0003", |
13 | - "0E:2A:69:30:13:86" | 9 | + "FF:FF:FF:FF:00:03", |
10 | + "sw-3-yo", | ||
11 | + "" | ||
14 | ], | 12 | ], |
15 | - "props": {} | 13 | + "metaUi": { |
14 | + "x": 800, | ||
15 | + "y": 280 | ||
16 | + } | ||
16 | } | 17 | } |
17 | } | 18 | } | ... | ... |
1 | { | 1 | { |
2 | - "event": "addHost", | 2 | + "event": "addLink", |
3 | "payload": { | 3 | "payload": { |
4 | - "id": "A6:96:E5:03:52:5F/-1", | 4 | + "id": "of:0000ffffffff0003/21-of:0000ffffffff0008/20", |
5 | - "ingress": "A6:96:E5:03:52:5F/-1/0-of:0000ffffffff0008/1", | 5 | + "type": "direct", |
6 | - "egress": "of:0000ffffffff0008/1-A6:96:E5:03:52:5F/-1/0", | 6 | + "linkWidth": 2, |
7 | - "cp": { | 7 | + "src": "of:0000ffffffff0003", |
8 | - "device": "of:0000ffffffff0008", | 8 | + "srcPort": "21", |
9 | - "port": 1 | 9 | + "dst": "of:0000ffffffff0008", |
10 | - }, | 10 | + "dstPort": "20", |
11 | - "labels": [ | 11 | + "props" : { |
12 | - "unknown", | 12 | + "BW": "70 G" |
13 | - "A6:96:E5:03:52:5F" | 13 | + } |
14 | - ], | ||
15 | - "props": {} | ||
16 | } | 14 | } |
17 | } | 15 | } | ... | ... |
1 | { | 1 | { |
2 | - "event": "updateHost", | 2 | + "event": "addHost", |
3 | "payload": { | 3 | "payload": { |
4 | "id": "0E:2A:69:30:13:86/-1", | 4 | "id": "0E:2A:69:30:13:86/-1", |
5 | "ingress": "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/2", | 5 | "ingress": "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/2", |
... | @@ -9,7 +9,7 @@ | ... | @@ -9,7 +9,7 @@ |
9 | "port": 2 | 9 | "port": 2 |
10 | }, | 10 | }, |
11 | "labels": [ | 11 | "labels": [ |
12 | - "10.0.0.13", | 12 | + "unknown", |
13 | "0E:2A:69:30:13:86" | 13 | "0E:2A:69:30:13:86" |
14 | ], | 14 | ], |
15 | "props": {} | 15 | "props": {} | ... | ... |
1 | { | 1 | { |
2 | - "event": "updateHost", | 2 | + "event": "addHost", |
3 | "payload": { | 3 | "payload": { |
4 | "id": "A6:96:E5:03:52:5F/-1", | 4 | "id": "A6:96:E5:03:52:5F/-1", |
5 | "ingress": "A6:96:E5:03:52:5F/-1/0-of:0000ffffffff0008/1", | 5 | "ingress": "A6:96:E5:03:52:5F/-1/0-of:0000ffffffff0008/1", |
... | @@ -9,7 +9,7 @@ | ... | @@ -9,7 +9,7 @@ |
9 | "port": 1 | 9 | "port": 1 |
10 | }, | 10 | }, |
11 | "labels": [ | 11 | "labels": [ |
12 | - "10.0.0.17", | 12 | + "unknown", |
13 | "A6:96:E5:03:52:5F" | 13 | "A6:96:E5:03:52:5F" |
14 | ], | 14 | ], |
15 | "props": {} | 15 | "props": {} | ... | ... |
1 | +{ | ||
2 | + "event": "updateHost", | ||
3 | + "payload": { | ||
4 | + "id": "0E:2A:69:30:13:86/-1", | ||
5 | + "ingress": "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/2", | ||
6 | + "egress": "of:0000ffffffff0003/2-0E:2A:69:30:13:86/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000ffffffff0003", | ||
9 | + "port": 2 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "10.0.0.13", | ||
13 | + "0E:2A:69:30:13:86" | ||
14 | + ], | ||
15 | + "props": {} | ||
16 | + } | ||
17 | +} |
1 | +{ | ||
2 | + "event": "updateHost", | ||
3 | + "payload": { | ||
4 | + "id": "A6:96:E5:03:52:5F/-1", | ||
5 | + "ingress": "A6:96:E5:03:52:5F/-1/0-of:0000ffffffff0008/1", | ||
6 | + "egress": "of:0000ffffffff0008/1-A6:96:E5:03:52:5F/-1/0", | ||
7 | + "cp": { | ||
8 | + "device": "of:0000ffffffff0008", | ||
9 | + "port": 1 | ||
10 | + }, | ||
11 | + "labels": [ | ||
12 | + "10.0.0.17", | ||
13 | + "A6:96:E5:03:52:5F" | ||
14 | + ], | ||
15 | + "props": {} | ||
16 | + } | ||
17 | +} |
... | @@ -6,5 +6,17 @@ | ... | @@ -6,5 +6,17 @@ |
6 | "title": "Simple Startup Scenario", | 6 | "title": "Simple Startup Scenario", |
7 | "params": { | 7 | "params": { |
8 | "lastAuto": 0 | 8 | "lastAuto": 0 |
9 | - } | 9 | + }, |
10 | + "description": [ | ||
11 | + "1. add device [8] (offline)", | ||
12 | + "2. add device [3] (offline)", | ||
13 | + "3. update device [8] (online)", | ||
14 | + "4. update device [3] (online)", | ||
15 | + "5. add link [3] --> [8]", | ||
16 | + "6. add host (to [3])", | ||
17 | + "7. add host (to [8])", | ||
18 | + "8. update host[3] (IP now 10.0.0.13)", | ||
19 | + "9. update host[8] (IP now 10.0.0.17)", | ||
20 | + "" | ||
21 | + ] | ||
10 | } | 22 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -33,7 +33,8 @@ | ... | @@ -33,7 +33,8 @@ |
33 | var uiApi, | 33 | var uiApi, |
34 | viewApi, | 34 | viewApi, |
35 | navApi, | 35 | navApi, |
36 | - libApi; | 36 | + libApi, |
37 | + exported = {}; | ||
37 | 38 | ||
38 | var defaultOptions = { | 39 | var defaultOptions = { |
39 | trace: false, | 40 | trace: false, |
... | @@ -658,6 +659,7 @@ | ... | @@ -658,6 +659,7 @@ |
658 | return makeUid(this, id); | 659 | return makeUid(this, id); |
659 | }, | 660 | }, |
660 | 661 | ||
662 | + // TODO : add exportApi and importApi methods | ||
661 | // TODO : implement custom dialogs | 663 | // TODO : implement custom dialogs |
662 | 664 | ||
663 | // Consider enhancing alert mechanism to handle multiples | 665 | // Consider enhancing alert mechanism to handle multiples |
... | @@ -737,6 +739,7 @@ | ... | @@ -737,6 +739,7 @@ |
737 | // .......................................................... | 739 | // .......................................................... |
738 | // View API | 740 | // View API |
739 | 741 | ||
742 | + // TODO: deprecated | ||
740 | viewApi = { | 743 | viewApi = { |
741 | /** @api view empty( ) | 744 | /** @api view empty( ) |
742 | * Empties the current view. | 745 | * Empties the current view. |
... | @@ -802,7 +805,8 @@ | ... | @@ -802,7 +805,8 @@ |
802 | lib: libApi, | 805 | lib: libApi, |
803 | //view: viewApi, | 806 | //view: viewApi, |
804 | nav: navApi, | 807 | nav: navApi, |
805 | - buildUi: buildOnosUi | 808 | + buildUi: buildOnosUi, |
809 | + exported: exported | ||
806 | }; | 810 | }; |
807 | }; | 811 | }; |
808 | 812 | ... | ... |
... | @@ -41,11 +41,16 @@ | ... | @@ -41,11 +41,16 @@ |
41 | stroke: #ccc; | 41 | stroke: #ccc; |
42 | } | 42 | } |
43 | 43 | ||
44 | -#topo svg .node.device.switch { | 44 | +/* note: device is offline without the 'online' class */ |
45 | +#topo svg .node.device { | ||
46 | + fill: #777; | ||
47 | +} | ||
48 | + | ||
49 | +#topo svg .node.device.switch.online { | ||
45 | fill: #17f; | 50 | fill: #17f; |
46 | } | 51 | } |
47 | 52 | ||
48 | -#topo svg .node.device.roadm { | 53 | +#topo svg .node.device.roadm.online { |
49 | fill: #03c; | 54 | fill: #03c; |
50 | } | 55 | } |
51 | 56 | ||
... | @@ -53,12 +58,17 @@ | ... | @@ -53,12 +58,17 @@ |
53 | fill: #846; | 58 | fill: #846; |
54 | } | 59 | } |
55 | 60 | ||
61 | +/* note: device is offline without the 'online' class */ | ||
56 | #topo svg .node.device text { | 62 | #topo svg .node.device text { |
57 | - fill: white; | 63 | + fill: #aaa; |
58 | font: 10pt sans-serif; | 64 | font: 10pt sans-serif; |
59 | pointer-events: none; | 65 | pointer-events: none; |
60 | } | 66 | } |
61 | 67 | ||
68 | +#topo svg .node.device.online text { | ||
69 | + fill: white; | ||
70 | +} | ||
71 | + | ||
62 | #topo svg .node.host text { | 72 | #topo svg .node.host text { |
63 | fill: #846; | 73 | fill: #846; |
64 | font: 9pt sans-serif; | 74 | font: 9pt sans-serif; | ... | ... |
... | @@ -24,7 +24,8 @@ | ... | @@ -24,7 +24,8 @@ |
24 | 'use strict'; | 24 | 'use strict'; |
25 | 25 | ||
26 | // shorter names for library APIs | 26 | // shorter names for library APIs |
27 | - var d3u = onos.lib.d3util; | 27 | + var d3u = onos.lib.d3util, |
28 | + trace; | ||
28 | 29 | ||
29 | // configuration data | 30 | // configuration data |
30 | var config = { | 31 | var config = { |
... | @@ -241,8 +242,8 @@ | ... | @@ -241,8 +242,8 @@ |
241 | } | 242 | } |
242 | 243 | ||
243 | function handleUiEvent(data) { | 244 | function handleUiEvent(data) { |
244 | - testDebug('handleUiEvent(): ' + data.event); | 245 | + scenario.view.alert('UI Tx: ' + data.event + '\n\n' + |
245 | - // TODO: | 246 | + JSON.stringify(data)); |
246 | } | 247 | } |
247 | 248 | ||
248 | function injectStartupEvents(view) { | 249 | function injectStartupEvents(view) { |
... | @@ -259,32 +260,44 @@ | ... | @@ -259,32 +260,44 @@ |
259 | bgImg.style('visibility', (vis === 'hidden') ? 'visible' : 'hidden'); | 260 | bgImg.style('visibility', (vis === 'hidden') ? 'visible' : 'hidden'); |
260 | } | 261 | } |
261 | 262 | ||
262 | - function cycleLabels() { | 263 | + function updateDeviceLabel(d) { |
263 | - deviceLabelIndex = (deviceLabelIndex === network.deviceLabelCount - 1) ? 0 : deviceLabelIndex + 1; | 264 | + var label = niceLabel(deviceLabel(d)), |
265 | + node = d.el, | ||
266 | + box; | ||
264 | 267 | ||
265 | - network.nodes.forEach(function (d) { | 268 | + node.select('text') |
266 | - if (d.class !== 'device') { return; } | 269 | + .text(label) |
270 | + .style('opacity', 0) | ||
271 | + .transition() | ||
272 | + .style('opacity', 1); | ||
267 | 273 | ||
268 | - var label = niceLabel(deviceLabel(d)), | 274 | + box = adjustRectToFitText(node); |
269 | - node = d.el, | ||
270 | - box; | ||
271 | 275 | ||
272 | - node.select('text') | 276 | + node.select('rect') |
273 | - .text(label) | 277 | + .transition() |
274 | - .style('opacity', 0) | 278 | + .attr(box); |
275 | - .transition() | ||
276 | - .style('opacity', 1); | ||
277 | 279 | ||
278 | - box = adjustRectToFitText(node); | 280 | + node.select('image') |
281 | + .transition() | ||
282 | + .attr('x', box.x + config.icons.xoff) | ||
283 | + .attr('y', box.y + config.icons.yoff); | ||
284 | + } | ||
279 | 285 | ||
280 | - node.select('rect') | 286 | + function updateHostLabel(d) { |
281 | - .transition() | 287 | + var label = hostLabel(d), |
282 | - .attr(box); | 288 | + host = d.el; |
289 | + | ||
290 | + host.select('text').text(label); | ||
291 | + } | ||
292 | + | ||
293 | + function cycleLabels() { | ||
294 | + deviceLabelIndex = (deviceLabelIndex === network.deviceLabelCount - 1) | ||
295 | + ? 0 : deviceLabelIndex + 1; | ||
283 | 296 | ||
284 | - node.select('image') | 297 | + network.nodes.forEach(function (d) { |
285 | - .transition() | 298 | + if (d.class === 'device') { |
286 | - .attr('x', box.x + config.icons.xoff) | 299 | + updateDeviceLabel(d); |
287 | - .attr('y', box.y + config.icons.yoff); | 300 | + } |
288 | }); | 301 | }); |
289 | } | 302 | } |
290 | 303 | ||
... | @@ -348,15 +361,20 @@ | ... | @@ -348,15 +361,20 @@ |
348 | // ============================== | 361 | // ============================== |
349 | // Event handlers for server-pushed events | 362 | // Event handlers for server-pushed events |
350 | 363 | ||
364 | + function logicError(msg) { | ||
365 | + // TODO, report logic error to server, via websock, so it can be logged | ||
366 | + network.view.alert('Logic Error:\n\n' + msg); | ||
367 | + } | ||
368 | + | ||
351 | var eventDispatch = { | 369 | var eventDispatch = { |
352 | addDevice: addDevice, | 370 | addDevice: addDevice, |
353 | - updateDevice: stillToImplement, | ||
354 | - removeDevice: stillToImplement, | ||
355 | addLink: addLink, | 371 | addLink: addLink, |
356 | - updateLink: stillToImplement, | ||
357 | - removeLink: stillToImplement, | ||
358 | addHost: addHost, | 372 | addHost: addHost, |
373 | + updateDevice: updateDevice, | ||
374 | + updateLink: stillToImplement, | ||
359 | updateHost: updateHost, | 375 | updateHost: updateHost, |
376 | + removeDevice: stillToImplement, | ||
377 | + removeLink: stillToImplement, | ||
360 | removeHost: stillToImplement, | 378 | removeHost: stillToImplement, |
361 | showPath: showPath | 379 | showPath: showPath |
362 | }; | 380 | }; |
... | @@ -364,8 +382,6 @@ | ... | @@ -364,8 +382,6 @@ |
364 | function addDevice(data) { | 382 | function addDevice(data) { |
365 | var device = data.payload, | 383 | var device = data.payload, |
366 | nodeData = createDeviceNode(device); | 384 | nodeData = createDeviceNode(device); |
367 | - note('addDevice', device.id); | ||
368 | - | ||
369 | network.nodes.push(nodeData); | 385 | network.nodes.push(nodeData); |
370 | network.lookup[nodeData.id] = nodeData; | 386 | network.lookup[nodeData.id] = nodeData; |
371 | updateNodes(); | 387 | updateNodes(); |
... | @@ -375,10 +391,7 @@ | ... | @@ -375,10 +391,7 @@ |
375 | function addLink(data) { | 391 | function addLink(data) { |
376 | var link = data.payload, | 392 | var link = data.payload, |
377 | lnk = createLink(link); | 393 | lnk = createLink(link); |
378 | - | ||
379 | if (lnk) { | 394 | if (lnk) { |
380 | - note('addLink', link.id); | ||
381 | - | ||
382 | network.links.push(lnk); | 395 | network.links.push(lnk); |
383 | network.lookup[lnk.id] = lnk; | 396 | network.lookup[lnk.id] = lnk; |
384 | updateLinks(); | 397 | updateLinks(); |
... | @@ -390,8 +403,6 @@ | ... | @@ -390,8 +403,6 @@ |
390 | var host = data.payload, | 403 | var host = data.payload, |
391 | node = createHostNode(host), | 404 | node = createHostNode(host), |
392 | lnk; | 405 | lnk; |
393 | - note('addHost', node.id); | ||
394 | - | ||
395 | network.nodes.push(node); | 406 | network.nodes.push(node); |
396 | network.lookup[host.id] = node; | 407 | network.lookup[host.id] = node; |
397 | updateNodes(); | 408 | updateNodes(); |
... | @@ -406,13 +417,28 @@ | ... | @@ -406,13 +417,28 @@ |
406 | network.force.start(); | 417 | network.force.start(); |
407 | } | 418 | } |
408 | 419 | ||
420 | + function updateDevice(data) { | ||
421 | + var device = data.payload, | ||
422 | + id = device.id, | ||
423 | + nodeData = network.lookup[id]; | ||
424 | + if (nodeData) { | ||
425 | + $.extend(nodeData, device); | ||
426 | + updateDeviceState(nodeData); | ||
427 | + } else { | ||
428 | + logicError('updateDevice lookup fail. ID = "' + id + '"'); | ||
429 | + } | ||
430 | + } | ||
431 | + | ||
409 | function updateHost(data) { | 432 | function updateHost(data) { |
410 | var host = data.payload, | 433 | var host = data.payload, |
411 | - hostData = network.lookup[host.id]; | 434 | + id = host.id, |
412 | - note('updateHost', host.id); | 435 | + hostData = network.lookup[id]; |
413 | - | 436 | + if (hostData) { |
414 | - $.extend(hostData, host); | 437 | + $.extend(hostData, host); |
415 | - updateNodes(); | 438 | + updateHostState(hostData); |
439 | + } else { | ||
440 | + logicError('updateHost lookup fail. ID = "' + id + '"'); | ||
441 | + } | ||
416 | } | 442 | } |
417 | 443 | ||
418 | function showPath(data) { | 444 | function showPath(data) { |
... | @@ -466,9 +492,8 @@ | ... | @@ -466,9 +492,8 @@ |
466 | lnk; | 492 | lnk; |
467 | 493 | ||
468 | if (!dstNode) { | 494 | if (!dstNode) { |
469 | - // TODO: send warning message back to server on websocket | 495 | + logicError('switch not on map for link\n\n' + |
470 | - network.view.alert('switch not on map for link\n\n' + | 496 | + 'src = ' + src + '\ndst = ' + dst); |
471 | - 'src = ' + src + '\ndst = ' + dst); | ||
472 | return null; | 497 | return null; |
473 | } | 498 | } |
474 | 499 | ||
... | @@ -500,9 +525,8 @@ | ... | @@ -500,9 +525,8 @@ |
500 | dstNode = network.lookup[dst]; | 525 | dstNode = network.lookup[dst]; |
501 | 526 | ||
502 | if (!(srcNode && dstNode)) { | 527 | if (!(srcNode && dstNode)) { |
503 | - // TODO: send warning message back to server on websocket | 528 | + logicError('nodes not on map for link\n\n' + |
504 | - network.view.alert('nodes not on map for link\n\n' + | 529 | + 'src = ' + src + '\ndst = ' + dst); |
505 | - 'src = ' + src + '\ndst = ' + dst); | ||
506 | return null; | 530 | return null; |
507 | } | 531 | } |
508 | 532 | ||
... | @@ -578,11 +602,12 @@ | ... | @@ -578,11 +602,12 @@ |
578 | function createDeviceNode(device) { | 602 | function createDeviceNode(device) { |
579 | // start with the object as is | 603 | // start with the object as is |
580 | var node = device, | 604 | var node = device, |
581 | - type = device.type; | 605 | + type = device.type, |
606 | + svgCls = type ? 'node device ' + type : 'node device'; | ||
582 | 607 | ||
583 | // Augment as needed... | 608 | // Augment as needed... |
584 | node.class = 'device'; | 609 | node.class = 'device'; |
585 | - node.svgClass = type ? 'node device ' + type : 'node device'; | 610 | + node.svgClass = device.online ? svgCls + ' online' : svgCls; |
586 | positionNode(node); | 611 | positionNode(node); |
587 | 612 | ||
588 | // cache label array length | 613 | // cache label array length |
... | @@ -669,15 +694,24 @@ | ... | @@ -669,15 +694,24 @@ |
669 | return (label && label.trim()) ? label : '.'; | 694 | return (label && label.trim()) ? label : '.'; |
670 | } | 695 | } |
671 | 696 | ||
697 | + function updateDeviceState(nodeData) { | ||
698 | + nodeData.el.classed('online', nodeData.online); | ||
699 | + updateDeviceLabel(nodeData); | ||
700 | + // TODO: review what else might need to be updated | ||
701 | + } | ||
702 | + | ||
703 | + function updateHostState(hostData) { | ||
704 | + updateHostLabel(hostData); | ||
705 | + // TODO: review what else might need to be updated | ||
706 | + } | ||
707 | + | ||
708 | + | ||
672 | function updateNodes() { | 709 | function updateNodes() { |
673 | node = nodeG.selectAll('.node') | 710 | node = nodeG.selectAll('.node') |
674 | .data(network.nodes, function (d) { return d.id; }); | 711 | .data(network.nodes, function (d) { return d.id; }); |
675 | 712 | ||
676 | // operate on existing nodes, if necessary | 713 | // operate on existing nodes, if necessary |
677 | // update host labels | 714 | // update host labels |
678 | - node.filter('.host').select('text') | ||
679 | - .text(hostLabel); | ||
680 | - | ||
681 | //node .foo() .bar() ... | 715 | //node .foo() .bar() ... |
682 | 716 | ||
683 | // operate on entering nodes: | 717 | // operate on entering nodes: |
... | @@ -828,7 +862,7 @@ | ... | @@ -828,7 +862,7 @@ |
828 | 862 | ||
829 | webSock.ws.onmessage = function(m) { | 863 | webSock.ws.onmessage = function(m) { |
830 | if (m.data) { | 864 | if (m.data) { |
831 | - console.log(m.data); | 865 | + wsTraceRx(m.data); |
832 | handleServerEvent(JSON.parse(m.data)); | 866 | handleServerEvent(JSON.parse(m.data)); |
833 | } | 867 | } |
834 | }; | 868 | }; |
... | @@ -858,11 +892,28 @@ | ... | @@ -858,11 +892,28 @@ |
858 | 892 | ||
859 | function sendMessage(evType, payload) { | 893 | function sendMessage(evType, payload) { |
860 | var toSend = { | 894 | var toSend = { |
861 | - event: evType, | 895 | + event: evType, |
862 | - sid: ++sid, | 896 | + sid: ++sid, |
863 | - payload: payload | 897 | + payload: payload |
864 | - }; | 898 | + }, |
865 | - webSock.send(JSON.stringify(toSend)); | 899 | + asText = JSON.stringify(toSend); |
900 | + wsTraceTx(asText); | ||
901 | + webSock.send(asText); | ||
902 | + } | ||
903 | + | ||
904 | + function wsTraceTx(msg) { | ||
905 | + wsTrace('tx', msg); | ||
906 | + } | ||
907 | + function wsTraceRx(msg) { | ||
908 | + wsTrace('rx', msg); | ||
909 | + } | ||
910 | + function wsTrace(rxtx, msg) { | ||
911 | + | ||
912 | + console.log('[' + rxtx + '] ' + msg); | ||
913 | + // TODO: integrate with trace view | ||
914 | + //if (trace) { | ||
915 | + // trace.output(rxtx, msg); | ||
916 | + //} | ||
866 | } | 917 | } |
867 | 918 | ||
868 | 919 | ||
... | @@ -944,12 +995,19 @@ | ... | @@ -944,12 +995,19 @@ |
944 | sc.evNumber = 0; | 995 | sc.evNumber = 0; |
945 | 996 | ||
946 | d3.json(urlSc, function(err, data) { | 997 | d3.json(urlSc, function(err, data) { |
947 | - var p = data && data.params || {}; | 998 | + var p = data && data.params || {}, |
999 | + desc = data && data.description || null, | ||
1000 | + intro; | ||
1001 | + | ||
948 | if (err) { | 1002 | if (err) { |
949 | view.alert('No scenario found:\n\n' + urlSc + '\n\n' + err); | 1003 | view.alert('No scenario found:\n\n' + urlSc + '\n\n' + err); |
950 | } else { | 1004 | } else { |
951 | sc.params = p; | 1005 | sc.params = p; |
952 | - view.alert("Scenario loaded: " + ctx + '\n\n' + data.title); | 1006 | + intro = "Scenario loaded: " + ctx + '\n\n' + data.title; |
1007 | + if (desc) { | ||
1008 | + intro += '\n\n ' + desc.join('\n '); | ||
1009 | + } | ||
1010 | + view.alert(intro); | ||
953 | } | 1011 | } |
954 | }); | 1012 | }); |
955 | 1013 | ||
... | @@ -967,6 +1025,9 @@ | ... | @@ -967,6 +1025,9 @@ |
967 | fpad = fcfg.pad, | 1025 | fpad = fcfg.pad, |
968 | forceDim = [w - 2*fpad, h - 2*fpad]; | 1026 | forceDim = [w - 2*fpad, h - 2*fpad]; |
969 | 1027 | ||
1028 | + // TODO: set trace api | ||
1029 | + //trace = onos.exported.webSockTrace; | ||
1030 | + | ||
970 | // NOTE: view.$div is a D3 selection of the view's div | 1031 | // NOTE: view.$div is a D3 selection of the view's div |
971 | svg = view.$div.append('svg'); | 1032 | svg = view.$div.append('svg'); |
972 | setSize(svg, view); | 1033 | setSize(svg, view); | ... | ... |
web/gui/src/main/webapp/webSockTrace.css
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 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 -- Web Socket Trace -- CSS file | ||
19 | + | ||
20 | + @author Simon Hunt | ||
21 | + */ | ||
22 | + | ||
23 | +#webSockTrace .toolbar { | ||
24 | + height: 36px; | ||
25 | + padding: 4px; | ||
26 | + vertical-align: baseline; | ||
27 | + font-size: 12pt; | ||
28 | + margin-top: 6px; | ||
29 | +} | ||
30 | + | ||
31 | +/* theme-related */ | ||
32 | +#webSockTrace .toolbar { | ||
33 | + background-color: #448; | ||
34 | + color: #fff; | ||
35 | +} | ||
36 | + | ||
37 | +#webSockTrace .output { | ||
38 | + overflow-y: scroll; | ||
39 | +} | ||
40 | + | ||
41 | +/* theme-related */ | ||
42 | +#webSockTrace .output { | ||
43 | + background-color: #eef; | ||
44 | + color: #226; | ||
45 | +} | ||
46 | + | ||
47 | +#webSockTrace .output p { | ||
48 | + margin: 2px 8px; | ||
49 | + font-size: 10pt; | ||
50 | + padding-left: 6px; | ||
51 | +} | ||
52 | + | ||
53 | +/* theme-related */ | ||
54 | +#webSockTrace .output p.tx { | ||
55 | + color: magenta; | ||
56 | +} | ||
57 | +#webSockTrace .output p.rx { | ||
58 | + color: blue; | ||
59 | +} | ||
60 | + | ||
61 | + | ||
62 | +#webSockTrace .output p.subtitle { | ||
63 | + margin: 6px 8px; | ||
64 | + padding-left: 2px; | ||
65 | + font-size: 12pt; | ||
66 | + font-weight: bold; | ||
67 | + font-style: italic; | ||
68 | +} | ||
69 | + | ||
70 | +/* theme-related */ | ||
71 | +#webSockTrace .output p.subtitle { | ||
72 | + color: #626; | ||
73 | +} |
web/gui/src/main/webapp/webSockTrace.js
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 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 | + View that traces messages across the websocket. | ||
19 | + | ||
20 | + @author Simon Hunt | ||
21 | + */ | ||
22 | + | ||
23 | +(function (onos) { | ||
24 | + 'use strict'; | ||
25 | + | ||
26 | + var v, | ||
27 | + $d, | ||
28 | + tb, | ||
29 | + out, | ||
30 | + which = 'tx', | ||
31 | + keyDispatch = { | ||
32 | + space: function () { | ||
33 | + output(which, "Simon woz 'ere... " + which); | ||
34 | + which = (which === 'tx') ? 'rx' : 'tx'; | ||
35 | + } | ||
36 | + }; | ||
37 | + | ||
38 | + | ||
39 | + function addHeader() { | ||
40 | + tb = $d.append('div') | ||
41 | + .attr('class', 'toolbar'); | ||
42 | + tb.append('span').text('Web Socket Trace'); | ||
43 | + } | ||
44 | + | ||
45 | + function addOutput() { | ||
46 | + out = $d.append('div') | ||
47 | + .attr('class', 'output'); | ||
48 | + } | ||
49 | + | ||
50 | + function subtitle(msg) { | ||
51 | + out.append('p').attr('class', 'subtitle').text(msg); | ||
52 | + } | ||
53 | + | ||
54 | + function output(rxtx, msg) { | ||
55 | + out.append('p').attr('class', rxtx).text(msg); | ||
56 | + } | ||
57 | + | ||
58 | + // invoked only the first time the view is loaded | ||
59 | + function preload(view, ctx, flags) { | ||
60 | + // NOTE: view.$div is a D3 selection of the view's div | ||
61 | + v = view; | ||
62 | + $d = v.$div; | ||
63 | + addHeader(); | ||
64 | + addOutput(); | ||
65 | + | ||
66 | + | ||
67 | + // hack for now, to allow topo access to our API | ||
68 | + // TODO: add 'exportApi' and 'importApi' to views. | ||
69 | + onos.exported.webSockTrace = { | ||
70 | + subtitle: subtitle, | ||
71 | + output: output | ||
72 | + }; | ||
73 | + } | ||
74 | + | ||
75 | + // invoked just prior to loading the view | ||
76 | + function reset(view, ctx, flags) { | ||
77 | + | ||
78 | + } | ||
79 | + | ||
80 | + // invoked when the view is loaded | ||
81 | + function load(view, ctx, flags) { | ||
82 | + resize(view, ctx, flags); | ||
83 | + view.setKeys(keyDispatch); | ||
84 | + subtitle('Waiting for messages...'); | ||
85 | + } | ||
86 | + | ||
87 | + // invoked when the view is resized | ||
88 | + function resize(view, ctx, flags) { | ||
89 | + var h = view.height(); | ||
90 | + out.style('height', h + 'px'); | ||
91 | + | ||
92 | + } | ||
93 | + | ||
94 | + // == register the view here, with links to lifecycle callbacks | ||
95 | + | ||
96 | + onos.ui.addView('webSockTrace', { | ||
97 | + preload: preload, | ||
98 | + load: load, | ||
99 | + resize: resize | ||
100 | + }); | ||
101 | + | ||
102 | +}(ONOS)); |
-
Please register or login to post a comment