Committed by
Gerrit Code Review
Adding ability to drop OAR files to install apps.
Change-Id: I989a92db4c94ef86d029d6b36f769f28e4fee52d
Showing
5 changed files
with
85 additions
and
8 deletions
... | @@ -22,15 +22,18 @@ import org.onosproject.core.Application; | ... | @@ -22,15 +22,18 @@ import org.onosproject.core.Application; |
22 | import org.onosproject.core.ApplicationId; | 22 | import org.onosproject.core.ApplicationId; |
23 | 23 | ||
24 | import javax.ws.rs.Consumes; | 24 | import javax.ws.rs.Consumes; |
25 | +import javax.ws.rs.DefaultValue; | ||
25 | import javax.ws.rs.GET; | 26 | import javax.ws.rs.GET; |
26 | import javax.ws.rs.POST; | 27 | import javax.ws.rs.POST; |
27 | import javax.ws.rs.Path; | 28 | import javax.ws.rs.Path; |
28 | import javax.ws.rs.PathParam; | 29 | import javax.ws.rs.PathParam; |
29 | import javax.ws.rs.Produces; | 30 | import javax.ws.rs.Produces; |
31 | +import javax.ws.rs.QueryParam; | ||
30 | import javax.ws.rs.core.MediaType; | 32 | import javax.ws.rs.core.MediaType; |
31 | import javax.ws.rs.core.Response; | 33 | import javax.ws.rs.core.Response; |
32 | import java.io.IOException; | 34 | import java.io.IOException; |
33 | import java.io.InputStream; | 35 | import java.io.InputStream; |
36 | +import java.util.Objects; | ||
34 | 37 | ||
35 | /** | 38 | /** |
36 | * Application upload resource. | 39 | * Application upload resource. |
... | @@ -38,11 +41,20 @@ import java.io.InputStream; | ... | @@ -38,11 +41,20 @@ import java.io.InputStream; |
38 | @Path("applications") | 41 | @Path("applications") |
39 | public class ApplicationResource extends BaseResource { | 42 | public class ApplicationResource extends BaseResource { |
40 | 43 | ||
44 | + static String lastInstalledAppName = null; | ||
45 | + | ||
46 | + | ||
41 | @Path("upload") | 47 | @Path("upload") |
42 | @POST | 48 | @POST |
43 | @Consumes(MediaType.MULTIPART_FORM_DATA) | 49 | @Consumes(MediaType.MULTIPART_FORM_DATA) |
44 | - public Response upload(@FormDataParam("file") InputStream stream) throws IOException { | 50 | + public Response upload(@QueryParam("activate") @DefaultValue("false") String activate, |
45 | - get(ApplicationAdminService.class).install(stream); | 51 | + @FormDataParam("file") InputStream stream) throws IOException { |
52 | + ApplicationAdminService service = get(ApplicationAdminService.class); | ||
53 | + Application app = service.install(stream); | ||
54 | + lastInstalledAppName = app.id().name(); | ||
55 | + if (Objects.equals(activate, "true")) { | ||
56 | + service.activate(app.id()); | ||
57 | + } | ||
46 | return Response.ok().build(); | 58 | return Response.ok().build(); |
47 | } | 59 | } |
48 | 60 | ... | ... |
... | @@ -30,6 +30,7 @@ import org.onosproject.ui.table.TableRequestHandler; | ... | @@ -30,6 +30,7 @@ import org.onosproject.ui.table.TableRequestHandler; |
30 | 30 | ||
31 | import java.util.Collection; | 31 | import java.util.Collection; |
32 | 32 | ||
33 | +import static com.google.common.base.Strings.isNullOrEmpty; | ||
33 | import static org.onosproject.app.ApplicationState.ACTIVE; | 34 | import static org.onosproject.app.ApplicationState.ACTIVE; |
34 | 35 | ||
35 | /** | 36 | /** |
... | @@ -160,6 +161,13 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { | ... | @@ -160,6 +161,13 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { |
160 | public void process(long sid, ObjectNode payload) { | 161 | public void process(long sid, ObjectNode payload) { |
161 | String id = string(payload, ID); | 162 | String id = string(payload, ID); |
162 | ApplicationService as = get(ApplicationService.class); | 163 | ApplicationService as = get(ApplicationService.class); |
164 | + | ||
165 | + // If the ID was not specified in the payload, use the name of the | ||
166 | + // most recently uploaded app. | ||
167 | + if (isNullOrEmpty(id)) { | ||
168 | + id = ApplicationResource.lastInstalledAppName; | ||
169 | + } | ||
170 | + | ||
163 | ApplicationId appId = as.getId(id); | 171 | ApplicationId appId = as.getId(id); |
164 | ApplicationState state = as.getState(appId); | 172 | ApplicationState state = as.getState(appId); |
165 | Application app = as.getApplication(appId); | 173 | Application app = as.getApplication(appId); |
... | @@ -198,5 +206,6 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { | ... | @@ -198,5 +206,6 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { |
198 | rootNode.set(DETAILS, data); | 206 | rootNode.set(DETAILS, data); |
199 | sendMessage(APP_DETAILS_RESP, 0, rootNode); | 207 | sendMessage(APP_DETAILS_RESP, 0, rootNode); |
200 | } | 208 | } |
209 | + | ||
201 | } | 210 | } |
202 | } | 211 | } | ... | ... |
1 | <!-- app partial HTML --> | 1 | <!-- app partial HTML --> |
2 | -<div id="ov-app"> | 2 | +<div id="ov-app" filedrop on-file-drop="appDropped()"> |
3 | <div class="tabular-header"> | 3 | <div class="tabular-header"> |
4 | <h2>Applications ({{tableData.length}} total)</h2> | 4 | <h2>Applications ({{tableData.length}} total)</h2> |
5 | <div class="ctrl-btns"> | 5 | <div class="ctrl-btns"> |
... | @@ -14,6 +14,7 @@ | ... | @@ -14,6 +14,7 @@ |
14 | type="file" size="50" accept=".oar" | 14 | type="file" size="50" accept=".oar" |
15 | file-model="appFile"> | 15 | file-model="appFile"> |
16 | </form> | 16 | </form> |
17 | + | ||
17 | <div icon icon-size="36" icon-id="plus" | 18 | <div icon icon-size="36" icon-id="plus" |
18 | class="active" trigger-form | 19 | class="active" trigger-form |
19 | tooltip tt-msg="uploadTip"> | 20 | tooltip tt-msg="uploadTip"> | ... | ... |
... | @@ -31,7 +31,8 @@ | ... | @@ -31,7 +31,8 @@ |
31 | top, | 31 | top, |
32 | middle, | 32 | middle, |
33 | bottom, | 33 | bottom, |
34 | - wSize = false; | 34 | + wSize = false, |
35 | + activateImmediately; | ||
35 | 36 | ||
36 | // constants | 37 | // constants |
37 | var INSTALLED = 'INSTALLED', | 38 | var INSTALLED = 'INSTALLED', |
... | @@ -43,6 +44,7 @@ | ... | @@ -43,6 +44,7 @@ |
43 | detailsReq = 'appDetailsRequest', | 44 | detailsReq = 'appDetailsRequest', |
44 | detailsResp = 'appDetailsResponse', | 45 | detailsResp = 'appDetailsResponse', |
45 | fileUploadUrl = 'applications/upload', | 46 | fileUploadUrl = 'applications/upload', |
47 | + activateOption = '?activate=true', | ||
46 | iconUrlPrefix = 'rs/applications/', | 48 | iconUrlPrefix = 'rs/applications/', |
47 | iconUrlSuffix = '/icon', | 49 | iconUrlSuffix = '/icon', |
48 | dialogId = 'app-dialog', | 50 | dialogId = 'app-dialog', |
... | @@ -200,16 +202,18 @@ | ... | @@ -200,16 +202,18 @@ |
200 | 202 | ||
201 | function respDetailsCb(data) { | 203 | function respDetailsCb(data) { |
202 | $scope.panelData = data.details; | 204 | $scope.panelData = data.details; |
205 | + $scope.selId = data.details.id; | ||
206 | + $scope.ctrlBtnState.selection = data.details.id; | ||
203 | $scope.$apply(); | 207 | $scope.$apply(); |
204 | } | 208 | } |
205 | 209 | ||
206 | angular.module('ovApp', []) | 210 | angular.module('ovApp', []) |
207 | .controller('OvAppCtrl', | 211 | .controller('OvAppCtrl', |
208 | - ['$log', '$scope', '$http', | 212 | + ['$log', '$scope', '$http', '$timeout', |
209 | 'WebSocketService', 'FnService', 'KeyService', 'PanelService', | 213 | 'WebSocketService', 'FnService', 'KeyService', 'PanelService', |
210 | 'IconService', 'UrlFnService', 'DialogService', 'TableBuilderService', | 214 | 'IconService', 'UrlFnService', 'DialogService', 'TableBuilderService', |
211 | 215 | ||
212 | - function (_$log_, _$scope_, $http, _wss_, _fs_, _ks_, _ps_, _is_, ufs, ds, tbs) { | 216 | + function (_$log_, _$scope_, $http, $timeout, _wss_, _fs_, _ks_, _ps_, _is_, ufs, ds, tbs) { |
213 | $log = _$log_; | 217 | $log = _$log_; |
214 | $scope = _$scope_; | 218 | $scope = _$scope_; |
215 | wss = _wss_; | 219 | wss = _wss_; |
... | @@ -302,6 +306,11 @@ | ... | @@ -302,6 +306,11 @@ |
302 | sortCol: spar.sortCol, | 306 | sortCol: spar.sortCol, |
303 | sortDir: spar.sortDir | 307 | sortDir: spar.sortDir |
304 | }); | 308 | }); |
309 | + if (action == 'uninstall') { | ||
310 | + detailsPanel.hide(); | ||
311 | + } else { | ||
312 | + wss.sendEvent(detailsReq, {id: itemId}); | ||
313 | + } | ||
305 | } | 314 | } |
306 | 315 | ||
307 | function dCancel() { | 316 | function dCancel() { |
... | @@ -323,22 +332,32 @@ | ... | @@ -323,22 +332,32 @@ |
323 | }; | 332 | }; |
324 | 333 | ||
325 | $scope.$on('FileChanged', function () { | 334 | $scope.$on('FileChanged', function () { |
326 | - var formData = new FormData(); | 335 | + var formData = new FormData(), |
336 | + url; | ||
327 | if ($scope.appFile) { | 337 | if ($scope.appFile) { |
328 | formData.append('file', $scope.appFile); | 338 | formData.append('file', $scope.appFile); |
329 | - $http.post(ufs.rsUrl(fileUploadUrl), formData, { | 339 | + url = fileUploadUrl + (activateImmediately || ''); |
340 | + $http.post(ufs.rsUrl(url), formData, { | ||
330 | transformRequest: angular.identity, | 341 | transformRequest: angular.identity, |
331 | headers: { | 342 | headers: { |
332 | 'Content-Type': undefined | 343 | 'Content-Type': undefined |
333 | } | 344 | } |
334 | }) | 345 | }) |
335 | .finally(function () { | 346 | .finally(function () { |
347 | + activateImmediately = null; | ||
336 | $scope.sortCallback($scope.sortParams); | 348 | $scope.sortCallback($scope.sortParams); |
337 | document.getElementById('inputFileForm').reset(); | 349 | document.getElementById('inputFileForm').reset(); |
350 | + $timeout(function () { wss.sendEvent(detailsReq); }, 250); | ||
338 | }); | 351 | }); |
339 | } | 352 | } |
340 | }); | 353 | }); |
341 | 354 | ||
355 | + $scope.appDropped = function() { | ||
356 | + activateImmediately = activateOption; | ||
357 | + $scope.$emit('FileChanged'); | ||
358 | + $scope.appFile = null; | ||
359 | + }; | ||
360 | + | ||
342 | $scope.$on('$destroy', function () { | 361 | $scope.$on('$destroy', function () { |
343 | ks.unbindKeys(); | 362 | ks.unbindKeys(); |
344 | wss.unbindHandlers(handlers); | 363 | wss.unbindHandlers(handlers); |
... | @@ -380,6 +399,42 @@ | ... | @@ -380,6 +399,42 @@ |
380 | }; | 399 | }; |
381 | }]) | 400 | }]) |
382 | 401 | ||
402 | + .directive("filedrop", function ($parse, $document) { | ||
403 | + return { | ||
404 | + restrict: "A", | ||
405 | + link: function (scope, element, attrs) { | ||
406 | + var onAppDrop = $parse(attrs.onFileDrop); | ||
407 | + | ||
408 | + // When an item is dragged over the document | ||
409 | + var onDragOver = function (e) { | ||
410 | + e.preventDefault(); | ||
411 | + }; | ||
412 | + | ||
413 | + // When the user leaves the window, cancels the drag or drops the item | ||
414 | + var onDragEnd = function (e) { | ||
415 | + e.preventDefault(); | ||
416 | + }; | ||
417 | + | ||
418 | + // When a file is dropped | ||
419 | + var loadFile = function (file) { | ||
420 | + scope.appFile = file; | ||
421 | + scope.$apply(onAppDrop(scope)); | ||
422 | + }; | ||
423 | + | ||
424 | + // Dragging begins on the document | ||
425 | + $document.bind("dragover", onDragOver); | ||
426 | + | ||
427 | + // Dragging ends on the overlay, which takes the whole window | ||
428 | + element.bind("dragleave", onDragEnd) | ||
429 | + .bind("drop", function (e) { | ||
430 | + $log.info('Drag leave', e); | ||
431 | + loadFile(e.dataTransfer.files[0]); | ||
432 | + onDragEnd(e); | ||
433 | + }); | ||
434 | + } | ||
435 | + }; | ||
436 | + }) | ||
437 | + | ||
383 | .directive('applicationDetailsPanel', | 438 | .directive('applicationDetailsPanel', |
384 | ['$rootScope', '$window', '$timeout', 'KeyService', | 439 | ['$rootScope', '$window', '$timeout', 'KeyService', |
385 | function ($rootScope, $window, $timeout, ks) { | 440 | function ($rootScope, $window, $timeout, ks) { | ... | ... |
-
Please register or login to post a comment