From 7890c809993bf34412b938b4879d25fd9d85036d Mon Sep 17 00:00:00 2001 From: baron_l Date: Thu, 14 Feb 2019 19:18:30 +0100 Subject: [PATCH] feat(storidge): add drives list and details view --- app/extensions/storidge/__module.js | 24 ++++ .../storidgeClusterEventsDatatable.js | 2 +- .../storidgeDrivesDatatable.html | 133 ++++++++++++++++++ .../storidgeDrivesDatatable.js | 14 ++ .../storidgeDrivesDatatableController.js | 16 +++ .../nodes-datatable/storidgeNodesDatatable.js | 2 +- .../storidgeProfilesDatatable.js | 2 +- app/extensions/storidge/filters/filters.js | 15 ++ app/extensions/storidge/models/drive.js | 9 ++ app/extensions/storidge/rest/storidge.js | 7 +- .../storidge/services/driveService.js | 73 ++++++++++ .../storidge/views/drives/drives.html | 22 +++ .../storidge/views/drives/drivesController.js | 73 ++++++++++ .../storidge/views/drives/inspect/drive.html | 58 ++++++++ .../views/drives/inspect/driveController.js | 54 +++++++ app/portainer/views/sidebar/sidebar.html | 7 +- 16 files changed, 505 insertions(+), 6 deletions(-) create mode 100644 app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html create mode 100644 app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js create mode 100644 app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js create mode 100644 app/extensions/storidge/filters/filters.js create mode 100644 app/extensions/storidge/models/drive.js create mode 100644 app/extensions/storidge/services/driveService.js create mode 100644 app/extensions/storidge/views/drives/drives.html create mode 100644 app/extensions/storidge/views/drives/drivesController.js create mode 100644 app/extensions/storidge/views/drives/inspect/drive.html create mode 100644 app/extensions/storidge/views/drives/inspect/driveController.js diff --git a/app/extensions/storidge/__module.js b/app/extensions/storidge/__module.js index 9fe339859..6c2c3a6e6 100644 --- a/app/extensions/storidge/__module.js +++ b/app/extensions/storidge/__module.js @@ -32,6 +32,28 @@ angular.module('extension.storidge', []) } }; + var drives = { + name: 'storidge.drives', + url: '/drives', + views: { + 'content@': { + templateUrl: 'app/extensions/storidge/views/drives/drives.html', + controller: 'StoridgeDrivesController' + } + } + }; + + var drive = { + name: 'storidge.drives.drive', + url: '/:id', + views: { + 'content@': { + templateUrl: 'app/extensions/storidge/views/drives/inspect/drive.html', + controller: 'StoridgeDriveController' + } + } + }; + var profileCreation = { name: 'storidge.profiles.new', url: '/new', @@ -69,6 +91,8 @@ angular.module('extension.storidge', []) }; $stateRegistryProvider.register(storidge); + $stateRegistryProvider.register(drives); + $stateRegistryProvider.register(drive); $stateRegistryProvider.register(profiles); $stateRegistryProvider.register(profile); $stateRegistryProvider.register(profileCreation); diff --git a/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js b/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js index c97cc3ddc..9aabd5496 100644 --- a/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js +++ b/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js @@ -2,7 +2,7 @@ angular.module('extension.storidge').component('storidgeClusterEventsDatatable', templateUrl: 'app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.html', controller: 'GenericDatatableController', bindings: { - title: '@', + titleText: '@', titleIcon: '@', dataset: '<', tableKey: '@', diff --git a/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html new file mode 100644 index 000000000..5da25e4f0 --- /dev/null +++ b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html @@ -0,0 +1,133 @@ +
+ + +
+
+ {{ $ctrl.titleText }} +
+
+
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + Id + + + + + + Node + + + + + + Device + + + + + + Size + + + + + + Use + + + + + + Type + + + + + + Status + + + +
+ + + + + {{ item.Id }} + {{ item.Node }}{{ item.Device }}{{ item.Size }}{{ item.Use }}{{ item.Type }} + {{ item.Status|capitalize }} +
Loading...
No drives available.
+
+ +
+
+
diff --git a/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js new file mode 100644 index 000000000..63e4e5994 --- /dev/null +++ b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js @@ -0,0 +1,14 @@ +angular.module('extension.storidge').component('storidgeDrivesDatatable', { + templateUrl: 'app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html', + controller: 'StoridgeDrivesDatatableController', + bindings: { + titleText: '@', + titleIcon: '@', + dataset: '<', + tableKey: '@', + orderBy: '@', + reverseOrder: '<', + removeAction: '<', + addAction: '<' + } +}); diff --git a/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js new file mode 100644 index 000000000..65f44972b --- /dev/null +++ b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js @@ -0,0 +1,16 @@ +angular.module('portainer.docker') + .controller('StoridgeDrivesDatatableController', ['$scope', '$controller', + function ($scope, $controller) { + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); + + this.selectAll = function() { + for (var i = 0; i < this.state.filteredDataSet.length; i++) { + var item = this.state.filteredDataSet[i]; + if (item.Status !== 'normal' && item.Checked !== this.state.selectAll) { + item.Checked = this.state.selectAll; + this.selectItem(item); + } + } + }; + } +]); \ No newline at end of file diff --git a/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js b/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js index 3731350dd..8fb01f9c4 100644 --- a/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js +++ b/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js @@ -2,7 +2,7 @@ angular.module('extension.storidge').component('storidgeNodesDatatable', { templateUrl: 'app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.html', controller: 'GenericDatatableController', bindings: { - title: '@', + titleText: '@', titleIcon: '@', dataset: '<', tableKey: '@', diff --git a/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js b/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js index 0d0c60a83..1b68eb929 100644 --- a/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js +++ b/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js @@ -2,7 +2,7 @@ angular.module('extension.storidge').component('storidgeProfilesDatatable', { templateUrl: 'app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.html', controller: 'GenericDatatableController', bindings: { - title: '@', + titleText: '@', titleIcon: '@', dataset: '<', tableKey: '@', diff --git a/app/extensions/storidge/filters/filters.js b/app/extensions/storidge/filters/filters.js new file mode 100644 index 000000000..82c9414e7 --- /dev/null +++ b/app/extensions/storidge/filters/filters.js @@ -0,0 +1,15 @@ +angular.module('extension.storidge') +.filter('drivestatusbadge', function () { +'use strict'; + return function (text) { + var status = _.toLower(text); + if (includeString(status, ['normal'])) { + return 'success'; + } else if (includeString(status, ['available'])) { + return 'info'; + } else if (includeString(status, ['faulty'])) { + return 'danger'; + } + return 'info'; + }; +}); \ No newline at end of file diff --git a/app/extensions/storidge/models/drive.js b/app/extensions/storidge/models/drive.js new file mode 100644 index 000000000..32f20fa5c --- /dev/null +++ b/app/extensions/storidge/models/drive.js @@ -0,0 +1,9 @@ +function StoridgeDriveModel(data) { + this.Id = data.driveid; + this.Node = data.node; + this.Use = data.use; + this.Status = data.drivestatus.toLowerCase(); + this.Size = data.size; + this.Type = data.type; + this.Device = data.device; +} diff --git a/app/extensions/storidge/rest/storidge.js b/app/extensions/storidge/rest/storidge.js index d4a7d0793..86a5b70ee 100644 --- a/app/extensions/storidge/rest/storidge.js +++ b/app/extensions/storidge/rest/storidge.js @@ -15,6 +15,11 @@ angular.module('extension.storidge') getProfile: { method: 'GET', params: { resource: 'profiles' } }, createProfile: { method: 'POST', params: { resource: 'profiles' } }, updateProfile: { method: 'PUT', params: { resource: 'profiles', id: '@name' } }, - deleteProfile: { method: 'DELETE', params: { resource: 'profiles' } } + deleteProfile: { method: 'DELETE', params: { resource: 'profiles' } }, + queryDrives: { method: 'GET', params: { resource: 'drives' } }, + getDrive: { method: 'GET', params: { resource: 'drives', id: '@id' } }, + addDrive: { method: 'POST', params: { resource: 'drives' } }, + removeDrive: { method: 'DELETE', params: { resource: 'drives', id: '@id' } }, + getNode: { method: 'GET', params: { resource: 'nodes', id: '@id' } } }); }]); diff --git a/app/extensions/storidge/services/driveService.js b/app/extensions/storidge/services/driveService.js new file mode 100644 index 000000000..d10638c9c --- /dev/null +++ b/app/extensions/storidge/services/driveService.js @@ -0,0 +1,73 @@ +angular.module('extension.storidge') +.factory('StoridgeDriveService', ['$q', 'Storidge', function StoridgeDriveServiceFactory($q, Storidge) { + 'use strict'; + var service = {}; + + service.drives = function () { + var deferred = $q.defer(); + + Storidge.queryDrives().$promise + .then(function success(data) { + var driveData = data.drives; + var drives = driveData.map(function (drive) { + return new StoridgeDriveModel(drive); + }); + + deferred.resolve(drives); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve Storidge drives', err: err }); + }); + + return deferred.promise; + }; + + service.drive = function (id) { + var deferred = $q.defer(); + + Storidge.getDrive({ id: id }).$promise + .then(function success(data) { + var drive = new StoridgeDriveModel(data); + Storidge.getNode({ id: data.nodeid }).$promise + .then(function (data) { + drive.Node = data.name; + deferred.resolve(drive); + }); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to retrieve Storidge drive', err: err }); + }); + + return deferred.promise; + }; + + service.add = function (device, node) { + var deferred = $q.defer(); + + Storidge.addDrive({ device: device, node: node }).$promise + .then(function success() { + deferred.resolve(); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to add Storidge drive', err: err }); + }); + + return deferred.promise; + }; + + service.remove = function (id) { + var deferred = $q.defer(); + + Storidge.removeDrive({ id: id }).$promise + .then(function success() { + deferred.resolve(); + }) + .catch(function error(err) { + deferred.reject({ msg: 'Unable to remove Storidge drive', err: err }); + }); + + return deferred.promise; + }; + + return service; +}]); diff --git a/app/extensions/storidge/views/drives/drives.html b/app/extensions/storidge/views/drives/drives.html new file mode 100644 index 000000000..8a35e8164 --- /dev/null +++ b/app/extensions/storidge/views/drives/drives.html @@ -0,0 +1,22 @@ + + + + + + + + Storidge > Drives + + + +
+
+ +
+
diff --git a/app/extensions/storidge/views/drives/drivesController.js b/app/extensions/storidge/views/drives/drivesController.js new file mode 100644 index 000000000..b41538068 --- /dev/null +++ b/app/extensions/storidge/views/drives/drivesController.js @@ -0,0 +1,73 @@ +angular.module('extension.storidge') +.controller('StoridgeDrivesController', ['$q', '$scope', '$state', 'Notifications', 'ModalService', 'StoridgeDriveService', +function ($q, $scope, $state, Notifications, ModalService, StoridgeDriveService) { + + $scope.removeAction = function(selectedItems) { + ModalService.confirm({ + title: 'Are you sure?', + message: 'Do you want really want to remove this drive from the storage pool?', + buttons: { + confirm: { + label: 'Remove', + className: 'btn-danger' + } + }, + callback: function onConfirm(confirmed) { + if(!confirmed) { return; } + var actionCount = selectedItems.length; + selectedItems = selectedItems.filter(function (item) { + return item.Status === 'faulty'; + }); + angular.forEach(selectedItems, function (drive) { + StoridgeDriveService.delete(drive.Id) + .then(function success() { + Notifications.success('Drive successfully removed', drive.Id); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove drive'); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); + }); + } + }); + }; + + $scope.addAction = function (selectedItems) { + var actionCount = selectedItems.length; + selectedItems = selectedItems.filter(function (item) { + return item.Status === 'available'; + }); + angular.forEach(selectedItems, function (drive) { + StoridgeDriveService.add(drive.Id) + .then(function success() { + Notifications.success('Drive successfully added', drive.Id); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to add drive'); + }) + .finally(function final() { + --actionCount; + if (actionCount === 0) { + $state.reload(); + } + }); + }); + }; + + function initView() { + StoridgeDriveService.drives() + .then(function success(data) { + $scope.drives = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve drives'); + }); + } + + initView(); +}]); diff --git a/app/extensions/storidge/views/drives/inspect/drive.html b/app/extensions/storidge/views/drives/inspect/drive.html new file mode 100644 index 000000000..e07dd12ca --- /dev/null +++ b/app/extensions/storidge/views/drives/inspect/drive.html @@ -0,0 +1,58 @@ + + + + Storidge > Drives > {{ drive.Id }} + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID + {{ drive.Id }} + + +
Node{{ drive.Node }}
Device{{ drive.Device }}
Size{{ drive.Size }}
Use{{ drive.Use }}
Type{{ drive.Type }}
Status + {{ drive.Status|capitalize }} +
+
+
+
+
\ No newline at end of file diff --git a/app/extensions/storidge/views/drives/inspect/driveController.js b/app/extensions/storidge/views/drives/inspect/driveController.js new file mode 100644 index 000000000..b2995c885 --- /dev/null +++ b/app/extensions/storidge/views/drives/inspect/driveController.js @@ -0,0 +1,54 @@ +angular.module('extension.storidge') +.controller('StoridgeDriveController', ['$scope', '$state', '$transition$', 'Notifications', 'StoridgeDriveService', +function ($scope, $state, $transition$, Notifications, StoridgeDriveService) { + + $scope.addDrive = function () { + StoridgeDriveService.add($scope.drive.Device, $scope.drive.Node) + .then(function () { + Notifications.success('Success', 'Drive added to storage pool'); + $state.reload(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to add drive to storage pool'); + }); + }; + + $scope.removeDrive = function () { + ModalService.confirm({ + title: 'Are you sure?', + message: 'Do you want really want to remove this drive from the storage pool?', + buttons: { + confirm: { + label: 'Remove', + className: 'btn-danger' + } + }, + callback: function onConfirm(confirmed) { + if(!confirmed) { return; } + StoridgeDriveService.remove($scope.drive.Id) + .then(function () { + Notifications.success('Success', 'Drive removed from storage pool'); + $state.reload(); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to remove drive from storage pool'); + }); + } + }); + }; + + function initView() { + $scope.id = $transition$.params().id; + + StoridgeDriveService.drive($scope.id) + .then(function success(data) { + $scope.drive = data; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve drive details'); + }); + } + + initView(); + +}]); diff --git a/app/portainer/views/sidebar/sidebar.html b/app/portainer/views/sidebar/sidebar.html index 776a1e35c..e1df0cf0d 100644 --- a/app/portainer/views/sidebar/sidebar.html +++ b/app/portainer/views/sidebar/sidebar.html @@ -29,12 +29,15 @@