Converting builtin applications to be delivered in a self-contained manner via OAR files.
Change-Id: I5b7c6939aacc263248868fac2e0f69124c5f3609
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java
index 7f4f9b2..d19c987 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java
@@ -18,9 +18,11 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
+import org.onosproject.app.ApplicationAdminService;
import org.onosproject.app.ApplicationService;
import org.onosproject.app.ApplicationState;
import org.onosproject.core.Application;
+import org.onosproject.core.ApplicationId;
import java.util.Arrays;
import java.util.List;
@@ -37,11 +39,20 @@
* Creates a new message handler for the application messages.
*/
protected ApplicationViewMessageHandler() {
- super(ImmutableSet.of("appDataRequest"));
+ super(ImmutableSet.of("appDataRequest", "appManagementRequest"));
}
@Override
public void process(ObjectNode message) {
+ String type = string(message, "event", "unknown");
+ if (type.equals("appDataRequest")) {
+ sendAppList(message);
+ } else if (type.equals("appManagementRequest")) {
+ processManagementCommand(message);
+ }
+ }
+
+ private void sendAppList(ObjectNode message) {
ObjectNode payload = payload(message);
String sortCol = string(payload, "sortCol", "id");
String sortDir = string(payload, "sortDir", "asc");
@@ -58,6 +69,24 @@
connection().sendMessage("appDataResponse", 0, rootNode);
}
+ private void processManagementCommand(ObjectNode message) {
+ ObjectNode payload = payload(message);
+ String action = string(payload, "action");
+ String name = string(payload, "name");
+ if (action != null && name != null) {
+ ApplicationAdminService service = get(ApplicationAdminService.class);
+ ApplicationId appId = service.getId(name);
+ if (action.equals("activate")) {
+ service.activate(appId);
+ } else if (action.equals("deactivate")) {
+ service.deactivate(appId);
+ } else if (action.equals("uninstall")) {
+ service.uninstall(appId);
+ }
+ sendAppList(message);
+ }
+ }
+
private TableRow[] generateTableRows(ApplicationService service) {
List<TableRow> list = service.getApplications().stream()
.map(application -> new ApplicationTableRow(service, application))
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
index 3cc12b3..3be244e 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
@@ -628,7 +628,9 @@
public void event(MastershipEvent event) {
sendAllInstances("updateInstance");
Device device = deviceService.getDevice(event.subject());
- sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
+ if (device != null) {
+ sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
+ }
}
}
diff --git a/web/gui/src/main/webapp/WEB-INF/web.xml b/web/gui/src/main/webapp/WEB-INF/web.xml
index e6807fa..f83fbad 100644
--- a/web/gui/src/main/webapp/WEB-INF/web.xml
+++ b/web/gui/src/main/webapp/WEB-INF/web.xml
@@ -160,7 +160,6 @@
<url-pattern>/websock/*</url-pattern>
</servlet-mapping>
-
<servlet>
<servlet-name>Legacy Web Socket Service</servlet-name>
<servlet-class>org.onosproject.ui.impl.GuiWebSocketServlet</servlet-class>
diff --git a/web/gui/src/main/webapp/app/view/app/app.css b/web/gui/src/main/webapp/app/view/app/app.css
index 481708d..a44b219 100644
--- a/web/gui/src/main/webapp/app/view/app/app.css
+++ b/web/gui/src/main/webapp/app/view/app/app.css
@@ -37,25 +37,45 @@
cursor: pointer;
}
-.light .ctrl-btns g.icon use {
- fill: #fff;
+
+/* Inactive */
+.light .ctrl-btns div g.icon rect,
+.light .ctrl-btns div:hover g.icon rect {
+ fill: #eee;
}
-.dark .ctrl-btns g.icon use {
+.dark .ctrl-btns div g.icon rect,
+.dark .ctrl-btns div:hover g.icon rect {
+ fill: #222;
+}
+
+.light .ctrl-btns div g.icon use {
+ fill: #ddd;
+}
+.dark .ctrl-btns div g.icon use {
fill: #333;
}
-.light .ctrl-btns g.icon rect {
- fill: #bbb;
-}
-.dark .ctrl-btns g.icon rect {
- fill: #444;
+/* Active hover */
+.light .ctrl-btns div.active:hover g.icon rect {
+ fill: #800;
}
-/* Inactive */
-.light .ctrl-btns .disabled g.icon rect {
+.dark .ctrl-btns div.active:hover g.icon rect {
+ fill: #CE5650;
+}
+
+/* Active */
+.light .ctrl-btns div.active g.icon use {
+ fill: #fff;
+}
+.dark .ctrl-btns div.active g.icon use {
fill: #eee;
}
-.dark .ctrl-btns .disabled g.icon rect {
- fill: #111;
+
+.light .ctrl-btns div.active g.icon rect {
+ fill: #bbb;
+}
+.dark .ctrl-btns div.active g.icon rect {
+ fill: #444;
}
diff --git a/web/gui/src/main/webapp/app/view/app/app.html b/web/gui/src/main/webapp/app/view/app/app.html
index ced8ec2..e1e1647 100644
--- a/web/gui/src/main/webapp/app/view/app/app.html
+++ b/web/gui/src/main/webapp/app/view/app/app.html
@@ -3,11 +3,16 @@
<div class="tabular-header">
<h2>Applications ({{ctrl.tableData.length}} total)</h2>
<div class="ctrl-btns">
- <div icon icon-size="36" icon-id="plus"></div>
- <div icon icon-size="36" icon-id="minus" class="disabled"></div>
- <div icon icon-size="36" icon-id="play" class="disabled"></div>
- <div icon icon-size="36" icon-id="stop" class="disabled"></div>
+ <div id="app-install" icon icon-size="36" icon-id="plus" class="active"></div>
+ <div id="app-activate" icon icon-size="36" icon-id="play"></div>
+ <div id="app-deactivate" icon icon-size="36" icon-id="stop"></div>
+ <div id="app-uninstall" icon icon-size="36" icon-id="minus"></div>
</div>
+
+ <form id="app-form" method="POST" action="/onos/v1/applications/upload" enctype="multipart/form-data" style="display:none">
+ <input type="file" id="file" accept=".oar">
+ <button type="submit" id="app-upload">Upload</button>
+ </form>
</div>
<table class="summary-list"
@@ -20,7 +25,7 @@
<th colId="id" sortable>App ID </th>
<th colId="version" sortable>Version </th>
<th colId="origin" sortable>Origin </th>
- <th colId="desc" col-width="400px">Description </th>
+ <th colId="desc" col-width="640px">Description </th>
</tr>
</thead>
diff --git a/web/gui/src/main/webapp/app/view/app/app.js b/web/gui/src/main/webapp/app/view/app/app.js
index 1d46471..236099d 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -1,14 +1,14 @@
/*
* Copyright 2015 Open Networking Laboratory
*
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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,
+ * 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.
@@ -21,19 +21,49 @@
(function () {
'use strict';
- var selRow;
+ var selRow, selection;
angular.module('ovApp', [])
.controller('OvAppCtrl',
- ['$log', '$scope', 'TableBuilderService',
+ ['$log', '$scope', 'TableBuilderService', 'WebSocketService',
- function ($log, $scope, tbs) {
+ function ($log, $scope, tbs, wss) {
function selCb($event, row) {
selRow = angular.element($event.currentTarget);
- // adjust which toolbar buttons are selected
+ selection = row;
$log.debug('Got a click on:', row);
+ // adjust which toolbar buttons are selected
+ d3.select('#app-activate').classed('active', row && row.state === 'INSTALLED');
+ d3.select('#app-deactivate').classed('active', row && row.state === 'ACTIVE');
+ d3.select('#app-uninstall').classed('active', row);
}
+ d3.select('#app-install').on('click', function () {
+ $log.debug('Initiating install');
+ var evt = document.createEvent("HTMLEvents");
+ evt.initEvent("click", true, true);
+ document.getElementById('file').dispatchEvent(evt);
+ });
+
+ function appAction(action) {
+ if (selection) {
+ $log.debug('Initiating uninstall of', selection);
+ wss.sendEvent('appManagementRequest', {action: action, name: selection.id});
+ }
+ }
+
+ d3.select('#file').on('change', function () {
+ var file = document.getElementById('file').value.replace('C:\\fakepath\\', '');
+ $log.info('Handling file', file);
+ var evt = document.createEvent("HTMLEvents");
+ evt.initEvent("click", true, true);
+ document.getElementById('app-upload').dispatchEvent(evt);
+ });
+
+ d3.select('#app-uninstall').on('click', function () { appAction('uninstall'); });
+ d3.select('#app-activate').on('click', function () { appAction('activate'); });
+ d3.select('#app-deactivate').on('click', function () { appAction('deactivate'); });
+
tbs.buildTable({
self: this,
scope: $scope,