Simon Hunt

Updated GUI Archetype to implement a simple table view.

Change-Id: I1e4faa457d7407f81b1926949a09e8c4570399e2
......@@ -2,7 +2,7 @@
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/*
* Copyright 2014 Open Networking Laboratory
* Copyright 2014,2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -18,25 +18,19 @@
*/
package ${package};
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiExtension;
import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
/**
......@@ -62,7 +56,8 @@ public class AppUiComponent {
);
// Application UI extension
protected UiExtension extension = new UiExtension(uiViews, messageHandlerFactory,
protected UiExtension extension =
new UiExtension(uiViews, messageHandlerFactory,
getClass().getClassLoader());
@Activate
......@@ -77,24 +72,4 @@ public class AppUiComponent {
log.info("Stopped");
}
// Application UI message handler
private class AppUiMessageHandler extends UiMessageHandler {
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(new SampleRequest());
}
private class SampleRequest extends RequestHandler {
public SampleRequest() {
super("sampleRequest");
}
@Override
public void process(long sid, ObjectNode objectNode) {
log.info("We got a message: {}", objectNode);
}
}
}
}
......
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/*
* Copyright 2014,2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ${package};
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.table.TableModel;
import org.onosproject.ui.table.TableRequestHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.Override;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Skeletal ONOS UI message handler.
* <p>
* This example specifically supporting a "table" view.
*/
public class AppUiMessageHandler extends UiMessageHandler {
private static final String SAMPLE_DATA_REQ = "sampleDataRequest";
private static final String SAMPLE_DATA_RESP = "sampleDataResponse";
private static final String SAMPLES = "samples";
private static final String SAMPLE_DETAIL_REQ = "sampleDetailsRequest";
private static final String SAMPLE_DETAIL_RESP = "sampleDetailsResponse";
private static final String DETAILS = "details";
private static final String ID = "id";
private static final String LABEL = "label";
private static final String CODE = "code";
private static final String COMMENT = "comment";
private static final String RESULT = "result";
private static final String[] COLUMN_IDS = { ID, LABEL, CODE };
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
new SampleDataRequestHandler(),
new SampleDetailRequestHandler()
);
}
// handler for sample table requests
private final class SampleDataRequestHandler extends TableRequestHandler {
private SampleDataRequestHandler() {
super(SAMPLE_DATA_REQ, SAMPLE_DATA_RESP, SAMPLES);
}
// if necessary, override defaultColumnId() -- if it isn't "id"
@Override
protected String[] getColumnIds() {
return COLUMN_IDS;
}
@Override
protected void populateTable(TableModel tm, ObjectNode payload) {
// === set custom column cell formatters/comparators if need be...
// tm.setFormatter(CODE, new CodeFormatter());
// tm.setComparator(CODE, new CodeComparator());
// === retrieve table row items from some service...
// SomeService ss = get(SomeService.class);
// List<Item> items = ss.getItems()
// fake data for demonstration purposes...
List<Item> items = getItems();
for (Item item: items) {
populateRow(tm.addRow(), item);
}
}
private void populateRow(TableModel.Row row, Item item) {
row.cell(ID, item.id())
.cell(LABEL, item.label())
.cell(CODE, item.code());
}
}
// handler for sample item details requests
private final class SampleDetailRequestHandler extends RequestHandler {
private SampleDetailRequestHandler() {
super(SAMPLE_DETAIL_REQ);
}
@Override
public void process(long sid, ObjectNode payload) {
String id = string(payload, ID, "(none)");
// SomeService ss = get(SomeService.class);
// Item item = ss.getItemDetails(id)
// fake data for demonstration purposes...
Item item = getItem(id);
ObjectNode rootNode = MAPPER.createObjectNode();
ObjectNode data = MAPPER.createObjectNode();
rootNode.set(DETAILS, data);
if (item == null) {
rootNode.put(RESULT, "Item with id '" + id + "' not found");
log.warn("attempted to get item detail for id '{}'", id);
} else {
rootNode.put(RESULT, "Found item with id '" + id + "'");
data.put(ID, item.id());
data.put(LABEL, item.label());
data.put(CODE, item.code());
data.put(COMMENT, "Some arbitrary comment");
}
sendMessage(SAMPLE_DETAIL_RESP, 0, rootNode);
}
}
// ===================================================================
// NOTE: The code below this line is to create fake data for this
// sample code. Normally you would use existing services to
// provide real data.
// Lookup a single item.
private static Item getItem(String id) {
// We realize this code is really inefficient, but
// it suffices for our purposes of demonstration...
for (Item item : getItems()) {
if (item.id().equals(id)) {
return item;
}
}
return null;
}
// Produce a list of items.
private static List<Item> getItems() {
List<Item> items = new ArrayList<>();
items.add(new Item("item-1", "foo", 42));
items.add(new Item("item-2", "bar", 99));
items.add(new Item("item-3", "baz", 65));
return items;
}
// Simple model class to provide sample data
private static class Item {
private final String id;
private final String label;
private final int code;
Item(String id, String label, int code) {
this.id = id;
this.label = label;
this.code = code;
}
String id() { return id; }
String label() { return label; }
int code() { return code; }
}
}
\ No newline at end of file
<!-- partial HTML -->
<div id="ov-sample">
<h2>Sample App View</h2>
<div class="tabular-header">
<h2>Items ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh" ng-class="{active: autoRefresh}"
icon icon-id="refresh" icon-size="36"
tooltip tt-msg="autoRefreshTip"
ng-click="toggleRefresh()"></div>
</div>
</div>
<div class="summary-list" onos-table-resize>
<div class="table-header" onos-sortable-header>
<table>
<tr>
<td colId="id" sortable> Item ID </td>
<td colId="label" sortable> Label </td>
<td colId="code" sortable> Code </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-if="!tableData.length" class="no-data">
<td colspan="3">
No Items found
</td>
</tr>
<tr ng-repeat="item in tableData track by $index"
ng-click="selectCallback($event, item)"
ng-class="{selected: item.id === selId}">
<td>{{item.id}}</td>
<td>{{item.label}}</td>
<td>{{item.code}}</td>
</tr>
</table>
</div>
</div>
<p> {{ctrl.msg}} </p>
<item-details-panel></item-details-panel>
</div>
......
......@@ -2,14 +2,70 @@
(function () {
'use strict';
// injected refs
var $log, $scope, fs, mast, ps, wss;
// internal state
var selRow,
detailsPanel,
pStartY, pHeight,
wSize;
// constants
var topPadding = 20,
detailsReq = 'sampleDetailsRequest',
detailsResp = 'sampleDetailsResponse',
pName = 'item-details-panel',
propOrder = [ 'id', 'label', 'code'],
friendlyProps = [ 'Item ID', 'Item Label', 'Special Code' ];
function respDetailsCb(data) {
$scope.panelData = data.details;
$scope.$apply();
}
angular.module('ovSample', [])
.controller('OvSampleCtrl',
['$log', '$scope',
['$log', '$scope', 'TableBuilderService',
'FnService', 'WebSocketService',
function (_$log_, _$scope_, tbs, _fs_, _wss_) {
$log = _$log_;
$scope = _$scope_;
fs = _fs_;
wss = _wss_;
var handlers = {};
$scope.panelData = [];
function selCb($event, row) {
selRow = angular.element($event.currentTarget);
if ($scope.selId) {
wss.sendEvent(detailsReq, { id: row.id });
} else {
$log.debug('need to hide details panel');
//detailsPanel.hide()
}
$log.debug('Got a click on:', row);
}
tbs.buildTable({
scope: $scope,
tag: 'sample',
selCb: selCb
});
function ($log, $scope) {
var self = this;
// details response handler
handlers[detailsResp] = respDetailsCb;
wss.bindHandlers(handlers);
self.msg = 'A message from our app...';
$scope.$on('$destroy', function () {
wss.unbindHandlerse(handlers);
});
$log.log('OvSampleCtrl has been created');
}]);
......