Updated GUI Archetype to implement a simple table view.
Change-Id: I1e4faa457d7407f81b1926949a09e8c4570399e2
Showing
4 changed files
with
294 additions
and
35 deletions
tools/package/archetypes/ui/src/main/resources/archetype-resources/src/main/java/AppUiComponent.java
... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
2 | #set( $symbol_dollar = '$' ) | 2 | #set( $symbol_dollar = '$' ) |
3 | #set( $symbol_escape = '\' ) | 3 | #set( $symbol_escape = '\' ) |
4 | /* | 4 | /* |
5 | - * Copyright 2014 Open Networking Laboratory | 5 | + * Copyright 2014,2015 Open Networking Laboratory |
6 | * | 6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); | 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * you may not use this file except in compliance with the License. | 8 | * you may not use this file except in compliance with the License. |
... | @@ -18,25 +18,19 @@ | ... | @@ -18,25 +18,19 @@ |
18 | */ | 18 | */ |
19 | package ${package}; | 19 | package ${package}; |
20 | 20 | ||
21 | -import com.fasterxml.jackson.databind.node.ObjectNode; | ||
22 | import com.google.common.collect.ImmutableList; | 21 | import com.google.common.collect.ImmutableList; |
23 | -import com.google.common.collect.ImmutableSet; | ||
24 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
25 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
26 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
27 | -import org.apache.felix.scr.annotations.Service; | ||
28 | import org.apache.felix.scr.annotations.Reference; | 25 | import org.apache.felix.scr.annotations.Reference; |
29 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 26 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
30 | -import org.onosproject.ui.RequestHandler; | ||
31 | import org.onosproject.ui.UiExtension; | 27 | import org.onosproject.ui.UiExtension; |
32 | import org.onosproject.ui.UiExtensionService; | 28 | import org.onosproject.ui.UiExtensionService; |
33 | -import org.onosproject.ui.UiMessageHandler; | ||
34 | import org.onosproject.ui.UiMessageHandlerFactory; | 29 | import org.onosproject.ui.UiMessageHandlerFactory; |
35 | import org.onosproject.ui.UiView; | 30 | import org.onosproject.ui.UiView; |
36 | import org.slf4j.Logger; | 31 | import org.slf4j.Logger; |
37 | import org.slf4j.LoggerFactory; | 32 | import org.slf4j.LoggerFactory; |
38 | 33 | ||
39 | -import java.util.Collection; | ||
40 | import java.util.List; | 34 | import java.util.List; |
41 | 35 | ||
42 | /** | 36 | /** |
... | @@ -62,7 +56,8 @@ public class AppUiComponent { | ... | @@ -62,7 +56,8 @@ public class AppUiComponent { |
62 | ); | 56 | ); |
63 | 57 | ||
64 | // Application UI extension | 58 | // Application UI extension |
65 | - protected UiExtension extension = new UiExtension(uiViews, messageHandlerFactory, | 59 | + protected UiExtension extension = |
60 | + new UiExtension(uiViews, messageHandlerFactory, | ||
66 | getClass().getClassLoader()); | 61 | getClass().getClassLoader()); |
67 | 62 | ||
68 | @Activate | 63 | @Activate |
... | @@ -77,24 +72,4 @@ public class AppUiComponent { | ... | @@ -77,24 +72,4 @@ public class AppUiComponent { |
77 | log.info("Stopped"); | 72 | log.info("Stopped"); |
78 | } | 73 | } |
79 | 74 | ||
80 | - // Application UI message handler | ||
81 | - private class AppUiMessageHandler extends UiMessageHandler { | ||
82 | - | ||
83 | - @Override | ||
84 | - protected Collection<RequestHandler> createRequestHandlers() { | ||
85 | - return ImmutableSet.of(new SampleRequest()); | ||
86 | - } | ||
87 | - | ||
88 | - private class SampleRequest extends RequestHandler { | ||
89 | - public SampleRequest() { | ||
90 | - super("sampleRequest"); | ||
91 | - } | ||
92 | - | ||
93 | - @Override | ||
94 | - public void process(long sid, ObjectNode objectNode) { | ||
95 | - log.info("We got a message: {}", objectNode); | ||
96 | - } | ||
97 | - } | ||
98 | - } | ||
99 | - | ||
100 | } | 75 | } | ... | ... |
1 | +#set( $symbol_pound = '#' ) | ||
2 | +#set( $symbol_dollar = '$' ) | ||
3 | +#set( $symbol_escape = '\' ) | ||
4 | +/* | ||
5 | + * Copyright 2014,2015 Open Networking Laboratory | ||
6 | + * | ||
7 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | + * you may not use this file except in compliance with the License. | ||
9 | + * You may obtain a copy of the License at | ||
10 | + * | ||
11 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | + * | ||
13 | + * Unless required by applicable law or agreed to in writing, software | ||
14 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | + * See the License for the specific language governing permissions and | ||
17 | + * limitations under the License. | ||
18 | + */ | ||
19 | +package ${package}; | ||
20 | + | ||
21 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
22 | +import com.google.common.collect.ImmutableSet; | ||
23 | +import org.onosproject.ui.RequestHandler; | ||
24 | +import org.onosproject.ui.UiMessageHandler; | ||
25 | +import org.onosproject.ui.table.TableModel; | ||
26 | +import org.onosproject.ui.table.TableRequestHandler; | ||
27 | +import org.slf4j.Logger; | ||
28 | +import org.slf4j.LoggerFactory; | ||
29 | + | ||
30 | +import java.lang.Override; | ||
31 | +import java.util.ArrayList; | ||
32 | +import java.util.Collection; | ||
33 | +import java.util.List; | ||
34 | + | ||
35 | +/** | ||
36 | + * Skeletal ONOS UI message handler. | ||
37 | + * <p> | ||
38 | + * This example specifically supporting a "table" view. | ||
39 | + */ | ||
40 | +public class AppUiMessageHandler extends UiMessageHandler { | ||
41 | + | ||
42 | + private static final String SAMPLE_DATA_REQ = "sampleDataRequest"; | ||
43 | + private static final String SAMPLE_DATA_RESP = "sampleDataResponse"; | ||
44 | + private static final String SAMPLES = "samples"; | ||
45 | + | ||
46 | + private static final String SAMPLE_DETAIL_REQ = "sampleDetailsRequest"; | ||
47 | + private static final String SAMPLE_DETAIL_RESP = "sampleDetailsResponse"; | ||
48 | + private static final String DETAILS = "details"; | ||
49 | + | ||
50 | + private static final String ID = "id"; | ||
51 | + private static final String LABEL = "label"; | ||
52 | + private static final String CODE = "code"; | ||
53 | + private static final String COMMENT = "comment"; | ||
54 | + private static final String RESULT = "result"; | ||
55 | + | ||
56 | + private static final String[] COLUMN_IDS = { ID, LABEL, CODE }; | ||
57 | + | ||
58 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
59 | + | ||
60 | + | ||
61 | + @Override | ||
62 | + protected Collection<RequestHandler> createRequestHandlers() { | ||
63 | + return ImmutableSet.of( | ||
64 | + new SampleDataRequestHandler(), | ||
65 | + new SampleDetailRequestHandler() | ||
66 | + ); | ||
67 | + } | ||
68 | + | ||
69 | + // handler for sample table requests | ||
70 | + private final class SampleDataRequestHandler extends TableRequestHandler { | ||
71 | + | ||
72 | + private SampleDataRequestHandler() { | ||
73 | + super(SAMPLE_DATA_REQ, SAMPLE_DATA_RESP, SAMPLES); | ||
74 | + } | ||
75 | + | ||
76 | + // if necessary, override defaultColumnId() -- if it isn't "id" | ||
77 | + | ||
78 | + @Override | ||
79 | + protected String[] getColumnIds() { | ||
80 | + return COLUMN_IDS; | ||
81 | + } | ||
82 | + | ||
83 | + @Override | ||
84 | + protected void populateTable(TableModel tm, ObjectNode payload) { | ||
85 | + // === set custom column cell formatters/comparators if need be... | ||
86 | + // tm.setFormatter(CODE, new CodeFormatter()); | ||
87 | + // tm.setComparator(CODE, new CodeComparator()); | ||
88 | + | ||
89 | + // === retrieve table row items from some service... | ||
90 | + // SomeService ss = get(SomeService.class); | ||
91 | + // List<Item> items = ss.getItems() | ||
92 | + | ||
93 | + // fake data for demonstration purposes... | ||
94 | + List<Item> items = getItems(); | ||
95 | + for (Item item: items) { | ||
96 | + populateRow(tm.addRow(), item); | ||
97 | + } | ||
98 | + } | ||
99 | + | ||
100 | + private void populateRow(TableModel.Row row, Item item) { | ||
101 | + row.cell(ID, item.id()) | ||
102 | + .cell(LABEL, item.label()) | ||
103 | + .cell(CODE, item.code()); | ||
104 | + } | ||
105 | + } | ||
106 | + | ||
107 | + | ||
108 | + // handler for sample item details requests | ||
109 | + private final class SampleDetailRequestHandler extends RequestHandler { | ||
110 | + | ||
111 | + private SampleDetailRequestHandler() { | ||
112 | + super(SAMPLE_DETAIL_REQ); | ||
113 | + } | ||
114 | + | ||
115 | + @Override | ||
116 | + public void process(long sid, ObjectNode payload) { | ||
117 | + String id = string(payload, ID, "(none)"); | ||
118 | + | ||
119 | + // SomeService ss = get(SomeService.class); | ||
120 | + // Item item = ss.getItemDetails(id) | ||
121 | + | ||
122 | + // fake data for demonstration purposes... | ||
123 | + Item item = getItem(id); | ||
124 | + | ||
125 | + ObjectNode rootNode = MAPPER.createObjectNode(); | ||
126 | + ObjectNode data = MAPPER.createObjectNode(); | ||
127 | + rootNode.set(DETAILS, data); | ||
128 | + | ||
129 | + if (item == null) { | ||
130 | + rootNode.put(RESULT, "Item with id '" + id + "' not found"); | ||
131 | + log.warn("attempted to get item detail for id '{}'", id); | ||
132 | + | ||
133 | + } else { | ||
134 | + rootNode.put(RESULT, "Found item with id '" + id + "'"); | ||
135 | + | ||
136 | + data.put(ID, item.id()); | ||
137 | + data.put(LABEL, item.label()); | ||
138 | + data.put(CODE, item.code()); | ||
139 | + data.put(COMMENT, "Some arbitrary comment"); | ||
140 | + } | ||
141 | + | ||
142 | + sendMessage(SAMPLE_DETAIL_RESP, 0, rootNode); | ||
143 | + } | ||
144 | + } | ||
145 | + | ||
146 | + | ||
147 | + // =================================================================== | ||
148 | + // NOTE: The code below this line is to create fake data for this | ||
149 | + // sample code. Normally you would use existing services to | ||
150 | + // provide real data. | ||
151 | + | ||
152 | + // Lookup a single item. | ||
153 | + private static Item getItem(String id) { | ||
154 | + // We realize this code is really inefficient, but | ||
155 | + // it suffices for our purposes of demonstration... | ||
156 | + for (Item item : getItems()) { | ||
157 | + if (item.id().equals(id)) { | ||
158 | + return item; | ||
159 | + } | ||
160 | + } | ||
161 | + return null; | ||
162 | + } | ||
163 | + | ||
164 | + // Produce a list of items. | ||
165 | + private static List<Item> getItems() { | ||
166 | + List<Item> items = new ArrayList<>(); | ||
167 | + items.add(new Item("item-1", "foo", 42)); | ||
168 | + items.add(new Item("item-2", "bar", 99)); | ||
169 | + items.add(new Item("item-3", "baz", 65)); | ||
170 | + return items; | ||
171 | + } | ||
172 | + | ||
173 | + // Simple model class to provide sample data | ||
174 | + private static class Item { | ||
175 | + private final String id; | ||
176 | + private final String label; | ||
177 | + private final int code; | ||
178 | + | ||
179 | + Item(String id, String label, int code) { | ||
180 | + this.id = id; | ||
181 | + this.label = label; | ||
182 | + this.code = code; | ||
183 | + } | ||
184 | + | ||
185 | + String id() { return id; } | ||
186 | + String label() { return label; } | ||
187 | + int code() { return code; } | ||
188 | + } | ||
189 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | - | ||
2 | <!-- partial HTML --> | 1 | <!-- partial HTML --> |
3 | <div id="ov-sample"> | 2 | <div id="ov-sample"> |
4 | - <h2>Sample App View</h2> | 3 | + <div class="tabular-header"> |
4 | + <h2>Items ({{tableData.length}} total)</h2> | ||
5 | + <div class="ctrl-btns"> | ||
6 | + <div class="refresh" ng-class="{active: autoRefresh}" | ||
7 | + icon icon-id="refresh" icon-size="36" | ||
8 | + tooltip tt-msg="autoRefreshTip" | ||
9 | + ng-click="toggleRefresh()"></div> | ||
10 | + </div> | ||
11 | + </div> | ||
12 | + | ||
13 | + <div class="summary-list" onos-table-resize> | ||
14 | + | ||
15 | + <div class="table-header" onos-sortable-header> | ||
16 | + <table> | ||
17 | + <tr> | ||
18 | + <td colId="id" sortable> Item ID </td> | ||
19 | + <td colId="label" sortable> Label </td> | ||
20 | + <td colId="code" sortable> Code </td> | ||
21 | + </tr> | ||
22 | + </table> | ||
23 | + </div> | ||
24 | + | ||
25 | + <div class="table-body"> | ||
26 | + <table> | ||
27 | + <tr ng-if="!tableData.length" class="no-data"> | ||
28 | + <td colspan="3"> | ||
29 | + No Items found | ||
30 | + </td> | ||
31 | + </tr> | ||
32 | + | ||
33 | + <tr ng-repeat="item in tableData track by $index" | ||
34 | + ng-click="selectCallback($event, item)" | ||
35 | + ng-class="{selected: item.id === selId}"> | ||
36 | + <td>{{item.id}}</td> | ||
37 | + <td>{{item.label}}</td> | ||
38 | + <td>{{item.code}}</td> | ||
39 | + </tr> | ||
40 | + </table> | ||
41 | + </div> | ||
42 | + | ||
43 | + </div> | ||
5 | 44 | ||
6 | - <p> {{ctrl.msg}} </p> | 45 | + <item-details-panel></item-details-panel> |
7 | </div> | 46 | </div> | ... | ... |
... | @@ -2,14 +2,70 @@ | ... | @@ -2,14 +2,70 @@ |
2 | (function () { | 2 | (function () { |
3 | 'use strict'; | 3 | 'use strict'; |
4 | 4 | ||
5 | + // injected refs | ||
6 | + var $log, $scope, fs, mast, ps, wss; | ||
7 | + | ||
8 | + // internal state | ||
9 | + var selRow, | ||
10 | + detailsPanel, | ||
11 | + pStartY, pHeight, | ||
12 | + wSize; | ||
13 | + | ||
14 | + // constants | ||
15 | + var topPadding = 20, | ||
16 | + | ||
17 | + detailsReq = 'sampleDetailsRequest', | ||
18 | + detailsResp = 'sampleDetailsResponse', | ||
19 | + pName = 'item-details-panel', | ||
20 | + | ||
21 | + propOrder = [ 'id', 'label', 'code'], | ||
22 | + friendlyProps = [ 'Item ID', 'Item Label', 'Special Code' ]; | ||
23 | + | ||
24 | + | ||
25 | + function respDetailsCb(data) { | ||
26 | + $scope.panelData = data.details; | ||
27 | + $scope.$apply(); | ||
28 | + } | ||
29 | + | ||
5 | angular.module('ovSample', []) | 30 | angular.module('ovSample', []) |
6 | .controller('OvSampleCtrl', | 31 | .controller('OvSampleCtrl', |
7 | - ['$log', '$scope', | 32 | + ['$log', '$scope', 'TableBuilderService', |
33 | + 'FnService', 'WebSocketService', | ||
34 | + | ||
35 | + function (_$log_, _$scope_, tbs, _fs_, _wss_) { | ||
36 | + $log = _$log_; | ||
37 | + $scope = _$scope_; | ||
38 | + fs = _fs_; | ||
39 | + wss = _wss_; | ||
40 | + | ||
41 | + var handlers = {}; | ||
42 | + | ||
43 | + $scope.panelData = []; | ||
44 | + | ||
45 | + function selCb($event, row) { | ||
46 | + selRow = angular.element($event.currentTarget); | ||
47 | + if ($scope.selId) { | ||
48 | + wss.sendEvent(detailsReq, { id: row.id }); | ||
49 | + } else { | ||
50 | + $log.debug('need to hide details panel'); | ||
51 | + //detailsPanel.hide() | ||
52 | + } | ||
53 | + $log.debug('Got a click on:', row); | ||
54 | + } | ||
55 | + | ||
56 | + tbs.buildTable({ | ||
57 | + scope: $scope, | ||
58 | + tag: 'sample', | ||
59 | + selCb: selCb | ||
60 | + }); | ||
8 | 61 | ||
9 | - function ($log, $scope) { | 62 | + // details response handler |
10 | - var self = this; | 63 | + handlers[detailsResp] = respDetailsCb; |
64 | + wss.bindHandlers(handlers); | ||
11 | 65 | ||
12 | - self.msg = 'A message from our app...'; | 66 | + $scope.$on('$destroy', function () { |
67 | + wss.unbindHandlerse(handlers); | ||
68 | + }); | ||
13 | 69 | ||
14 | $log.log('OvSampleCtrl has been created'); | 70 | $log.log('OvSampleCtrl has been created'); |
15 | }]); | 71 | }]); | ... | ... |
-
Please register or login to post a comment