diff --git a/app/app.js b/app/app.js index c94961bb2..8ec6554ba 100644 --- a/app/app.js +++ b/app/app.js @@ -21,7 +21,8 @@ angular.module('dockerui', [ 'events', 'stats', 'network', - 'networks']) + 'networks', + 'volumes']) .config(['$routeProvider', function ($routeProvider) { 'use strict'; $routeProvider.when('/', { diff --git a/app/components/masthead/masthead.html b/app/components/masthead/masthead.html index 3bb8a0267..7ff8766a0 100644 --- a/app/components/masthead/masthead.html +++ b/app/components/masthead/masthead.html @@ -5,7 +5,8 @@
  • Containers
  • Containers Network
  • Images
  • -
  • Networks
  • +
  • Networks
  • +
  • Volumes
  • Info
  • diff --git a/app/components/masthead/mastheadController.js b/app/components/masthead/mastheadController.js index 9d12cba42..ae375cab4 100644 --- a/app/components/masthead/mastheadController.js +++ b/app/components/masthead/mastheadController.js @@ -1,4 +1,11 @@ angular.module('masthead', []) - .controller('MastheadController', ['$scope', function ($scope) { + .controller('MastheadController', ['$scope', 'Version', function ($scope, Version) { $scope.template = 'app/components/masthead/masthead.html'; + $scope.showNetworksVolumes = false; + + Version.get(function(d) { + if (d.ApiVersion >= 1.21) { + $scope.showNetworksVolumes = true; + } + }); }]); diff --git a/app/components/volumes/volumes.html b/app/components/volumes/volumes.html new file mode 100644 index 000000000..af8921776 --- /dev/null +++ b/app/components/volumes/volumes.html @@ -0,0 +1,56 @@ +

    Volumes:

    + +
    + + +
    + +
    +
    + + + + + + + + + + + + + + + + + +
    SelectNameDriverMountpoint
    {{ volume.Name|truncate:20 }}{{ volume.Driver }}{{ volume.Mountpoint }}
    +
    +
    +
    +
    + + +
    +
    + + +
    + +
    +
    +
    \ No newline at end of file diff --git a/app/components/volumes/volumesController.js b/app/components/volumes/volumesController.js new file mode 100644 index 000000000..bed59316a --- /dev/null +++ b/app/components/volumes/volumesController.js @@ -0,0 +1,75 @@ +angular.module('volumes', []).config(['$routeProvider', function ($routeProvider) { + $routeProvider.when('/volumes', { + templateUrl: 'app/components/volumes/volumes.html', + controller: 'VolumesController' + }); +}]).controller('VolumesController', ['$scope', 'Volume', 'ViewSpinner', 'Messages', '$route', 'errorMsgFilter', + function ($scope, Volume, ViewSpinner, Messages, $route, errorMsgFilter) { + $scope.toggle = false; + $scope.predicate = '-Created'; + $scope.createVolumeConfig = { + "Name": "", + "Driver": "" + }; + + + + $scope.removeAction = function () { + ViewSpinner.spin(); + var counter = 0; + var complete = function () { + counter = counter - 1; + if (counter === 0) { + ViewSpinner.stop(); + } + }; + angular.forEach($scope.volumes, function (volume) { + if (volume.Checked) { + counter = counter + 1; + Volume.remove({name: volume.Name}, function (d) { + Messages.send("Volume deleted", volume.Name); + var index = $scope.volumes.indexOf(volume); + $scope.volumes.splice(index, 1); + complete(); + }, function (e) { + Messages.error("Failure", e.data); + complete(); + }); + } + }); + }; + + $scope.toggleSelectAll = function () { + angular.forEach($scope.volumes, function (i) { + i.Checked = $scope.toggle; + }); + }; + + $scope.addVolume = function addVolume(createVolumeConfig) { + ViewSpinner.spin(); + Volume.create(createVolumeConfig, function (d) { + if (d.Name) { + Messages.send("Volume created", d.Name); + } else { + Messages.error('Failure', errorMsgFilter(d)); + } + ViewSpinner.stop(); + fetchVolumes(); + }, function (e) { + Messages.error("Failure", e.data); + ViewSpinner.stop(); + }); + }; + + function fetchVolumes() { + ViewSpinner.spin(); + Volume.query({}, function (d) { + $scope.volumes = d.Volumes; + ViewSpinner.stop(); + }, function (e) { + Messages.error("Failure", e.data); + ViewSpinner.stop(); + }); + } + fetchVolumes(); + }]); diff --git a/app/shared/services.js b/app/shared/services.js index 3f48132b5..e0775de67 100644 --- a/app/shared/services.js +++ b/app/shared/services.js @@ -117,7 +117,7 @@ angular.module('dockerui.services', ['ngResource']) get: {method: 'GET'} }); }]) - .factory('Network', ['$resource', 'Settings', function NetworksFactory($resource, Settings) { + .factory('Network', ['$resource', 'Settings', function NetworkFactory($resource, Settings) { 'use strict'; // http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-5-networks return $resource(Settings.url + '/networks/:id/:action', {id: '@id'}, { @@ -129,6 +129,16 @@ angular.module('dockerui.services', ['ngResource']) disconnect: {method: 'POST', params: {action: 'disconnect'}} }); }]) + .factory('Volume', ['$resource', 'Settings', function VolumeFactory($resource, Settings) { + 'use strict'; + // http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-5-networks + return $resource(Settings.url + '/volumes/:name/:action', {name: '@name'}, { + query: {method: 'GET'}, + get: {method: 'GET'}, + create: {method: 'POST', params: {action: 'create'}}, + remove: {method: 'DELETE'} + }); + }]) .factory('Settings', ['DOCKER_ENDPOINT', 'DOCKER_PORT', 'UI_VERSION', function SettingsFactory(DOCKER_ENDPOINT, DOCKER_PORT, UI_VERSION) { 'use strict'; var url = DOCKER_ENDPOINT; diff --git a/test/unit/app/components/volumesController.spec.js b/test/unit/app/components/volumesController.spec.js new file mode 100644 index 000000000..ef567c07a --- /dev/null +++ b/test/unit/app/components/volumesController.spec.js @@ -0,0 +1,64 @@ +describe('VolumesController', function () { + var $scope, $httpBackend, $routeParams; + + beforeEach(module('dockerui')); + beforeEach(inject(function (_$httpBackend_, $controller, _$routeParams_) { + $scope = {}; + $httpBackend = _$httpBackend_; + $routeParams = _$routeParams_; + $controller('VolumesController', { + '$scope': $scope, + '$routeParams': $routeParams + }); + })); + + it('initializes correctly', function () { + expectGetVolumes(); + $httpBackend.flush(); + }); + + + it('issues correct remove calls to the remote API', function () { + expectGetVolumes(); + $httpBackend.flush(); + $scope.volumes[0].Checked = true; + $scope.volumes[2].Checked = true; + $httpBackend.expectDELETE('dockerapi/volumes/tardis').respond(200); + $httpBackend.expectDELETE('dockerapi/volumes/bar').respond(200); + $scope.removeAction(); + $httpBackend.flush(); + }); + it('issues a correct volume creation call to the remote API', function () { + expectGetVolumes(); + var createBody = { + "Name": "tardis", + "Driver": "local" + }; + $httpBackend.expectPOST('dockerapi/volumes/create', createBody).respond(201); + expectGetVolumes(); + $scope.addVolume(createBody); + $httpBackend.flush(); + }); + + function expectGetVolumes() { + $httpBackend.expectGET('dockerapi/volumes').respond({ + "Volumes": [ + { + "Name": "tardis", + "Driver": "local", + "Mountpoint": "/var/lib/docker/volumes/tardis" + }, + { + "Name": "foo", + "Driver": "local", + "Mountpoint": "/var/lib/docker/volumes/foo" + }, + { + "Name": "bar", + "Driver": "local", + "Mountpoint": "/var/lib/docker/volumes/bar" + } + ] + }); + } +}); \ No newline at end of file