Simon Hunt

Updated GUI Archetype to implement a simple table view.

Change-Id: I1e4faa457d7407f81b1926949a09e8c4570399e2
...@@ -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 }]);
......