ONOS-2074 - GUI -- Refactor Application view to use directives. WIP.
Change-Id: If886b5af1313ef350e041dc9f9a21ba150edcd79
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationResource.java b/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationResource.java
index c4b4c88..398bfee 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationResource.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationResource.java
@@ -18,7 +18,6 @@
import com.sun.jersey.multipart.FormDataParam;
import org.onlab.rest.BaseResource;
import org.onosproject.app.ApplicationAdminService;
-import org.onosproject.core.Application;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
@@ -38,8 +37,8 @@
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload(@FormDataParam("file") InputStream stream) throws IOException {
- Application app = get(ApplicationAdminService.class).install(stream);
- return Response.ok(app.toString()).build();
+ get(ApplicationAdminService.class).install(stream);
+ return Response.ok().build();
}
}
diff --git a/web/gui/src/main/webapp/app/fw/remote/rest.js b/web/gui/src/main/webapp/app/fw/remote/rest.js
index aa451f9..04b9fe0 100644
--- a/web/gui/src/main/webapp/app/fw/remote/rest.js
+++ b/web/gui/src/main/webapp/app/fw/remote/rest.js
@@ -24,9 +24,9 @@
angular.module('onosRemote')
.factory('RestService',
- ['$log', '$http', 'UrlFnService',
+ ['$log', '$http', 'FnService', 'UrlFnService',
- function (_$log_, $http, ufs) {
+ function (_$log_, $http, fs, ufs) {
$log = _$log_;
function get(url, callback, errorCb) {
@@ -37,7 +37,7 @@
callback(response.data);
}, function (response) {
// error
- var emsg = 'Failed to retrieve JSON data: ' + fullUrl;
+ var emsg = 'Failed to retrieve JSON data: ' + fullUrl;
$log.warn(emsg, response.status, response.data);
if (errorCb) {
errorCb(emsg);
@@ -45,8 +45,28 @@
});
}
+ // TODO: test this
+ function post(url, data, callbacks) {
+ var fullUrl = ufs.rsUrl(url);
+ $http.post(fullUrl, data).then(function (response) {
+ // success
+ if (callbacks && fs.isF(callbacks.success)) {
+ callbacks.success(response.data);
+ }
+ }, function (response) {
+ // error
+ var msg = 'Problem with $http post request: ' + fullUrl;
+ $log.warn(msg, response.status, response.data);
+
+ if (callbacks && fs.isF(callbacks.error)) {
+ callbacks.error(msg);
+ }
+ });
+ }
+
return {
- get: get
+ get: get,
+ post: post
};
}]);
}());
diff --git a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
index b3d759e..ba04b30 100644
--- a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
+++ b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
@@ -44,6 +44,7 @@
req = o.tag + 'DataRequest',
resp = o.tag + 'DataResponse',
onSel = fs.isF(o.selCb),
+ onResp = fs.isF(o.respCb),
promise;
o.scope.tableData = [];
@@ -52,6 +53,7 @@
function respCb(data) {
o.scope.tableData = data[root];
+ onResp && onResp();
o.scope.$apply();
}
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 c2d61cc..2b84e83 100644
--- a/web/gui/src/main/webapp/app/view/app/app.css
+++ b/web/gui/src/main/webapp/app/view/app/app.css
@@ -31,3 +31,8 @@
width: 24px;
border: none;
}
+
+#ov-app form#inputFileForm,
+#ov-app input#uploadFile {
+ display: none;
+}
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 3b78853..0243b5a 100644
--- a/web/gui/src/main/webapp/app/view/app/app.html
+++ b/web/gui/src/main/webapp/app/view/app/app.html
@@ -7,31 +7,28 @@
icon icon-size="36" icon-id="refresh"
ng-click="toggleRefresh()"></div>
<div class="separator"></div>
- <div id="app-install"
- icon icon-size="36" icon-id="plus"
- class="active">
+
+ <form id="inputFileForm">
+ <input id="uploadFile"
+ type="file" size="50" accept=".oar"
+ file-model="appFile">
+ </form>
+ <div icon icon-size="36" icon-id="plus"
+ class="active" trigger-form>
</div>
- <div id="app-activate"
- icon icon-size="36" icon-id="play"
+ <div icon icon-size="36" icon-id="play"
+ ng-click="appAction('activate')"
ng-class="{active: ctrlBtnState.installed}">
</div>
- <div id="app-deactivate"
- icon icon-size="36" icon-id="stop"
+ <div icon icon-size="36" icon-id="stop"
+ ng-click="appAction('deactivate')"
ng-class="{active: ctrlBtnState.active}">
</div>
- <div id="app-uninstall"
- icon icon-size="36" icon-id="garbage"
+ <div icon icon-size="36" icon-id="garbage"
+ ng-click="appAction('uninstall')"
ng-class="{active: ctrlBtnState.selection}">
</div>
</div>
-
- <form id="app-form" method="POST" action="rs/applications/upload"
- target="app-form-response" enctype="multipart/form-data" style="display:none">
- <input type="file" name="file" id="file" size="50" accept=".oar">
- <button type="submit" id="app-upload">Upload</button>
- </form>
- <iframe id="app-form-response" name="app-form-response"
- src="" width="0" height="0" style="visibility:hidden;display:none"></iframe>
</div>
<div class="summary-list" onos-fixed-header>
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 29cc9b6..1918f3a 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -21,74 +21,115 @@
(function () {
'use strict';
- var selectionObj;
+ // constants
+ var INSTALLED = 'INSTALLED',
+ ACTIVE = 'ACTIVE',
+ APP_MGMENT_REQ = 'appManagementRequest',
+ FILE_UPLOAD_URL = 'applications/upload';
angular.module('ovApp', [])
.controller('OvAppCtrl',
- ['$log', '$scope', 'FnService', 'TableBuilderService', 'WebSocketService',
+ ['$log', '$scope', '$http',
+ 'FnService', 'TableBuilderService', 'WebSocketService', 'UrlFnService',
- function ($log, $scope, fs, tbs, wss) {
+ function ($log, $scope, $http, fs, tbs, wss, ufs) {
+ var refreshCtrls;
$scope.ctrlBtnState = {};
- // TODO: clean up view
- // all DOM manipulation (adding styles, getting elements and doing stuff
- // with them) should be done in directives
function selCb($event, row) {
+ // selId comes from tableBuilder
$scope.ctrlBtnState.selection = !!$scope.selId;
- selectionObj = row;
$log.debug('Got a click on:', row);
- if ($scope.ctrlBtnState.selection) {
- $scope.ctrlBtnState.installed = row.state === 'INSTALLED';
- $scope.ctrlBtnState.active = row.state === 'ACTIVE';
- } else {
- $scope.ctrlBtnState.installed = false;
- $scope.ctrlBtnState.active = false;
- }
+ refreshCtrls = function () {
+ if ($scope.ctrlBtnState.selection) {
+ $scope.ctrlBtnState.installed = row.state === INSTALLED;
+ $scope.ctrlBtnState.active = row.state === ACTIVE;
+ } else {
+ $scope.ctrlBtnState.installed = false;
+ $scope.ctrlBtnState.active = false;
+ }
+ };
+
+ refreshCtrls();
+ }
+
+ function respCb() {
+ refreshCtrls && refreshCtrls();
}
tbs.buildTable({
scope: $scope,
tag: 'app',
- selCb: selCb
+ selCb: selCb,
+ respCb: respCb
});
- // TODO: use d3 click events -- move to directive
- 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);
- });
-
- // TODO: use d3 to select elements -- move to directive
- document.getElementById('app-form-response').onload = function () {
- document.getElementById('app-form').reset();
- $scope.$apply();
- //$scope.sortCallback($scope.sortParams);
+ $scope.appAction = function (action) {
+ if ($scope.ctrlBtnState.selection) {
+ $log.debug('Initiating ' + action + ' of ' + $scope.selId);
+ wss.sendEvent(APP_MGMENT_REQ, {
+ action: action,
+ name: $scope.selId
+ });
+ }
};
- function appAction(action) {
- if ($scope.ctrlBtnState.selection) {
- $log.debug('Initiating ' + action + ' of', selectionObj);
- wss.sendEvent('appManagementRequest', {action: action, name: selectionObj.id});
+ $scope.$on('FileChanged', function () {
+ var formData = new FormData();
+ if ($scope.appFile) {
+ formData.append('file', $scope.appFile);
+ $http.post(ufs.rsUrl(FILE_UPLOAD_URL), formData, {
+ transformRequest: angular.identity,
+ headers: {
+ 'Content-Type': undefined
+ }
+ })
+ // TODO: look for finally function to combine lines
+ // TODO: reexamine reset input value
+ .success(function () {
+ $scope.sortCallback($scope.sortParams);
+ document.getElementById('inputFileForm').reset();
+ })
+ .error(function () {
+ $scope.sortCallback($scope.sortParams);
+ });
}
- }
-
- // TODO: use d3 to select elements -- move to directive
- 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);
});
- // TODO: move to directive
- 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'); });
-
$log.log('OvAppCtrl has been created');
+ }])
+
+ // triggers the input form to appear when button is clicked
+ .directive('triggerForm', function () {
+ return {
+ restrict: 'A',
+ link: function (scope, elem) {
+ elem.bind('click', function () {
+ document.getElementById('uploadFile')
+ .dispatchEvent(new Event('click'));
+ });
+ }
+ };
+ })
+
+ // binds the model file to the scope in scope.appFile
+ // sends upload request to the server
+ .directive('fileModel', ['$parse',
+ function ($parse) {
+ return {
+ restrict: 'A',
+ link: function (scope, elem, attrs) {
+ var model = $parse(attrs.fileModel),
+ modelSetter = model.assign;
+
+ elem.bind('change', function () {
+ scope.$apply(function () {
+ modelSetter(scope, elem[0].files[0]);
+ });
+ scope.$emit('FileChanged');
+ });
+ }
+ };
}]);
}());
diff --git a/web/gui/src/main/webapp/app/view/port/port.html b/web/gui/src/main/webapp/app/view/port/port.html
index 5683ca2..3e93eb3 100644
--- a/web/gui/src/main/webapp/app/view/port/port.html
+++ b/web/gui/src/main/webapp/app/view/port/port.html
@@ -18,8 +18,8 @@
<div id="ov-port">
<div class="tabular-header">
<h2>
- Ports for Device {{devId || "(No device selected)"}}
- ({{tableData.length}} total)
+ Port Statistics for Device {{devId || "(No device selected)"}}
+ ({{tableData.length}} Ports total)
</h2>
<div class="ctrl-btns">
<div class="refresh" ng-class="{active: autoRefresh}"