Simon Hunt
Committed by Gerrit Code Review

ONOS-3505: Basic behaviour of drivers table implemented.

- WIP -- still need to fix scrolling, styling, etc.

Change-Id: I376155ab1375ea4b4b136969b89f74c3733178b8
......@@ -30,24 +30,24 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Message handler for device view related messages.
* Message handler for driver matrix view related messages.
*/
public class DriverViewMessageHandler extends UiMessageHandler {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final int ONE = 1;
private static final String DRIVER_DATA_REQUEST = "driverDataRequest";
private static final String DRIVER_DATA_RESPONSE = "driverDataResponse";
private static final String DRIVERS = "drivers";
private static final String BEHAVIOURS = "behaviours";
private static final String MATRIX = "matrix";
private static final Comparator<? super Class<? extends Behaviour>> BEHAVIOUR_BY_NAME =
(o1, o2) -> o1.getSimpleName().compareTo(o2.getSimpleName());
......@@ -59,11 +59,12 @@ public class DriverViewMessageHandler extends UiMessageHandler {
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
new DataRequestHandler()
// TODO: for row selection, produce data for detail panel
// new DetailRequestHandler()
);
}
// handler for device table requests
// handler for driver matrix requests
private final class DataRequestHandler extends RequestHandler {
private DataRequestHandler() {
......@@ -72,54 +73,46 @@ public class DriverViewMessageHandler extends UiMessageHandler {
@Override
public void process(long sid, ObjectNode payload) {
// Search for drivers producing two artifacts:
// 1) list of abstract behaviours as column listing
// 2) sparse matrix of drivers-to-concrete behaviours
DriverService driverService = get(DriverService.class);
// Collect all behaviours for all drivers
Map<Driver, Set<Class<? extends Behaviour>>> driverBehaviours = new HashMap<>();
driverService.getDrivers().forEach(d -> driverBehaviours.put(d, d.behaviours()));
// Order all drivers
List<Driver> drivers = orderDrivers(driverBehaviours.keySet());
List<Driver> drivers = new ArrayList<>(driverService.getDrivers());
drivers = orderDrivers(drivers);
// Produce a union of all behaviours (and order them)
List<Class<? extends Behaviour>> behaviours = orderBehaviours(driverBehaviours.values());
List<Class<? extends Behaviour>> behaviours = orderBehaviours(drivers);
// Produce a JSON structure and send it
sendMessage(DRIVER_DATA_RESPONSE, 0, driversJson(driverBehaviours, drivers, behaviours));
sendMessage(DRIVER_DATA_RESPONSE, 0, driversJson(drivers, behaviours));
}
private List<Driver> orderDrivers(Set<Driver> drivers) {
private List<Driver> orderDrivers(List<Driver> drivers) {
// For now order by alphanumeric name of the driver
List<Driver> ordered = new ArrayList<>(drivers);
ordered.sort(DRIVER_BY_NAME);
return ordered;
drivers.sort(DRIVER_BY_NAME);
return drivers;
}
private List<Class<? extends Behaviour>>
orderBehaviours(Collection<Set<Class<? extends Behaviour>>> behaviours) {
// For now order by alphanumeric name of the abstract behaviour simple name
private List<Class<? extends Behaviour>> orderBehaviours(List<Driver> drivers) {
// first, produce a set-union of all behaviours from all drivers...
Set<Class<? extends Behaviour>> allBehaviours = new HashSet<>();
behaviours.forEach(allBehaviours::addAll);
drivers.forEach(d -> allBehaviours.addAll(d.behaviours()));
// for now, order by alphanumeric name of the abstract behaviour simple name
List<Class<? extends Behaviour>> ordered = new ArrayList<>(allBehaviours);
ordered.sort(BEHAVIOUR_BY_NAME);
return ordered;
}
private ObjectNode driversJson(Map<Driver, Set<Class<? extends Behaviour>>> driverBehaviours,
List<Driver> drivers,
private ObjectNode driversJson(List<Driver> drivers,
List<Class<? extends Behaviour>> behaviours) {
ObjectNode root = objectNode();
addBehaviours(root, behaviours);
addDrivers(root, drivers);
addRelationships(root, drivers, behaviours, driverBehaviours);
addMatrixCells(root, drivers);
return root;
}
private void addBehaviours(ObjectNode root, List<Class<? extends Behaviour>> behaviours) {
private void addBehaviours(ObjectNode root,
List<Class<? extends Behaviour>> behaviours) {
ArrayNode array = arrayNode();
root.set(BEHAVIOURS, array);
behaviours.forEach(b -> array.add(b.getSimpleName()));
......@@ -131,9 +124,19 @@ public class DriverViewMessageHandler extends UiMessageHandler {
drivers.forEach(d -> array.add(d.name()));
}
private void addRelationships(ObjectNode root,
List<Driver> drivers, List<Class<? extends Behaviour>> behaviours,
Map<Driver, Set<Class<? extends Behaviour>>> driverBehaviours) {
private void addMatrixCells(ObjectNode root, List<Driver> drivers) {
ObjectNode matrix = objectNode();
root.set(MATRIX, matrix);
drivers.forEach(d -> {
ObjectNode dnode = objectNode();
matrix.set(d.name(), dnode);
d.behaviours().forEach(b -> {
// TODO: can put a payload here, rather than a '1' marker
dnode.put(b.getSimpleName(), ONE);
});
});
}
}
......
/* css for sample table view */
/* css for driver matrix view */
#ov-driver-matrix h2 {
display: inline-block;
}
#ov-driver-matrix table {
margin-left: 20px;
}
#ov-driver-matrix .table-header-rotated {
border-collapse: collapse;
}
#ov-driver-matrix .table-header-rotated td {
width: 30px;
}
#ov-driver-matrix .table-header-rotated td.xmark {
background-color: yellow;
}
#ov-driver-matrix .table-header-rotated td {
text-align: center;
padding: 2px 5px;
border: 1px solid #ccc;
}
#ov-driver-matrix .table-header-rotated th.rotate {
height: 140px;
white-space: nowrap;
}
#ov-driver-matrix .table-header-rotated th.rotate > div {
-webkit-transform: translate(25px, 51px) rotate(-45deg);
transform: translate(25px, 51px) rotate(-45deg);
width: 30px;
}
#ov-driver-matrix .table-header-rotated th.rotate > div > span {
border-bottom: 1px solid #ccc;
padding: 5px 10px;
}
#ov-driver-matrix .table-header-rotated th.row-header {
padding: 0 10px;
border-bottom: 1px solid #ccc;
text-align: right;
}
/* Panel Styling */
#ov-driver-matrix-item-details-panel.floatpanel {
position: absolute;
......@@ -33,3 +71,4 @@
font-style: italic;
opacity: 0.8;
}
......
<!-- partial HTML -->
<div id="ov-driver-matrix">
<div class="tabular-header">
<h2>Items ({{tableData.length}} total)</h2>
<h2>Driver Matrix</h2>
<div class="ctrl-btns">
<!-- TODO: fix (or remove) refresh button -->
<div class="refresh" ng-class="{active: autoRefresh}"
icon icon-id="refresh" icon-size="36"
tooltip tt-msg="autoRefreshTip"
......@@ -10,36 +11,35 @@
</div>
</div>
<div class="summary-list" onos-table-resize>
<div class="table-header" onos-sortable-header>
<table>
<!-- TODO: handle resizing / scrolling -->
<div class="driver-matrix">
<table class="table-header-rotated">
<thead>
<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>
<!-- first column header is not rotated -->
<th></th>
<!-- following headers are rotated -->
<th class="rotate" ng-repeat="beh in behaviours track by $index">
<div><span>{{beh}}</span></div>
</th>
</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>
</thead>
<tbody>
<tr ng-repeat="drv in drivers track by $index">
<!--ng-click="selectCallback($event, item)"-->
<!--ng-class="{selected: item.id === selId}">-->
<th class="row-header">
{{drv}}
</th>
<td ng-repeat="beh in behaviours track by $index"
ng-class="{'xmark':cellMarked(drv, beh)}">
{{cellValue(drv, beh)}}
</td>
</tr>
</tbody>
</table>
</div>
<ov-driver-matrix-item-details-panel></ov-driver-matrix-item-details-panel>
......
// js for sample app table view
// js for driver view
(function () {
'use strict';
......@@ -8,8 +8,8 @@
// constants
var detailsReq = 'driverDataRequest',
detailsResp = 'driverDataResponse',
// TODO: deal with details panel
pName = 'ov-driver-matrix-item-details-panel',
propOrder = ['id', 'label', 'code'],
friendlyProps = ['Item ID', 'Item Label', 'Special Code'];
......@@ -40,9 +40,11 @@
}
function respDetailsCb(data) {
$log.debug(data);
//$scope.panelDetails = data.details;
//$scope.$apply();
//$log.debug('Matrix Data', data);
$scope.behaviours = data.behaviours;
$scope.drivers = data.drivers;
$scope.matrix = data.matrix;
$scope.$apply();
}
angular.module('ovDriverMatrix', [])
......@@ -57,7 +59,9 @@
wss = _wss_;
var handlers = {};
$scope.panelDetails = {};
$scope.behaviours = [];
$scope.drivers = [];
$scope.matrix = {};
// details response handler
handlers[detailsResp] = respDetailsCb;
......@@ -75,12 +79,17 @@
// $log.debug('Got a click on:', row);
//}
//// TableBuilderService creating a table for us
//tbs.buildTable({
// scope: $scope,
// tag: 'driverMatrix',
// selCb: selCb
//});
function cellHit(d, b) {
var drec = $scope.matrix[d],
brec = drec && drec[b];
return !!brec;
}
$scope.cellMarked = cellHit;
$scope.cellValue = function(d, b) {
return cellHit(d, b) ? 'x' : '';
};
// cleanup
$scope.$on('$destroy', function () {
......@@ -91,6 +100,7 @@
$log.log('OvDriverMatrixCtrl has been created');
}])
// TODO: implement row selection to show details panel
.directive('ovDriverMatrixItemDetailsPanel', ['PanelService', 'KeyService',
function (ps, ks) {
return {
......