From 64ef74321ad592ebd856665e5c07497a101b28b5 Mon Sep 17 00:00:00 2001 From: Romain Date: Wed, 15 Feb 2017 23:14:56 +0100 Subject: [PATCH] feat(image): add the ability to force remove an image (#497) (#562) --- app/components/images/images.html | 11 ++++++++- app/components/images/imagesController.js | 28 +++++++++++++++++++---- app/rest/image.js | 2 +- app/services/modalService.js | 28 +++++++++++++++++++++++ assets/css/app.css | 4 ++++ bower.json | 3 ++- gruntfile.js | 1 + 7 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 app/services/modalService.js diff --git a/app/components/images/images.html b/app/components/images/images.html index 972b0602b..5d494bb77 100644 --- a/app/components/images/images.html +++ b/app/components/images/images.html @@ -63,7 +63,16 @@
- +
+ + + +
diff --git a/app/components/images/imagesController.js b/app/components/images/imagesController.js index 7000cddaa..e3bf84066 100644 --- a/app/components/images/imagesController.js +++ b/app/components/images/imagesController.js @@ -1,6 +1,6 @@ angular.module('images', []) -.controller('ImagesController', ['$scope', '$state', 'Config', 'Image', 'ImageHelper', 'Messages', 'Pagination', -function ($scope, $state, Config, Image, ImageHelper, Messages, Pagination) { +.controller('ImagesController', ['$scope', '$state', 'Config', 'Image', 'ImageHelper', 'Messages', 'Pagination', 'ModalService', +function ($scope, $state, Config, Image, ImageHelper, Messages, Pagination, ModalService) { $scope.state = {}; $scope.state.pagination_count = Pagination.getPaginationCount('images'); $scope.sortType = 'RepoTags'; @@ -59,7 +59,27 @@ function ($scope, $state, Config, Image, ImageHelper, Messages, Pagination) { }); }; - $scope.removeAction = function () { + $scope.confirmRemovalAction = function (force) { + ModalService.confirm({ + title: "Are you sure?", + message: "Forcing the removal of the image will remove the image even if it has multiple tags or if it is used by stopped containers.", + buttons: { + confirm: { + label: 'Remove the image', + }, + cancel: { + label: 'Cancel' + } + }, + callback: function (confirmed) { + if(!confirmed) { return; } + $scope.removeAction(force); + } + }); + }; + + $scope.removeAction = function (force) { + force = !!force; $('#loadImagesSpinner').show(); var counter = 0; var complete = function () { @@ -71,7 +91,7 @@ function ($scope, $state, Config, Image, ImageHelper, Messages, Pagination) { angular.forEach($scope.images, function (i) { if (i.Checked) { counter = counter + 1; - Image.remove({id: i.Id}, function (d) { + Image.remove({id: i.Id, force: force}, function (d) { if (d[0].message) { $('#loadImagesSpinner').hide(); Messages.error("Unable to remove image", {}, d[0].message); diff --git a/app/rest/image.js b/app/rest/image.js index 9361136fc..8a436b45a 100644 --- a/app/rest/image.js +++ b/app/rest/image.js @@ -18,7 +18,7 @@ angular.module('portainer.rest') isArray: true, transformResponse: jsonObjectsToArrayHandler }, remove: { - method: 'DELETE', params: {id: '@id'}, + method: 'DELETE', params: {id: '@id', force: '@force'}, isArray: true, transformResponse: deleteImageHandler } }); diff --git a/app/services/modalService.js b/app/services/modalService.js new file mode 100644 index 000000000..0e1d9729b --- /dev/null +++ b/app/services/modalService.js @@ -0,0 +1,28 @@ +angular.module('portainer.services') +.factory('ModalService', [function ModalServiceFactory() { + 'use strict'; + var service = {}; + service.confirm = function(options){ + var box = bootbox.confirm({ + title: options.title, + message: options.message, + buttons: { + confirm: { + label: options.buttons.confirm.label, + className: 'btn-danger' + }, + cancel: { + label: options.buttons.cancel.label + } + }, + callback: options.callback + }); + box.css({ + 'top': '50%', + 'margin-top': function () { + return -(box.height() / 2); + } + }); + } + return service; +}]); diff --git a/assets/css/app.css b/assets/css/app.css index cce7e440b..09a7b23b6 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -72,6 +72,10 @@ input[type="radio"] { vertical-align: middle; } +a[ng-click]{ + cursor: pointer; +} + .space-right { margin-right: 5px; } diff --git a/bower.json b/bower.json index 37054c119..2627f8495 100644 --- a/bower.json +++ b/bower.json @@ -47,7 +47,8 @@ "xterm.js": "~2.0.1", "font-awesome": "~4.7.0", "ng-file-upload": "~12.2.13", - "splitargs": "~0.2.0" + "splitargs": "~0.2.0", + "bootbox.js": "bootbox#^4.4.0" }, "resolutions": { "angular": "1.5.5" diff --git a/gruntfile.js b/gruntfile.js index b053ca3ae..4abb9f753 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -139,6 +139,7 @@ module.exports = function (grunt) { 'bower_components/filesize/lib/filesize.min.js', 'bower_components/moment/min/moment.min.js', 'bower_components/xterm.js/dist/xterm.js', + 'bower_components/bootbox.js/bootbox.js', 'assets/js/jquery.gritter.js', // Using custom version to fix error in minified build due to "use strict" 'assets/js/legend.js' // Not a bower package ],