Thomas Vachuska

GUI -- Added applications view.

Fixed table.js column width computation.
Fixed app.xml files to leave out ONOS from description.

Change-Id: Icfe323e63c7965dd8c3a268421ea58065c5c8236
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.bgprouter" origin="ON.Lab" version="1.2.0"
features="onos-app-bgprouter">
<description>ONOS BGP router application</description>
<description>BGP router application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.config" origin="ON.Lab" version="1.2.0"
features="onos-app-config">
<description>ONOS network configuration application</description>
<description>Network configuration application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.fwd" origin="ON.Lab" version="1.2.0"
features="onos-app-fwd">
<description>ONOS Reactive forwarding application using flow subsystem</description>
<description>Reactive forwarding application using flow subsystem</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.metrics" origin="ON.Lab" version="1.2.0"
features="onos-app-metrics">
<description>ONOS performance metrics collection</description>
<description>Performance metrics collection</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.mobility" origin="ON.Lab" version="1.2.0"
features="onos-app-mobility">
<description>ONOS host mobility application</description>
<description>Host mobility application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.optical" origin="ON.Lab" version="1.2.0"
features="onos-app-optical">
<description>ONOS Packet/Optical use-case application</description>
<description>Packet/Optical use-case application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.proxyarp" origin="ON.Lab" version="1.2.0"
features="onos-app-proxyarp">
<description>ONOS proxy ARP/NDP application</description>
<description>Proxy ARP/NDP application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.sdnip" origin="ON.Lab" version="1.2.0"
features="onos-app-sdnip">
<description>ONOS SDN/IP use-case application</description>
<description>SDN/IP use-case application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.election" origin="ON.Lab" version="1.2.0"
features="onos-app-election">
<description>ONOS master election test application</description>
<description>Master election test application</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.intentperf" origin="ON.Lab" version="1.2.0"
features="onos-app-intent-perf">
<description>Intent performance application</description>
<description>Intent performance test application</description>
</app>
\ No newline at end of file
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.null" origin="ON.Lab" version="1.2.0"
features="onos-null">
<description>ONOS null southbound providers for testing</description>
<description>Null southbound providers for testing</description>
</app>
......
......@@ -16,5 +16,5 @@
-->
<app name="org.onosproject.openflow" origin="ON.Lab" version="1.2.0"
features="onos-openflow">
<description>ONOS OpenFlow protocol southbound providers</description>
<description>OpenFlow protocol southbound providers</description>
</app>
......
/*
* Copyright 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 org.onosproject.ui.impl;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import org.onosproject.app.ApplicationService;
import org.onosproject.app.ApplicationState;
import org.onosproject.core.Application;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static org.onosproject.app.ApplicationState.ACTIVE;
/**
* Message handler for application view related messages.
*/
public class ApplicationViewMessageHandler extends AbstractTabularViewMessageHandler {
/**
* Creates a new message handler for the application messages.
*/
protected ApplicationViewMessageHandler() {
super(ImmutableSet.of("appDataRequest"));
}
@Override
public void process(ObjectNode message) {
ObjectNode payload = payload(message);
String sortCol = string(payload, "sortCol", "id");
String sortDir = string(payload, "sortDir", "asc");
ApplicationService service = get(ApplicationService.class);
TableRow[] rows = generateTableRows(service);
RowComparator rc =
new RowComparator(sortCol, RowComparator.direction(sortDir));
Arrays.sort(rows, rc);
ArrayNode applications = generateArrayNode(rows);
ObjectNode rootNode = mapper.createObjectNode();
rootNode.set("applications", applications);
connection().sendMessage("appDataResponse", 0, rootNode);
}
private TableRow[] generateTableRows(ApplicationService service) {
List<TableRow> list = service.getApplications().stream()
.map(application -> new ApplicationTableRow(service, application))
.collect(Collectors.toList());
return list.toArray(new TableRow[list.size()]);
}
/**
* TableRow implementation for {@link org.onosproject.core.Application applications}.
*/
private static class ApplicationTableRow extends AbstractTableRow {
private static final String STATE = "state";
private static final String STATE_IID = "_iconid_state";
private static final String ID = "id";
private static final String VERSION = "version";
private static final String ORIGIN = "origin";
private static final String DESC = "desc";
private static final String[] COL_IDS = {
STATE, STATE_IID, ID, VERSION, ORIGIN, DESC
};
private static final String ICON_ID_ACTIVE = "appActive";
private static final String ICON_ID_INACTIVE = "appInactive";
public ApplicationTableRow(ApplicationService service, Application app) {
ApplicationState state = service.getState(app.id());
String iconId = state == ACTIVE ? ICON_ID_ACTIVE : ICON_ID_INACTIVE;
add(STATE, state.toString());
add(STATE_IID, iconId);
add(ID, app.id().name());
add(VERSION, app.version().toString());
add(ORIGIN, app.origin());
add(DESC, app.description());
}
@Override
protected String[] columnIds() {
return COL_IDS;
}
}
}
......@@ -59,12 +59,14 @@ public class UiExtensionManager implements UiExtensionService {
List<UiView> coreViews = of(new UiView("topo", "Topology View"),
new UiView("device", "Devices"),
new UiView("host", "Hosts"),
new UiView("app", "Applications"),
new UiView("sample", "Sample"));
UiMessageHandlerFactory messageHandlerFactory =
() -> ImmutableList.of(
new TopologyViewMessageHandler(),
new DeviceViewMessageHandler(),
new HostViewMessageHandler()
new HostViewMessageHandler(),
new ApplicationViewMessageHandler()
);
return new UiExtension(coreViews, messageHandlerFactory, "core",
UiExtensionManager.class.getClassLoader());
......
......@@ -2,3 +2,4 @@
<link rel="stylesheet" href="app/view/topo/topo.css">
<link rel="stylesheet" href="app/view/device/device.css">
<link rel="stylesheet" href="app/view/host/host.css">
<link rel="stylesheet" href="app/view/app/app.css">
......
......@@ -13,4 +13,5 @@
<script src="app/view/topo/topoToolbar.js"></script>
<script src="app/view/device/device.js"></script>
<script src="app/view/host/host.js"></script>
<script src="app/view/app/app.js"></script>
<script src="app/view/sample/sample.js"></script>
......
......@@ -43,10 +43,21 @@ table.summary-list tbody {
background-color: #444;
}
.light table.summary-list tr.selected {
background-color: deepskyblue;
}
.dark table.summary-list tr.selected {
background-color: #304860;
}
table.summary-list td,th {
padding: 6px 6px 6px 6px;
text-align: left;
}
table.summary-list th {
padding: 10px;
letter-spacing: 0.02em;
text-align: left;
cursor: pointer;
}
table.summary-list th:first-child {
......@@ -55,6 +66,7 @@ table.summary-list th:first-child {
table.summary-list th:last-child {
border-radius: 0 8px 0 0;
}
.light table.summary-list th {
background-color: #bbb;
}
......@@ -63,11 +75,6 @@ table.summary-list th:last-child {
color: #ccc;
}
table.summary-list td {
padding: 6px 10px 6px 10px;
text-align: left;
}
.dark table.summary-list td {
color: #ccc;
}
......
......@@ -28,6 +28,29 @@ svg.embeddedIcon .icon .glyph {
fill-rule: evenodd;
}
/*
FIXME: The following should be consolidated to result in much less CSS and
not to require entries for every icon.
*/
.light svg.embeddedIcon .icon.appActive,
.light svg.embeddedIcon .icon.appInactive {
fill: none;
}
.dark svg.embeddedIcon .icon.appActive,
.dark svg.embeddedIcon .icon.appInactive {
fill: none;
}
.light svg.embeddedIcon .icon.appActive .glyph {
fill: green;
}
.dark svg.embeddedIcon .icon.appActive .glyph {
fill: #266610;
}
.light svg.embeddedIcon .icon.deviceOnline,
.light svg.embeddedIcon .icon.deviceOffline {
fill: none;
......@@ -73,6 +96,10 @@ svg.embeddedIcon .icon .glyph {
fill: #ccc;
}
.light svg.embeddedIcon .icon.appActive rect,
.light svg.embeddedIcon .icon.appInactive rect,
.dark svg.embeddedIcon .icon.appActive rect,
.dark svg.embeddedIcon .icon.appInactive rect,
.light svg.embeddedIcon .icon.deviceOnline rect,
.light svg.embeddedIcon .icon.deviceOffline rect,
.dark svg.embeddedIcon .icon.deviceOnline rect,
......
......@@ -29,6 +29,9 @@
// Maps icon ID to the glyph ID it uses.
// NOTE: icon ID maps to a CSS class for styling that icon
var glyphMapping = {
appActive: 'checkMark',
appInactive: 'unknown',
deviceOnline: 'checkMark',
deviceOffline: 'xMark',
devIcon_SWITCH: 'switch',
......
......@@ -29,19 +29,31 @@
// Functions for creating a fixed header on a table (Angular Directive)
function setTableWidth(t) {
var tHeaders, tdElement, colWidth, numCols,
var tHeaders, tdElement, colWidth, numIcons, numNonIcons,
winWidth = fs.windowSize().width;
tHeaders = t.selectAll('th');
numCols = tHeaders[0].length;
colWidth = Math.floor(winWidth / numCols);
numIcons = 0;
numNonIcons = 0;
// FIXME: This should observe custom-set width from the HTML
tHeaders.each(function(thElement, index) {
thElement = d3.select(this);
if (thElement.classed('table-icon')) {
numIcons = numIcons + 1;
} else {
numNonIcons = numNonIcons + 1;
}
});
colWidth = Math.floor((winWidth - (numIcons * tableIconTdSize)) / numNonIcons);
tHeaders.each(function(thElement, index) {
thElement = d3.select(this);
tdElement = t.select('td:nth-of-type(' + (index + 1) + ')');
if (tdElement.classed('table-icon')) {
if (thElement.classed('table-icon')) {
thElement.style('width', tableIconTdSize + 'px');
tdElement.style('width', tableIconTdSize + 'px');
} else {
......
/*
* Copyright 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.
*/
/*
ONOS GUI -- Host View -- CSS file
*/
#ov-app td {
}
<!-- app partial HTML -->
<div id="ov-app">
<h2>Applications ({{ctrl.appData.length}} total)</h2>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="state" class="table-icon" sortable></th>
<th colId="id" sortable>App ID </th>
<th colId="version" sortable>Version</th>
<th colId="origin" sortable>Origin </th>
<th colId="desc">Description </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="app in ctrl.appData"
ng-click="setSelected(app.id)"
ng-class="{selected: app.id === selectedAppId}"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{app._iconid_state}}"></div>
</td>
<td>{{app.id}}</td>
<td>{{app.version}}</td>
<td>{{app.origin}}</td>
<td>{{app.desc}}</td>
</tr>
</tbody>
</table>
</div>
/*
* Copyright 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.
*/
/*
ONOS GUI -- App View Module
*/
(function () {
'use strict';
angular.module('ovApp', [])
.controller('OvAppCtrl',
['$log', '$scope', '$location', 'FnService', 'WebSocketService',
function ($log, $scope, $location, fs, wss) {
var self = this;
self.appData = [];
$scope.responseCallback = function(data) {
self.appData = data.applications;
$scope.$apply();
};
$scope.sortCallback = function (requestParams) {
wss.sendEvent('appDataRequest', requestParams);
};
$scope.selectedAppId = null;
$scope.setSelected = function (appId) {
$scope.selectedAppId = appId;
};
var handlers = {
appDataResponse: $scope.responseCallback
};
wss.bindHandlers(handlers);
// Cleanup on destroyed scope
$scope.$on('$destroy', function () {
wss.unbindHandlers(handlers);
});
$scope.sortCallback();
$log.log('OvAppCtrl has been created');
}]);
}());
......@@ -18,6 +18,5 @@
ONOS GUI -- Device View -- CSS file
*/
#ov-device {
/* placeholder */
}
\ No newline at end of file
#ov-device td {
}
......
......@@ -7,8 +7,8 @@
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="available"></th>
<th colId="type"></th>
<th colId="available" class="table-icon" sortable></th>
<th colId="type" class="table-icon" sortable></th>
<th colId="id" sortable>Device ID </th>
<th colId="mfr" sortable>Vendor </th>
<th colId="hw" sortable>H/W Version </th>
......
......@@ -19,5 +19,5 @@
*/
#ov-host td {
padding: 12px 10px;
height: 20px;
}
\ No newline at end of file
......
......@@ -101,6 +101,7 @@
<script src="app/view/topo/topoToolbar.js"></script>
<script src="app/view/device/device.js"></script>
<script src="app/view/host/host.js"></script>
<script src="app/view/app/app.js"></script>
<script src="app/view/sample/sample.js"></script>
<!-- {INJECTED-JAVASCRIPT-END} -->
......@@ -110,6 +111,7 @@
<link rel="stylesheet" href="app/view/topo/topo.css">
<link rel="stylesheet" href="app/view/device/device.css">
<link rel="stylesheet" href="app/view/host/host.css">
<link rel="stylesheet" href="app/view/app/app.css">
<link rel="stylesheet" href="app/view/sample/sample.css">
<!-- {INJECTED-STYLESHEETS-END} -->
......
......@@ -39,6 +39,7 @@
'topo',
'device',
'host',
'app',
'sample',
// {INJECTED-VIEW-IDS-END}
......