GUI -- Base Cluster View implemented. Bug fixed of table bodies not being wide enough.
Change-Id: Iebf43c87c91404eb443ae1a098b56575ca9959fe
Showing
12 changed files
with
239 additions
and
14 deletions
... | @@ -90,7 +90,8 @@ | ... | @@ -90,7 +90,8 @@ |
90 | org.onlab.osgi.*, | 90 | org.onlab.osgi.*, |
91 | org.onlab.packet.*, | 91 | org.onlab.packet.*, |
92 | org.onlab.rest.*, | 92 | org.onlab.rest.*, |
93 | - org.onosproject.* | 93 | + org.onosproject.*, |
94 | + org.joda.time.* | ||
94 | </Import-Package> | 95 | </Import-Package> |
95 | <Web-ContextPath>${web.context}</Web-ContextPath> | 96 | <Web-ContextPath>${web.context}</Web-ContextPath> |
96 | </instructions> | 97 | </instructions> | ... | ... |
1 | +/* | ||
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 | +package org.onosproject.ui.impl; | ||
18 | + | ||
19 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
20 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
21 | +import com.google.common.collect.ImmutableSet; | ||
22 | +import org.joda.time.DateTime; | ||
23 | +import org.joda.time.format.DateTimeFormat; | ||
24 | +import org.onosproject.cluster.ClusterService; | ||
25 | +import org.onosproject.cluster.ControllerNode; | ||
26 | +import org.onosproject.cluster.NodeId; | ||
27 | + | ||
28 | +import java.util.ArrayList; | ||
29 | +import java.util.Arrays; | ||
30 | +import java.util.List; | ||
31 | + | ||
32 | + | ||
33 | +/** | ||
34 | + * Message handler for cluster view related messages. | ||
35 | + */ | ||
36 | +public class ClusterViewMessageHandler extends AbstractTabularViewMessageHandler { | ||
37 | + | ||
38 | + /** | ||
39 | + * Creates a new message handler for the cluster messages. | ||
40 | + */ | ||
41 | + protected ClusterViewMessageHandler() { | ||
42 | + super(ImmutableSet.of("clusterDataRequest")); | ||
43 | + } | ||
44 | + | ||
45 | + @Override | ||
46 | + public void process(ObjectNode message) { | ||
47 | + ObjectNode payload = payload(message); | ||
48 | + String sortCol = string(payload, "sortCol", "id"); | ||
49 | + String sortDir = string(payload, "sortDir", "asc"); | ||
50 | + | ||
51 | + ClusterService service = get(ClusterService.class); | ||
52 | + TableRow[] rows = generateTableRows(service); | ||
53 | + RowComparator rc = | ||
54 | + new RowComparator(sortCol, RowComparator.direction(sortDir)); | ||
55 | + Arrays.sort(rows, rc); | ||
56 | + ArrayNode clusterNodes = generateArrayNode(rows); | ||
57 | + ObjectNode rootNode = mapper.createObjectNode(); | ||
58 | + rootNode.set("clusters", clusterNodes); | ||
59 | + | ||
60 | + connection().sendMessage("clusterDataResponse", 0, rootNode); | ||
61 | + } | ||
62 | + | ||
63 | + private TableRow[] generateTableRows(ClusterService service) { | ||
64 | + List<TableRow> list = new ArrayList<>(); | ||
65 | + for (ControllerNode node : service.getNodes()) { | ||
66 | + list.add(new ControllerNodeTableRow(service, node)); | ||
67 | + } | ||
68 | + return list.toArray(new TableRow[list.size()]); | ||
69 | + } | ||
70 | + | ||
71 | + /** | ||
72 | + * TableRow implementation for {@link ControllerNode controller nodes}. | ||
73 | + */ | ||
74 | + private static class ControllerNodeTableRow extends AbstractTableRow { | ||
75 | + | ||
76 | + private static final String ID = "id"; | ||
77 | + private static final String IP = "ip"; | ||
78 | + private static final String TCP_PORT = "tcp"; | ||
79 | + private static final String STATE = "state"; | ||
80 | + private static final String UPDATED = "updated"; | ||
81 | + | ||
82 | + private static final String[] COL_IDS = { | ||
83 | + ID, IP, TCP_PORT, STATE, UPDATED | ||
84 | + }; | ||
85 | + | ||
86 | + public ControllerNodeTableRow(ClusterService service, ControllerNode n) { | ||
87 | + NodeId id = n.id(); | ||
88 | + DateTime lastUpdated = service.getLastUpdated(id); | ||
89 | + org.joda.time.format.DateTimeFormatter format = DateTimeFormat.longTime(); | ||
90 | + | ||
91 | + add(ID, id.toString()); | ||
92 | + add(IP, n.ip().toString()); | ||
93 | + add(TCP_PORT, Integer.toString(n.tcpPort())); | ||
94 | + add(STATE, service.getState(id).toString()); | ||
95 | + add(UPDATED, format.print(lastUpdated)); | ||
96 | + } | ||
97 | + | ||
98 | + @Override | ||
99 | + protected String[] columnIds() { | ||
100 | + return COL_IDS; | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
104 | +} |
... | @@ -61,6 +61,7 @@ public class UiExtensionManager implements UiExtensionService { | ... | @@ -61,6 +61,7 @@ public class UiExtensionManager implements UiExtensionService { |
61 | new UiView("host", "Hosts"), | 61 | new UiView("host", "Hosts"), |
62 | new UiView("app", "Applications"), | 62 | new UiView("app", "Applications"), |
63 | new UiView("intent", "Intents"), | 63 | new UiView("intent", "Intents"), |
64 | + new UiView("cluster", "Cluster Nodes"), | ||
64 | new UiView("sample", "Sample")); | 65 | new UiView("sample", "Sample")); |
65 | UiMessageHandlerFactory messageHandlerFactory = | 66 | UiMessageHandlerFactory messageHandlerFactory = |
66 | () -> ImmutableList.of( | 67 | () -> ImmutableList.of( |
... | @@ -68,7 +69,8 @@ public class UiExtensionManager implements UiExtensionService { | ... | @@ -68,7 +69,8 @@ public class UiExtensionManager implements UiExtensionService { |
68 | new DeviceViewMessageHandler(), | 69 | new DeviceViewMessageHandler(), |
69 | new HostViewMessageHandler(), | 70 | new HostViewMessageHandler(), |
70 | new ApplicationViewMessageHandler(), | 71 | new ApplicationViewMessageHandler(), |
71 | - new IntentViewMessageHandler() | 72 | + new IntentViewMessageHandler(), |
73 | + new ClusterViewMessageHandler() | ||
72 | ); | 74 | ); |
73 | return new UiExtension(coreViews, messageHandlerFactory, "core", | 75 | return new UiExtension(coreViews, messageHandlerFactory, "core", |
74 | UiExtensionManager.class.getClassLoader()); | 76 | UiExtensionManager.class.getClassLoader()); | ... | ... |
... | @@ -4,3 +4,4 @@ | ... | @@ -4,3 +4,4 @@ |
4 | <link rel="stylesheet" href="app/view/host/host.css"> | 4 | <link rel="stylesheet" href="app/view/host/host.css"> |
5 | <link rel="stylesheet" href="app/view/app/app.css"> | 5 | <link rel="stylesheet" href="app/view/app/app.css"> |
6 | <link rel="stylesheet" href="app/view/intent/intent.css"> | 6 | <link rel="stylesheet" href="app/view/intent/intent.css"> |
7 | +<link rel="stylesheet" href="app/view/cluster/cluster.css"> | ... | ... |
... | @@ -15,4 +15,5 @@ | ... | @@ -15,4 +15,5 @@ |
15 | <script src="app/view/host/host.js"></script> | 15 | <script src="app/view/host/host.js"></script> |
16 | <script src="app/view/app/app.js"></script> | 16 | <script src="app/view/app/app.js"></script> |
17 | <script src="app/view/intent/intent.js"></script> | 17 | <script src="app/view/intent/intent.js"></script> |
18 | +<script src="app/view/cluster/cluster.js"></script> | ||
18 | <script src="app/view/sample/sample.js"></script> | 19 | <script src="app/view/sample/sample.js"></script> | ... | ... |
... | @@ -83,7 +83,8 @@ | ... | @@ -83,7 +83,8 @@ |
83 | 83 | ||
84 | tHeaders.each(function (d, i) { | 84 | tHeaders.each(function (d, i) { |
85 | var thElement = d3.select(this), | 85 | var thElement = d3.select(this), |
86 | - tdElement = t.select('td:nth-of-type(' + (i + 1) + ')'), | 86 | + tr = t.select('tr:nth-of-type(2)'), |
87 | + tdElement = tr.select('td:nth-of-type(' + (i + 1) + ')'), | ||
87 | custWidth = thElement.attr(colWidth); | 88 | custWidth = thElement.attr(colWidth); |
88 | 89 | ||
89 | if (custWidth) { | 90 | if (custWidth) { |
... | @@ -105,9 +106,10 @@ | ... | @@ -105,9 +106,10 @@ |
105 | tableHeight = fs.windowSize(mast.mastHeight() + totalHeight).height; | 106 | tableHeight = fs.windowSize(mast.mastHeight() + totalHeight).height; |
106 | 107 | ||
107 | thead.style('display', 'block'); | 108 | thead.style('display', 'block'); |
108 | - tbody.style({'display': 'block', | 109 | + tbody.style({ |
109 | - 'height': (tableHeight + 'px'), | 110 | + display: 'block', |
110 | - 'overflow': 'auto' | 111 | + height: tableHeight + 'px', |
112 | + overflow: 'auto' | ||
111 | }); | 113 | }); |
112 | } | 114 | } |
113 | 115 | ... | ... |
1 | +/* | ||
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 -- Cluster View -- CSS file | ||
19 | + */ | ||
20 | + | ||
21 | +#ov-cluster td { | ||
22 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +<!-- | ||
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 | +<!-- Cluster partial HTML --> | ||
18 | +<div id="ov-cluster"> | ||
19 | + <h2>Cluster Nodes ({{ctrl.tableData.length}} total)</h2> | ||
20 | + <table class="summary-list" | ||
21 | + onos-fixed-header | ||
22 | + onos-sortable-header | ||
23 | + sort-callback="sortCallback(requestParams)"> | ||
24 | + <thead> | ||
25 | + <tr> | ||
26 | + <th colId="id" sortable>ID </th> | ||
27 | + <th colId="ip" sortable>IP Address </th> | ||
28 | + <th colId="tcp" sortable>TCP Port </th> | ||
29 | + <th colId="state" sortable>State </th> | ||
30 | + <th colId="updated" sortable>Last Updated </th> | ||
31 | + </tr> | ||
32 | + </thead> | ||
33 | + | ||
34 | + <tbody> | ||
35 | + <tr ng-hide="ctrl.tableData.length"> | ||
36 | + <td class="nodata" colspan="5"> | ||
37 | + No Cluster Nodes found | ||
38 | + </td> | ||
39 | + </tr> | ||
40 | + | ||
41 | + <tr ng-repeat="node in ctrl.tableData" | ||
42 | + ng-repeat-done> | ||
43 | + <td>{{node.id}}</td> | ||
44 | + <td>{{node.ip}}</td> | ||
45 | + <td>{{node.tcp}}</td> | ||
46 | + <td>{{node.state}}</td> | ||
47 | + <td>{{node.updated}}</td> | ||
48 | + </tr> | ||
49 | + </tbody> | ||
50 | + </table> | ||
51 | + | ||
52 | +</div> |
1 | +/* | ||
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 -- Cluster View Module | ||
19 | + */ | ||
20 | + | ||
21 | +(function () { | ||
22 | + 'use strict'; | ||
23 | + | ||
24 | + angular.module('ovCluster', []) | ||
25 | + .controller('OvClusterCtrl', | ||
26 | + ['$log', '$scope', 'TableBuilderService', | ||
27 | + | ||
28 | + function ($log, $scope, tbs) { | ||
29 | + tbs.buildTable({ | ||
30 | + self: this, | ||
31 | + scope: $scope, | ||
32 | + tag: 'cluster' | ||
33 | + }); | ||
34 | + | ||
35 | + $log.log('OvClusterCtrl has been created'); | ||
36 | + }]); | ||
37 | +}()); |
... | @@ -18,24 +18,24 @@ | ... | @@ -18,24 +18,24 @@ |
18 | ONOS GUI -- Intent View -- CSS file | 18 | ONOS GUI -- Intent View -- CSS file |
19 | */ | 19 | */ |
20 | 20 | ||
21 | -.light #ov-intent tr:nth-child(6n + 1), | ||
22 | .light #ov-intent tr:nth-child(6n + 2), | 21 | .light #ov-intent tr:nth-child(6n + 2), |
23 | -.light #ov-intent tr:nth-child(6n + 3) { | 22 | +.light #ov-intent tr:nth-child(6n + 3), |
23 | +.light #ov-intent tr:nth-child(6n + 4) { | ||
24 | background-color: #eee; | 24 | background-color: #eee; |
25 | } | 25 | } |
26 | -.light #ov-intent tr:nth-child(6n + 4), | ||
27 | .light #ov-intent tr:nth-child(6n + 5), | 26 | .light #ov-intent tr:nth-child(6n + 5), |
28 | -.light #ov-intent tr:nth-child(6n) { | 27 | +.light #ov-intent tr:nth-child(6n + 6), |
28 | +.light #ov-intent tr:nth-child(6n + 1) { | ||
29 | background-color: #ddd; | 29 | background-color: #ddd; |
30 | } | 30 | } |
31 | -.dark #ov-intent tr:nth-child(6n + 1), | ||
32 | .dark #ov-intent tr:nth-child(6n + 2), | 31 | .dark #ov-intent tr:nth-child(6n + 2), |
33 | -.dark #ov-intent tr:nth-child(6n + 3) { | 32 | +.dark #ov-intent tr:nth-child(6n + 3), |
33 | +.dark #ov-intent tr:nth-child(6n + 4) { | ||
34 | background-color: #444; | 34 | background-color: #444; |
35 | } | 35 | } |
36 | -.dark #ov-intent tr:nth-child(6n + 4), | ||
37 | .dark #ov-intent tr:nth-child(6n + 5), | 36 | .dark #ov-intent tr:nth-child(6n + 5), |
38 | -.dark #ov-intent tr:nth-child(6n) { | 37 | +.dark #ov-intent tr:nth-child(6n + 6), |
38 | +.dark #ov-intent tr:nth-child(6n + 1) { | ||
39 | background-color: #333; | 39 | background-color: #333; |
40 | } | 40 | } |
41 | 41 | ... | ... |
... | @@ -113,6 +113,7 @@ | ... | @@ -113,6 +113,7 @@ |
113 | <script src="app/view/host/host.js"></script> | 113 | <script src="app/view/host/host.js"></script> |
114 | <script src="app/view/app/app.js"></script> | 114 | <script src="app/view/app/app.js"></script> |
115 | <script src="app/view/intent/intent.js"></script> | 115 | <script src="app/view/intent/intent.js"></script> |
116 | + <script src="app/view/cluster/cluster.js"></script> | ||
116 | <script src="app/view/sample/sample.js"></script> | 117 | <script src="app/view/sample/sample.js"></script> |
117 | <!-- {INJECTED-JAVASCRIPT-END} --> | 118 | <!-- {INJECTED-JAVASCRIPT-END} --> |
118 | 119 | ||
... | @@ -124,6 +125,7 @@ | ... | @@ -124,6 +125,7 @@ |
124 | <link rel="stylesheet" href="app/view/host/host.css"> | 125 | <link rel="stylesheet" href="app/view/host/host.css"> |
125 | <link rel="stylesheet" href="app/view/app/app.css"> | 126 | <link rel="stylesheet" href="app/view/app/app.css"> |
126 | <link rel="stylesheet" href="app/view/intent/intent.css"> | 127 | <link rel="stylesheet" href="app/view/intent/intent.css"> |
128 | + <link rel="stylesheet" href="app/view/cluster/cluster.css"> | ||
127 | <link rel="stylesheet" href="app/view/sample/sample.css"> | 129 | <link rel="stylesheet" href="app/view/sample/sample.css"> |
128 | <!-- {INJECTED-STYLESHEETS-END} --> | 130 | <!-- {INJECTED-STYLESHEETS-END} --> |
129 | 131 | ... | ... |
-
Please register or login to post a comment