Bri Prebilic Cole

ONOS-2074 - GUI -- Refactor Application view to use directives. WIP.

Change-Id: If886b5af1313ef350e041dc9f9a21ba150edcd79
...@@ -18,7 +18,6 @@ package org.onosproject.ui.impl; ...@@ -18,7 +18,6 @@ package org.onosproject.ui.impl;
18 import com.sun.jersey.multipart.FormDataParam; 18 import com.sun.jersey.multipart.FormDataParam;
19 import org.onlab.rest.BaseResource; 19 import org.onlab.rest.BaseResource;
20 import org.onosproject.app.ApplicationAdminService; 20 import org.onosproject.app.ApplicationAdminService;
21 -import org.onosproject.core.Application;
22 21
23 import javax.ws.rs.Consumes; 22 import javax.ws.rs.Consumes;
24 import javax.ws.rs.POST; 23 import javax.ws.rs.POST;
...@@ -38,8 +37,8 @@ public class ApplicationResource extends BaseResource { ...@@ -38,8 +37,8 @@ public class ApplicationResource extends BaseResource {
38 @POST 37 @POST
39 @Consumes(MediaType.MULTIPART_FORM_DATA) 38 @Consumes(MediaType.MULTIPART_FORM_DATA)
40 public Response upload(@FormDataParam("file") InputStream stream) throws IOException { 39 public Response upload(@FormDataParam("file") InputStream stream) throws IOException {
41 - Application app = get(ApplicationAdminService.class).install(stream); 40 + get(ApplicationAdminService.class).install(stream);
42 - return Response.ok(app.toString()).build(); 41 + return Response.ok().build();
43 } 42 }
44 43
45 } 44 }
......
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
24 24
25 angular.module('onosRemote') 25 angular.module('onosRemote')
26 .factory('RestService', 26 .factory('RestService',
27 - ['$log', '$http', 'UrlFnService', 27 + ['$log', '$http', 'FnService', 'UrlFnService',
28 28
29 - function (_$log_, $http, ufs) { 29 + function (_$log_, $http, fs, ufs) {
30 $log = _$log_; 30 $log = _$log_;
31 31
32 function get(url, callback, errorCb) { 32 function get(url, callback, errorCb) {
...@@ -45,8 +45,28 @@ ...@@ -45,8 +45,28 @@
45 }); 45 });
46 } 46 }
47 47
48 + // TODO: test this
49 + function post(url, data, callbacks) {
50 + var fullUrl = ufs.rsUrl(url);
51 + $http.post(fullUrl, data).then(function (response) {
52 + // success
53 + if (callbacks && fs.isF(callbacks.success)) {
54 + callbacks.success(response.data);
55 + }
56 + }, function (response) {
57 + // error
58 + var msg = 'Problem with $http post request: ' + fullUrl;
59 + $log.warn(msg, response.status, response.data);
60 +
61 + if (callbacks && fs.isF(callbacks.error)) {
62 + callbacks.error(msg);
63 + }
64 + });
65 + }
66 +
48 return { 67 return {
49 - get: get 68 + get: get,
69 + post: post
50 }; 70 };
51 }]); 71 }]);
52 }()); 72 }());
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
44 req = o.tag + 'DataRequest', 44 req = o.tag + 'DataRequest',
45 resp = o.tag + 'DataResponse', 45 resp = o.tag + 'DataResponse',
46 onSel = fs.isF(o.selCb), 46 onSel = fs.isF(o.selCb),
47 + onResp = fs.isF(o.respCb),
47 promise; 48 promise;
48 49
49 o.scope.tableData = []; 50 o.scope.tableData = [];
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
52 53
53 function respCb(data) { 54 function respCb(data) {
54 o.scope.tableData = data[root]; 55 o.scope.tableData = data[root];
56 + onResp && onResp();
55 o.scope.$apply(); 57 o.scope.$apply();
56 } 58 }
57 59
......
...@@ -31,3 +31,8 @@ ...@@ -31,3 +31,8 @@
31 width: 24px; 31 width: 24px;
32 border: none; 32 border: none;
33 } 33 }
34 +
35 +#ov-app form#inputFileForm,
36 +#ov-app input#uploadFile {
37 + display: none;
38 +}
......
...@@ -7,31 +7,28 @@ ...@@ -7,31 +7,28 @@
7 icon icon-size="36" icon-id="refresh" 7 icon icon-size="36" icon-id="refresh"
8 ng-click="toggleRefresh()"></div> 8 ng-click="toggleRefresh()"></div>
9 <div class="separator"></div> 9 <div class="separator"></div>
10 - <div id="app-install" 10 +
11 - icon icon-size="36" icon-id="plus" 11 + <form id="inputFileForm">
12 - class="active"> 12 + <input id="uploadFile"
13 + type="file" size="50" accept=".oar"
14 + file-model="appFile">
15 + </form>
16 + <div icon icon-size="36" icon-id="plus"
17 + class="active" trigger-form>
13 </div> 18 </div>
14 - <div id="app-activate" 19 + <div icon icon-size="36" icon-id="play"
15 - icon icon-size="36" icon-id="play" 20 + ng-click="appAction('activate')"
16 ng-class="{active: ctrlBtnState.installed}"> 21 ng-class="{active: ctrlBtnState.installed}">
17 </div> 22 </div>
18 - <div id="app-deactivate" 23 + <div icon icon-size="36" icon-id="stop"
19 - icon icon-size="36" icon-id="stop" 24 + ng-click="appAction('deactivate')"
20 ng-class="{active: ctrlBtnState.active}"> 25 ng-class="{active: ctrlBtnState.active}">
21 </div> 26 </div>
22 - <div id="app-uninstall" 27 + <div icon icon-size="36" icon-id="garbage"
23 - icon icon-size="36" icon-id="garbage" 28 + ng-click="appAction('uninstall')"
24 ng-class="{active: ctrlBtnState.selection}"> 29 ng-class="{active: ctrlBtnState.selection}">
25 </div> 30 </div>
26 </div> 31 </div>
27 -
28 - <form id="app-form" method="POST" action="rs/applications/upload"
29 - target="app-form-response" enctype="multipart/form-data" style="display:none">
30 - <input type="file" name="file" id="file" size="50" accept=".oar">
31 - <button type="submit" id="app-upload">Upload</button>
32 - </form>
33 - <iframe id="app-form-response" name="app-form-response"
34 - src="" width="0" height="0" style="visibility:hidden;display:none"></iframe>
35 </div> 32 </div>
36 33
37 <div class="summary-list" onos-fixed-header> 34 <div class="summary-list" onos-fixed-header>
......
...@@ -21,74 +21,115 @@ ...@@ -21,74 +21,115 @@
21 (function () { 21 (function () {
22 'use strict'; 22 'use strict';
23 23
24 - var selectionObj; 24 + // constants
25 + var INSTALLED = 'INSTALLED',
26 + ACTIVE = 'ACTIVE',
27 + APP_MGMENT_REQ = 'appManagementRequest',
28 + FILE_UPLOAD_URL = 'applications/upload';
25 29
26 angular.module('ovApp', []) 30 angular.module('ovApp', [])
27 .controller('OvAppCtrl', 31 .controller('OvAppCtrl',
28 - ['$log', '$scope', 'FnService', 'TableBuilderService', 'WebSocketService', 32 + ['$log', '$scope', '$http',
33 + 'FnService', 'TableBuilderService', 'WebSocketService', 'UrlFnService',
29 34
30 - function ($log, $scope, fs, tbs, wss) { 35 + function ($log, $scope, $http, fs, tbs, wss, ufs) {
36 + var refreshCtrls;
31 $scope.ctrlBtnState = {}; 37 $scope.ctrlBtnState = {};
32 - // TODO: clean up view
33 - // all DOM manipulation (adding styles, getting elements and doing stuff
34 - // with them) should be done in directives
35 38
36 function selCb($event, row) { 39 function selCb($event, row) {
40 + // selId comes from tableBuilder
37 $scope.ctrlBtnState.selection = !!$scope.selId; 41 $scope.ctrlBtnState.selection = !!$scope.selId;
38 - selectionObj = row;
39 $log.debug('Got a click on:', row); 42 $log.debug('Got a click on:', row);
40 43
44 + refreshCtrls = function () {
41 if ($scope.ctrlBtnState.selection) { 45 if ($scope.ctrlBtnState.selection) {
42 - $scope.ctrlBtnState.installed = row.state === 'INSTALLED'; 46 + $scope.ctrlBtnState.installed = row.state === INSTALLED;
43 - $scope.ctrlBtnState.active = row.state === 'ACTIVE'; 47 + $scope.ctrlBtnState.active = row.state === ACTIVE;
44 } else { 48 } else {
45 $scope.ctrlBtnState.installed = false; 49 $scope.ctrlBtnState.installed = false;
46 $scope.ctrlBtnState.active = false; 50 $scope.ctrlBtnState.active = false;
47 } 51 }
52 + };
53 +
54 + refreshCtrls();
55 + }
56 +
57 + function respCb() {
58 + refreshCtrls && refreshCtrls();
48 } 59 }
49 60
50 tbs.buildTable({ 61 tbs.buildTable({
51 scope: $scope, 62 scope: $scope,
52 tag: 'app', 63 tag: 'app',
53 - selCb: selCb 64 + selCb: selCb,
65 + respCb: respCb
54 }); 66 });
55 67
56 - // TODO: use d3 click events -- move to directive 68 + $scope.appAction = function (action) {
57 - d3.select('#app-install').on('click', function () { 69 + if ($scope.ctrlBtnState.selection) {
58 - $log.debug('Initiating install'); 70 + $log.debug('Initiating ' + action + ' of ' + $scope.selId);
59 - var evt = document.createEvent("HTMLEvents"); 71 + wss.sendEvent(APP_MGMENT_REQ, {
60 - evt.initEvent("click", true, true); 72 + action: action,
61 - document.getElementById('file').dispatchEvent(evt); 73 + name: $scope.selId
62 }); 74 });
63 - 75 + }
64 - // TODO: use d3 to select elements -- move to directive
65 - document.getElementById('app-form-response').onload = function () {
66 - document.getElementById('app-form').reset();
67 - $scope.$apply();
68 - //$scope.sortCallback($scope.sortParams);
69 }; 76 };
70 77
71 - function appAction(action) { 78 + $scope.$on('FileChanged', function () {
72 - if ($scope.ctrlBtnState.selection) { 79 + var formData = new FormData();
73 - $log.debug('Initiating ' + action + ' of', selectionObj); 80 + if ($scope.appFile) {
74 - wss.sendEvent('appManagementRequest', {action: action, name: selectionObj.id}); 81 + formData.append('file', $scope.appFile);
82 + $http.post(ufs.rsUrl(FILE_UPLOAD_URL), formData, {
83 + transformRequest: angular.identity,
84 + headers: {
85 + 'Content-Type': undefined
75 } 86 }
87 + })
88 + // TODO: look for finally function to combine lines
89 + // TODO: reexamine reset input value
90 + .success(function () {
91 + $scope.sortCallback($scope.sortParams);
92 + document.getElementById('inputFileForm').reset();
93 + })
94 + .error(function () {
95 + $scope.sortCallback($scope.sortParams);
96 + });
76 } 97 }
98 + });
77 99
78 - // TODO: use d3 to select elements -- move to directive 100 + $log.log('OvAppCtrl has been created');
79 - d3.select('#file').on('change', function () { 101 + }])
80 - var file = document.getElementById('file').value.replace('C:\\fakepath\\', ''); 102 +
81 - $log.info('Handling file', file); 103 + // triggers the input form to appear when button is clicked
82 - var evt = document.createEvent("HTMLEvents"); 104 + .directive('triggerForm', function () {
83 - evt.initEvent("click", true, true); 105 + return {
84 - document.getElementById('app-upload').dispatchEvent(evt); 106 + restrict: 'A',
107 + link: function (scope, elem) {
108 + elem.bind('click', function () {
109 + document.getElementById('uploadFile')
110 + .dispatchEvent(new Event('click'));
85 }); 111 });
112 + }
113 + };
114 + })
86 115
87 - // TODO: move to directive 116 + // binds the model file to the scope in scope.appFile
88 - d3.select('#app-uninstall').on('click', function () { appAction('uninstall'); }); 117 + // sends upload request to the server
89 - d3.select('#app-activate').on('click', function () { appAction('activate'); }); 118 + .directive('fileModel', ['$parse',
90 - d3.select('#app-deactivate').on('click', function () { appAction('deactivate'); }); 119 + function ($parse) {
120 + return {
121 + restrict: 'A',
122 + link: function (scope, elem, attrs) {
123 + var model = $parse(attrs.fileModel),
124 + modelSetter = model.assign;
91 125
92 - $log.log('OvAppCtrl has been created'); 126 + elem.bind('change', function () {
127 + scope.$apply(function () {
128 + modelSetter(scope, elem[0].files[0]);
129 + });
130 + scope.$emit('FileChanged');
131 + });
132 + }
133 + };
93 }]); 134 }]);
94 }()); 135 }());
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
18 <div id="ov-port"> 18 <div id="ov-port">
19 <div class="tabular-header"> 19 <div class="tabular-header">
20 <h2> 20 <h2>
21 - Ports for Device {{devId || "(No device selected)"}} 21 + Port Statistics for Device {{devId || "(No device selected)"}}
22 - ({{tableData.length}} total) 22 + ({{tableData.length}} Ports total)
23 </h2> 23 </h2>
24 <div class="ctrl-btns"> 24 <div class="ctrl-btns">
25 <div class="refresh" ng-class="{active: autoRefresh}" 25 <div class="refresh" ng-class="{active: autoRefresh}"
......