From 1138fd5ab148288ef011a45cc353e6d95cee1337 Mon Sep 17 00:00:00 2001 From: xAt0mZ Date: Tue, 2 Jul 2019 17:51:17 +0200 Subject: [PATCH] fix(datatables): allow selecting range using shift (#344) (#2962) * fix(datatables): allow selecting range using shift (#344) * feat(datatables): more intuitive batch select behaviour * feat(datatables): add overridable function called on selection change * refactor(datatables): remove custom selectAll on Generic-extending Controllers * fix(datatables): stored state data retrieval on Generic-extanding datatables controllers * refactor(datatables): remove code duplication between GenericController and extending controllers --- .../containerGroupsDatatable.html | 2 +- .../configs-datatable/configsDatatable.html | 2 +- .../containersDatatable.html | 2 +- .../containersDatatableController.js | 83 +++------- .../jobsDatatableController.js | 52 ++---- .../images-datatable/imagesDatatable.html | 14 +- .../imagesDatatableController.js | 82 +++------- .../macvlanNodesDatatable.html | 2 +- .../networks-datatable/networksDatatable.html | 2 +- .../networksDatatableController.js | 41 +++-- .../secrets-datatable/secretsDatatable.html | 2 +- .../serviceTasksDatatableController.js | 149 +++++++++--------- .../services-datatable/servicesDatatable.html | 2 +- .../servicesDatatableController.js | 77 +++------ .../tasksDatatableController.js | 70 +++----- .../volumes-datatable/volumesDatatable.html | 14 +- .../volumesDatatableController.js | 82 +++------- .../registryRepositoriesDatatable.html | 2 +- .../registriesRepositoryTagsDatatable.html | 2 +- .../storidgeDrivesDatatableController.js | 37 +++-- .../storidgeNodesDatatableController.js | 29 +++- .../storidgeProfilesDatatable.html | 2 +- .../storidgeSnapshotsDatatable.html | 2 +- .../storidgeSnapshotsDatatable.js | 2 +- .../storidgeSnapshotsDatatableController.js | 7 - .../access-datatable/accessDatatable.html | 2 +- .../accessDatatableController.js | 37 +++-- .../components/datatables/datatable.css | 1 + .../endpointsDatatable.html | 2 +- .../datatables/genericDatatableController.js | 95 +++++++++-- .../groups-datatable/groupsDatatable.html | 2 +- .../registriesDatatable.html | 2 +- .../schedulesDatatable.html | 2 +- .../schedulesDatatableController.js | 79 ++++------ .../stacks-datatable/stacksDatatable.html | 2 +- .../stacksDatatableController.js | 68 +++----- .../tags-datatable/tagsDatatable.html | 2 +- .../teams-datatable/teamsDatatable.html | 2 +- .../users-datatable/usersDatatable.html | 2 +- 39 files changed, 477 insertions(+), 582 deletions(-) delete mode 100644 app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatableController.js diff --git a/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html b/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html index 9f85333b7..ae7a459ce 100644 --- a/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html +++ b/app/azure/components/datatables/containergroups-datatable/containerGroupsDatatable.html @@ -50,7 +50,7 @@ - + {{ item.Name | truncate:50 }} diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.html b/app/docker/components/datatables/configs-datatable/configsDatatable.html index 623359a4b..4e127d605 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.html +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.html @@ -54,7 +54,7 @@ - + {{ item.Name }} diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.html b/app/docker/components/datatables/containers-datatable/containersDatatable.html index 86c26ae37..1ecd6d223 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.html +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.html @@ -217,7 +217,7 @@ - + {{ item | containername | truncate: $ctrl.settings.containerNameTruncateSize }} diff --git a/app/docker/components/datatables/containers-datatable/containersDatatableController.js b/app/docker/components/datatables/containers-datatable/containersDatatableController.js index 337f794bc..b09b0bc7b 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatableController.js +++ b/app/docker/components/datatables/containers-datatable/containersDatatableController.js @@ -1,22 +1,19 @@ import _ from 'lodash-es'; angular.module('portainer.docker') -.controller('ContainersDatatableController', ['PaginationService', 'DatatableService', 'EndpointProvider', -function (PaginationService, DatatableService, EndpointProvider) { +.controller('ContainersDatatableController', ['$scope', '$controller', 'DatatableService', 'EndpointProvider', +function ($scope, $controller, DatatableService, EndpointProvider) { + + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); + var ctrl = this; - this.state = { - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [], + this.state = Object.assign(this.state, { noStoppedItemsSelected: true, noRunningItemsSelected: true, noPausedItemsSelected: true, publicURL: EndpointProvider.endpointPublicURL() - }; + }); this.settings = { open: false, @@ -81,45 +78,13 @@ function (PaginationService, DatatableService, EndpointProvider) { } }; - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - this.onColumnVisibilityChange = function() { DatatableService.setColumnVisibilitySettings(this.tableKey, this.columnVisibility); }; - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.toggleItemSelection = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectItem = function(item) { - this.toggleItemSelection(item); + this.onSelectionChanged = function() { this.updateSelectionState(); - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.toggleItemSelection(item); - } - } - this.updateSelectionState(); - }; + } this.updateSelectionState = function() { this.state.noStoppedItemsSelected = true; @@ -144,10 +109,6 @@ function (PaginationService, DatatableService, EndpointProvider) { } }; - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; - this.applyFilters = function(value) { var container = value; var filters = ctrl.filters; @@ -209,40 +170,38 @@ function (PaginationService, DatatableService, EndpointProvider) { }; this.$onInit = function() { - setDefaults(this); + this.setDefaults(); this.prepareTableFromDataset(); + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { this.state.reverseOrder = storedOrder.reverse; this.state.orderBy = storedOrder.orderBy; } + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); if (storedFilters !== null) { + this.filters = storedFilters; + this.filters.state.open = false; this.updateStoredFilters(storedFilters.state.values); } - this.filters.state.open = false; var storedSettings = DatatableService.getDataTableSettings(this.tableKey); if (storedSettings !== null) { this.settings = storedSettings; + this.settings.open = false; } - this.settings.open = false; var storedColumnVisibility = DatatableService.getColumnVisibilitySettings(this.tableKey); if (storedColumnVisibility !== null) { this.columnVisibility = storedColumnVisibility; - } - this.columnVisibility.state.open = false; - - var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); - if (textFilter !== null) { - this.state.textFilter = textFilter; + this.columnVisibility.state.open = false; } }; - - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } }]); diff --git a/app/docker/components/datatables/host-jobs-datatable/jobsDatatableController.js b/app/docker/components/datatables/host-jobs-datatable/jobsDatatableController.js index d156c0d88..71d1c6a14 100644 --- a/app/docker/components/datatables/host-jobs-datatable/jobsDatatableController.js +++ b/app/docker/components/datatables/host-jobs-datatable/jobsDatatableController.js @@ -1,15 +1,12 @@ import _ from 'lodash-es'; angular.module('portainer.docker') - .controller('JobsDatatableController', ['$q', '$state', 'PaginationService', 'DatatableService', 'ContainerService', 'ModalService', 'Notifications', - function ($q, $state, PaginationService, DatatableService, ContainerService, ModalService, Notifications) { - var ctrl = this; + .controller('JobsDatatableController', ['$scope', '$controller', '$q', '$state', 'PaginationService', 'DatatableService', 'ContainerService', 'ModalService', 'Notifications', + function ($scope, $controller, $q, $state, PaginationService, DatatableService, ContainerService, ModalService, Notifications) { - this.state = { - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false - }; + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); + + var ctrl = this; this.filters = { state: { @@ -19,20 +16,6 @@ angular.module('portainer.docker') } }; - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - - this.changeOrderBy = function (orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.changePaginationLimit = function () { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; - this.applyFilters = function (value) { var container = value; var filters = ctrl.filters; @@ -121,8 +104,8 @@ angular.module('portainer.docker') }); }; - this.$onInit = function () { - setDefaults(this); + this.$onInit = function() { + this.setDefaults(); this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); @@ -131,21 +114,20 @@ angular.module('portainer.docker') this.state.orderBy = storedOrder.orderBy; } - var storedFilters = DatatableService.getDataTableFilters(this.tableKey); - if (storedFilters !== null) { - this.updateStoredFilters(storedFilters.state.values); - } - this.filters.state.open = false; - var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); if (textFilter !== null) { this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + this.updateStoredFilters(storedFilters.state.values); + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; - - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } } ]); diff --git a/app/docker/components/datatables/images-datatable/imagesDatatable.html b/app/docker/components/datatables/images-datatable/imagesDatatable.html index de6c720c5..b2e1506ee 100644 --- a/app/docker/components/datatables/images-datatable/imagesDatatable.html +++ b/app/docker/components/datatables/images-datatable/imagesDatatable.html @@ -43,7 +43,7 @@ -
+ @@ -54,8 +54,8 @@
- Filter - Filter + Filter + Filter
@@ -112,7 +112,7 @@
- + {{ item.Id | truncate:40 }} diff --git a/app/docker/components/datatables/images-datatable/imagesDatatableController.js b/app/docker/components/datatables/images-datatable/imagesDatatableController.js index c197ccc64..afd0a0930 100644 --- a/app/docker/components/datatables/images-datatable/imagesDatatableController.js +++ b/app/docker/components/datatables/images-datatable/imagesDatatableController.js @@ -1,20 +1,13 @@ angular.module('portainer.docker') -.controller('ImagesDatatableController', ['PaginationService', 'DatatableService', -function (PaginationService, DatatableService) { +.controller('ImagesDatatableController', ['$scope', '$controller', 'DatatableService', +function ($scope, $controller, DatatableService) { + + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); var ctrl = this; - this.state = { - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [] - }; - this.filters = { - usage: { + state: { open: false, enabled: false, showUsedImages: true, @@ -22,62 +15,29 @@ function (PaginationService, DatatableService) { } }; - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } - } - }; - - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; - this.applyFilters = function(value) { var image = value; var filters = ctrl.filters; - if ((image.ContainerCount === 0 && filters.usage.showUnusedImages) - || (image.ContainerCount !== 0 && filters.usage.showUsedImages)) { + if ((image.ContainerCount === 0 && filters.state.showUnusedImages) + || (image.ContainerCount !== 0 && filters.state.showUsedImages)) { return true; } return false; }; - this.onUsageFilterChange = function() { - var filters = this.filters.usage; + this.onstateFilterChange = function() { + var filters = this.filters.state; var filtered = false; if (!filters.showUsedImages || !filters.showUnusedImages) { filtered = true; } - this.filters.usage.enabled = filtered; + this.filters.state.enabled = filtered; DatatableService.setDataTableFilters(this.tableKey, this.filters); }; this.$onInit = function() { - setDefaults(this); + this.setDefaults(); + this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { @@ -85,20 +45,18 @@ function (PaginationService, DatatableService) { this.state.orderBy = storedOrder.orderBy; } + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); if (storedFilters !== null) { this.filters = storedFilters; } - this.filters.usage.open = false; - - var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); - if (textFilter !== null) { - this.state.textFilter = textFilter; + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; - - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } }]); diff --git a/app/docker/components/datatables/macvlan-nodes-datatable/macvlanNodesDatatable.html b/app/docker/components/datatables/macvlan-nodes-datatable/macvlanNodesDatatable.html index f4a65f6c2..574aa2fe6 100644 --- a/app/docker/components/datatables/macvlan-nodes-datatable/macvlanNodesDatatable.html +++ b/app/docker/components/datatables/macvlan-nodes-datatable/macvlanNodesDatatable.html @@ -60,7 +60,7 @@ ng-class="{active: item.Checked}"> - + {{ item.Hostname }} diff --git a/app/docker/components/datatables/networks-datatable/networksDatatable.html b/app/docker/components/datatables/networks-datatable/networksDatatable.html index df718e7a4..1a7deb6de 100644 --- a/app/docker/components/datatables/networks-datatable/networksDatatable.html +++ b/app/docker/components/datatables/networks-datatable/networksDatatable.html @@ -110,7 +110,7 @@
- + {{ item.Name | truncate:40 }} diff --git a/app/docker/components/datatables/networks-datatable/networksDatatableController.js b/app/docker/components/datatables/networks-datatable/networksDatatableController.js index 8c9afd635..6ebdb1884 100644 --- a/app/docker/components/datatables/networks-datatable/networksDatatableController.js +++ b/app/docker/components/datatables/networks-datatable/networksDatatableController.js @@ -1,19 +1,42 @@ angular.module('portainer.docker') - .controller('NetworksDatatableController', ['$scope', '$controller', 'PREDEFINED_NETWORKS', - function ($scope, $controller, PREDEFINED_NETWORKS) { + .controller('NetworksDatatableController', ['$scope', '$controller', 'PREDEFINED_NETWORKS', 'DatatableService', + function ($scope, $controller, PREDEFINED_NETWORKS, DatatableService) { + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); this.disableRemove = function(item) { return PREDEFINED_NETWORKS.includes(item.Name); }; - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (!this.disableRemove(item) && item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } + /** + * Do not allow PREDEFINED_NETWORKS to be selected + */ + this.allowSelection = function(item) { + return !this.disableRemove(item); + } + + this.$onInit = function() { + this.setDefaults(); + this.prepareTableFromDataset(); + + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } + + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; } diff --git a/app/docker/components/datatables/secrets-datatable/secretsDatatable.html b/app/docker/components/datatables/secrets-datatable/secretsDatatable.html index 8db6b2e5c..24f4d45bb 100644 --- a/app/docker/components/datatables/secrets-datatable/secretsDatatable.html +++ b/app/docker/components/datatables/secrets-datatable/secretsDatatable.html @@ -54,7 +54,7 @@
- + {{ item.Name }} diff --git a/app/docker/components/datatables/service-tasks-datatable/serviceTasksDatatableController.js b/app/docker/components/datatables/service-tasks-datatable/serviceTasksDatatableController.js index ddd9a0b34..6ecd9ab24 100644 --- a/app/docker/components/datatables/service-tasks-datatable/serviceTasksDatatableController.js +++ b/app/docker/components/datatables/service-tasks-datatable/serviceTasksDatatableController.js @@ -1,77 +1,84 @@ import _ from 'lodash-es'; angular.module('portainer.docker') -.controller('ServiceTasksDatatableController', ['DatatableService', -function (DatatableService) { - var ctrl = this; + .controller('ServiceTasksDatatableController', ['$scope', '$controller', 'DatatableService', + function ($scope, $controller, DatatableService) { - this.state = { - orderBy: this.orderBy, - showQuickActionStats: true, - showQuickActionLogs: true, - showQuickActionExec: true, - showQuickActionInspect: true, - showQuickActionAttach: false - }; + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); - this.filters = { - state: { - open: false, - enabled: false, - values: [] + var ctrl = this; + + this.state = Object.assign(this.state, { + showQuickActionStats: true, + showQuickActionLogs: true, + showQuickActionConsole: true, + showQuickActionInspect: true, + showQuickActionAttach: false + }); + + this.filters = { + state: { + open: false, + enabled: false, + values: [] + } + }; + + this.applyFilters = function(item) { + var filters = ctrl.filters; + for (var i = 0; i < filters.state.values.length; i++) { + var filter = filters.state.values[i]; + if (item.Status.State === filter.label && filter.display) { + return true; + } + } + return false; + }; + + this.onStateFilterChange = function() { + var filters = this.filters.state.values; + var filtered = false; + for (var i = 0; i < filters.length; i++) { + var filter = filters[i]; + if (!filter.display) { + filtered = true; + } + } + this.filters.state.enabled = filtered; + }; + + this.prepareTableFromDataset = function() { + var availableStateFilters = []; + for (var i = 0; i < this.dataset.length; i++) { + var item = this.dataset[i]; + availableStateFilters.push({ label: item.Status.State, display: true }); + } + this.filters.state.values = _.uniqBy(availableStateFilters, 'label'); + }; + + this.$onInit = function() { + this.setDefaults(); + this.prepareTableFromDataset(); + + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } + + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; + } + }; } - }; - - this.applyFilters = function(item) { - var filters = ctrl.filters; - for (var i = 0; i < filters.state.values.length; i++) { - var filter = filters.state.values[i]; - if (item.Status.State === filter.label && filter.display) { - return true; - } - } - return false; - }; - - this.onStateFilterChange = function() { - var filters = this.filters.state.values; - var filtered = false; - for (var i = 0; i < filters.length; i++) { - var filter = filters[i]; - if (!filter.display) { - filtered = true; - } - } - this.filters.state.enabled = filtered; - }; - - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.prepareTableFromDataset = function() { - var availableStateFilters = []; - for (var i = 0; i < this.dataset.length; i++) { - var item = this.dataset[i]; - availableStateFilters.push({ label: item.Status.State, display: true }); - } - this.filters.state.values = _.uniqBy(availableStateFilters, 'label'); - }; - - this.$onInit = function() { - setDefaults(this); - this.prepareTableFromDataset(); - - var storedOrder = DatatableService.getDataTableOrder(this.tableKey); - if (storedOrder !== null) { - this.state.reverseOrder = storedOrder.reverse; - this.state.orderBy = storedOrder.orderBy; - } - }; - - function setDefaults(ctrl) { - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } -}]); +]); diff --git a/app/docker/components/datatables/services-datatable/servicesDatatable.html b/app/docker/components/datatables/services-datatable/servicesDatatable.html index e941aee41..214b13edf 100644 --- a/app/docker/components/datatables/services-datatable/servicesDatatable.html +++ b/app/docker/components/datatables/services-datatable/servicesDatatable.html @@ -84,7 +84,7 @@
- + diff --git a/app/docker/components/datatables/services-datatable/servicesDatatableController.js b/app/docker/components/datatables/services-datatable/servicesDatatableController.js index adee53500..7e32ad996 100644 --- a/app/docker/components/datatables/services-datatable/servicesDatatableController.js +++ b/app/docker/components/datatables/services-datatable/servicesDatatableController.js @@ -1,52 +1,18 @@ import _ from 'lodash-es'; angular.module('portainer.docker') -.controller('ServicesDatatableController', ['PaginationService', 'DatatableService', 'EndpointProvider', -function (PaginationService, DatatableService, EndpointProvider) { +.controller('ServicesDatatableController', ['$scope', '$controller', 'DatatableService', 'EndpointProvider', +function ($scope, $controller, DatatableService, EndpointProvider) { + + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); var ctrl = this; - this.state = { - selectAll: false, + this.state = Object.assign(this.state,{ expandAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [], expandedItems: [], publicURL: EndpointProvider.endpointPublicURL() - }; - - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } - } - }; + }); this.expandAll = function() { this.state.expandAll = !this.state.expandAll; @@ -56,10 +22,6 @@ function (PaginationService, DatatableService, EndpointProvider) { } }; - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; - this.expandItem = function(item, expanded) { item.Expanded = expanded; if (item.Expanded) { @@ -103,7 +65,8 @@ function (PaginationService, DatatableService, EndpointProvider) { }; this.$onInit = function() { - setDefaults(this); + this.setDefaults(); + this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { @@ -111,19 +74,23 @@ function (PaginationService, DatatableService, EndpointProvider) { this.state.orderBy = storedOrder.orderBy; } + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; + } + var storedExpandedItems = DatatableService.getDataTableExpandedItems(this.tableKey); if (storedExpandedItems !== null) { this.expandItems(storedExpandedItems); } - - var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); - if (textFilter !== null) { - this.state.textFilter = textFilter; - } }; - - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } }]); diff --git a/app/docker/components/datatables/tasks-datatable/tasksDatatableController.js b/app/docker/components/datatables/tasks-datatable/tasksDatatableController.js index eabf6202b..75e6d99c1 100644 --- a/app/docker/components/datatables/tasks-datatable/tasksDatatableController.js +++ b/app/docker/components/datatables/tasks-datatable/tasksDatatableController.js @@ -1,56 +1,20 @@ angular.module('portainer.docker') -.controller('TasksDatatableController', ['PaginationService', 'DatatableService', -function (PaginationService, DatatableService) { - this.state = { +.controller('TasksDatatableController', ['$scope', '$controller', 'DatatableService', +function ($scope, $controller, DatatableService) { + + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); + + this.state = Object.assign(this.state, { showQuickActionStats: true, showQuickActionLogs: true, showQuickActionExec: true, showQuickActionInspect: true, - showQuickActionAttach: false, - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [] - }; - - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } - } - }; - - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; + showQuickActionAttach: false + }); this.$onInit = function() { - setDefaults(this); + this.setDefaults(); + this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { @@ -61,11 +25,15 @@ function (PaginationService, DatatableService) { var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); if (textFilter !== null) { this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; - - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } }]); diff --git a/app/docker/components/datatables/volumes-datatable/volumesDatatable.html b/app/docker/components/datatables/volumes-datatable/volumesDatatable.html index 211759c46..c42c7e2a5 100644 --- a/app/docker/components/datatables/volumes-datatable/volumesDatatable.html +++ b/app/docker/components/datatables/volumes-datatable/volumesDatatable.html @@ -23,7 +23,7 @@ -
+ @@ -34,8 +34,8 @@
- Filter - Filter + Filter + Filter
@@ -106,7 +106,7 @@
- + {{ item.Id | truncate:40 }} diff --git a/app/docker/components/datatables/volumes-datatable/volumesDatatableController.js b/app/docker/components/datatables/volumes-datatable/volumesDatatableController.js index e7a88dd96..81bb158fb 100644 --- a/app/docker/components/datatables/volumes-datatable/volumesDatatableController.js +++ b/app/docker/components/datatables/volumes-datatable/volumesDatatableController.js @@ -1,20 +1,13 @@ angular.module('portainer.docker') -.controller('VolumesDatatableController', ['PaginationService', 'DatatableService', -function (PaginationService, DatatableService) { +.controller('VolumesDatatableController', ['$scope', '$controller', 'DatatableService', +function ($scope, $controller, DatatableService) { + + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); var ctrl = this; - this.state = { - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [] - }; - this.filters = { - usage: { + state: { open: false, enabled: false, showUsedVolumes: true, @@ -22,62 +15,29 @@ function (PaginationService, DatatableService) { } }; - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } - } - }; - - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; - this.applyFilters = function(value) { var volume = value; var filters = ctrl.filters; - if ((volume.dangling && filters.usage.showUnusedVolumes) - || (!volume.dangling && filters.usage.showUsedVolumes)) { + if ((volume.dangling && filters.state.showUnusedVolumes) + || (!volume.dangling && filters.state.showUsedVolumes)) { return true; } return false; }; - this.onUsageFilterChange = function() { - var filters = this.filters.usage; + this.onstateFilterChange = function() { + var filters = this.filters.state; var filtered = false; if (!filters.showUsedVolumes || !filters.showUnusedVolumes) { filtered = true; } - this.filters.usage.enabled = filtered; + this.filters.state.enabled = filtered; DatatableService.setDataTableFilters(this.tableKey, this.filters); }; this.$onInit = function() { - setDefaults(this); + this.setDefaults(); + this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { @@ -85,20 +45,18 @@ function (PaginationService, DatatableService) { this.state.orderBy = storedOrder.orderBy; } + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); if (storedFilters !== null) { this.filters = storedFilters; } - this.filters.usage.open = false; - - var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); - if (textFilter !== null) { - this.state.textFilter = textFilter; + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; - - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } }]); diff --git a/app/extensions/registry-management/components/registries-repositories-datatable/registryRepositoriesDatatable.html b/app/extensions/registry-management/components/registries-repositories-datatable/registryRepositoriesDatatable.html index c416605a3..7ea3164b1 100644 --- a/app/extensions/registry-management/components/registries-repositories-datatable/registryRepositoriesDatatable.html +++ b/app/extensions/registry-management/components/registries-repositories-datatable/registryRepositoriesDatatable.html @@ -39,7 +39,7 @@ ng-class="{active: item.Checked}"> - + - + {{ item.Name }} diff --git a/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js b/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js index 65f44972b..b70bae033 100644 --- a/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js +++ b/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js @@ -1,15 +1,34 @@ angular.module('portainer.docker') - .controller('StoridgeDrivesDatatableController', ['$scope', '$controller', - function ($scope, $controller) { + .controller('StoridgeDrivesDatatableController', ['$scope', '$controller', 'DatatableService', + function ($scope, $controller, DatatableService) { 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); - } + this.allowSelection = function (item) { + return item.Status !== 'normal'; + }; + + this.$onInit = function() { + this.setDefaults(); + this.prepareTableFromDataset(); + + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } + + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; } diff --git a/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js b/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js index 517b6566c..c3b2e635d 100644 --- a/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js +++ b/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js @@ -1,6 +1,6 @@ angular.module('portainer.integrations.storidge') -.controller('StoridgeNodesDatatableController', ['$scope', '$controller', 'clipboard', 'Notifications', 'StoridgeNodeService', -function($scope, $controller, clipboard, Notifications, StoridgeNodeService) { +.controller('StoridgeNodesDatatableController', ['$scope', '$controller', 'clipboard', 'Notifications', 'StoridgeNodeService', 'DatatableService', +function($scope, $controller, clipboard, Notifications, StoridgeNodeService, DatatableService) { angular.extend(this, $controller('GenericDatatableController', { $scope: $scope })); var ctrl = this; @@ -20,4 +20,29 @@ function($scope, $controller, clipboard, Notifications, StoridgeNodeService) { $('#copyNotification').show(); $('#copyNotification').fadeOut(2000); }; + + this.$onInit = function() { + this.setDefaults(); + this.prepareTableFromDataset(); + + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } + + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; + } + }; }]); diff --git a/app/integrations/storidge/components/profiles-datatable/storidgeProfilesDatatable.html b/app/integrations/storidge/components/profiles-datatable/storidgeProfilesDatatable.html index 594e1d079..36147404f 100644 --- a/app/integrations/storidge/components/profiles-datatable/storidgeProfilesDatatable.html +++ b/app/integrations/storidge/components/profiles-datatable/storidgeProfilesDatatable.html @@ -37,7 +37,7 @@
- + {{ item.Name }} diff --git a/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.html b/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.html index bd652567a..915e07280 100644 --- a/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.html +++ b/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.html @@ -51,7 +51,7 @@
- + {{ item.Id }} diff --git a/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.js b/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.js index ee0ef830d..e479f7c29 100644 --- a/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.js +++ b/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.js @@ -1,6 +1,6 @@ angular.module('portainer.integrations.storidge').component('storidgeSnapshotsDatatable', { templateUrl: './storidgeSnapshotsDatatable.html', - controller: 'StoridgeSnapshotsDatatableController', + controller: 'GenericDatatableController', bindings: { titleText: '@', titleIcon: '@', diff --git a/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatableController.js b/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatableController.js deleted file mode 100644 index 501a74343..000000000 --- a/app/integrations/storidge/components/snapshots-datatable/storidgeSnapshotsDatatableController.js +++ /dev/null @@ -1,7 +0,0 @@ -angular.module('portainer.docker') - .controller('StoridgeSnapshotsDatatableController', ['$scope', '$controller', - function ($scope, $controller) { - angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); - - } -]); \ No newline at end of file diff --git a/app/portainer/components/access-datatable/accessDatatable.html b/app/portainer/components/access-datatable/accessDatatable.html index 7defc92a7..2d33f779e 100644 --- a/app/portainer/components/access-datatable/accessDatatable.html +++ b/app/portainer/components/access-datatable/accessDatatable.html @@ -70,7 +70,7 @@ + ng-click="$ctrl.selectItem(item, $event)" /> {{ item.Name }} diff --git a/app/portainer/components/access-datatable/accessDatatableController.js b/app/portainer/components/access-datatable/accessDatatableController.js index 7004fb81c..de143c72d 100644 --- a/app/portainer/components/access-datatable/accessDatatableController.js +++ b/app/portainer/components/access-datatable/accessDatatableController.js @@ -1,19 +1,38 @@ angular.module('portainer.app') - .controller('AccessDatatableController', ['$scope', '$controller', - function ($scope, $controller) { + .controller('AccessDatatableController', ['$scope', '$controller', 'DatatableService', + function ($scope, $controller, DatatableService) { angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); this.disableRemove = function(item) { return item.Inherited; }; - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (!this.disableRemove(item) && item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } + this.allowSelection = function(item) { + return !this.disableRemove(item); + }; + + this.$onInit = function() { + this.setDefaults(); + this.prepareTableFromDataset(); + + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } + + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; } diff --git a/app/portainer/components/datatables/datatable.css b/app/portainer/components/datatables/datatable.css index 8f95085d5..10259d119 100644 --- a/app/portainer/components/datatables/datatable.css +++ b/app/portainer/components/datatables/datatable.css @@ -145,6 +145,7 @@ left: 0; position: absolute; top: 0; + pointer-events: none; } .md-checkbox label:before { diff --git a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html index d83793598..e61721001 100644 --- a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html +++ b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html @@ -62,7 +62,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/genericDatatableController.js b/app/portainer/components/datatables/genericDatatableController.js index 3fb1db1c8..21af10060 100644 --- a/app/portainer/components/datatables/genericDatatableController.js +++ b/app/portainer/components/datatables/genericDatatableController.js @@ -1,5 +1,10 @@ +import _ from 'lodash-es'; import './datatable.css'; +function isBetween(value, a, b) { + return (value >= a && value <= b) || (value >= b && value <= a) ; +} + angular.module('portainer.app') .controller('GenericDatatableController', ['PaginationService', 'DatatableService', 'PAGINATION_MAX_ITEMS', function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { @@ -9,7 +14,9 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { orderBy: this.orderBy, paginatedItemLimit: PAGINATION_MAX_ITEMS, displayTextFilter: false, - selectedItemCount: 0, + get selectedItemCount() { + return this.selectedItems.length || 0; + }, selectedItems: [] }; @@ -24,32 +31,86 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); }; - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; + this.selectItem = function(item, event) { + // Handle range select using shift + if (event && event.originalEvent.shiftKey && this.state.firstClickedItem) { + const firstItemIndex = this.state.filteredDataSet.indexOf(this.state.firstClickedItem); + const lastItemIndex = this.state.filteredDataSet.indexOf(item); + const itemsInRange = _.filter(this.state.filteredDataSet, (item, index) => { + return isBetween(index, firstItemIndex, lastItemIndex); + }); + const value = item.Checked; + + _.forEach(itemsInRange, (i) => { + if (!this.allowSelection(i)) { + return; + } + i.Checked = value; + }); + this.state.firstClickedItem = item; + } else if (event) { + this.state.firstClickedItem = item; } + this.state.selectedItems = this.state.filteredDataSet.filter(i => i.Checked); + if (event && this.state.selectAll && this.state.selectedItems.length !== this.state.filteredDataSet.length) { + this.state.selectAll = false; + } + this.onSelectionChanged(); }; this.selectAll = function() { + this.state.firstClickedItem = null; for (var i = 0; i < this.state.filteredDataSet.length; i++) { var item = this.state.filteredDataSet[i]; - if (item.Checked !== this.state.selectAll) { + if (this.allowSelection(item) && item.Checked !== this.state.selectAll) { item.Checked = this.state.selectAll; this.selectItem(item); } } + this.onSelectionChanged(); }; + /** + * Override this method to allow/deny selection + */ + this.allowSelection = function(/*item*/) { + return true; + } + + /** + * Override this method to prepare data table + */ + this.prepareTableFromDataset = function() { + return; + } + + /** + * Override this method to execute code after selection changed on datatable + */ + this.onSelectionChanged = function () { + return; + } + this.changePaginationLimit = function() { PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); }; + this.setDefaults = function() { + this.showTextFilter = this.showTextFilter ? this.showTextFilter : false; + this.state.reverseOrder = this.reverseOrder ? this.reverseOrder : false; + this.state.paginatedItemLimit = PaginationService.getPaginationLimit(this.tableKey); + } + + /** + * Duplicate this function when extending GenericDatatableController + * Extending-controller's bindings are not accessible there + * For more details see the following comments + * https://github.com/portainer/portainer/pull/2877#issuecomment-503333425 + * https://github.com/portainer/portainer/pull/2877#issuecomment-503537249 + */ this.$onInit = function() { - setDefaults(this); + this.setDefaults(); + this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { @@ -62,11 +123,13 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { this.state.textFilter = textFilter; this.onTextFilterChange(); } - }; - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - ctrl.state.paginatedItemLimit = PaginationService.getPaginationLimit(ctrl.tableKey); - } + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; + } + }; }]); diff --git a/app/portainer/components/datatables/groups-datatable/groupsDatatable.html b/app/portainer/components/datatables/groups-datatable/groupsDatatable.html index 003469270..64a63c413 100644 --- a/app/portainer/components/datatables/groups-datatable/groupsDatatable.html +++ b/app/portainer/components/datatables/groups-datatable/groupsDatatable.html @@ -41,7 +41,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/registries-datatable/registriesDatatable.html b/app/portainer/components/datatables/registries-datatable/registriesDatatable.html index 58377e2c3..f26e77443 100644 --- a/app/portainer/components/datatables/registries-datatable/registriesDatatable.html +++ b/app/portainer/components/datatables/registries-datatable/registriesDatatable.html @@ -48,7 +48,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/schedules-datatable/schedulesDatatable.html b/app/portainer/components/datatables/schedules-datatable/schedulesDatatable.html index adccfff95..86134c34e 100644 --- a/app/portainer/components/datatables/schedules-datatable/schedulesDatatable.html +++ b/app/portainer/components/datatables/schedules-datatable/schedulesDatatable.html @@ -54,7 +54,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js b/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js index bac777070..498e72ff3 100644 --- a/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js +++ b/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js @@ -1,58 +1,39 @@ angular.module('portainer.app') -.controller('SchedulesDatatableController', ['PaginationService', 'DatatableService', -function (PaginationService, DatatableService) { + .controller('SchedulesDatatableController', ['$scope', '$controller', 'DatatableService', + function ($scope, $controller, DatatableService) { - this.state = { - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [] - }; + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (item.JobType ===1 && item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); + /** + * Do not allow items + */ + this.allowSelection = function(item) { + return item.JobType === 1 } - } - }; - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; + this.$onInit = function() { + this.setDefaults(); + this.prepareTableFromDataset(); - this.$onInit = function() { - setDefaults(this); + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } - var storedOrder = DatatableService.getDataTableOrder(this.tableKey); - if (storedOrder !== null) { - this.state.reverseOrder = storedOrder.reverse; - this.state.orderBy = storedOrder.orderBy; - } - }; + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; + } + }; } -}]); +]); diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html index c149d58fc..6bd6852f3 100644 --- a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html +++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html @@ -55,7 +55,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatableController.js b/app/portainer/components/datatables/stacks-datatable/stacksDatatableController.js index a1d735964..6c8457cd6 100644 --- a/app/portainer/components/datatables/stacks-datatable/stacksDatatableController.js +++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatableController.js @@ -1,52 +1,19 @@ angular.module('portainer.app') -.controller('StacksDatatableController', ['PaginationService', 'DatatableService', -function (PaginationService, DatatableService) { +.controller('StacksDatatableController', ['$scope', '$controller', 'DatatableService', +function ($scope, $controller, DatatableService) { - this.state = { - selectAll: false, - orderBy: this.orderBy, - paginatedItemLimit: PaginationService.getPaginationLimit(this.tableKey), - displayTextFilter: false, - selectedItemCount: 0, - selectedItems: [] - }; + angular.extend(this, $controller('GenericDatatableController', {$scope: $scope})); - this.onTextFilterChange = function() { - DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); - }; - - this.changeOrderBy = function(orderField) { - this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false; - this.state.orderBy = orderField; - DatatableService.setDataTableOrder(this.tableKey, orderField, this.state.reverseOrder); - }; - - this.selectItem = function(item) { - if (item.Checked) { - this.state.selectedItemCount++; - this.state.selectedItems.push(item); - } else { - this.state.selectedItems.splice(this.state.selectedItems.indexOf(item), 1); - this.state.selectedItemCount--; - } - }; - - this.selectAll = function() { - for (var i = 0; i < this.state.filteredDataSet.length; i++) { - var item = this.state.filteredDataSet[i]; - if (!(item.External && item.Type === 2) && item.Checked !== this.state.selectAll) { - item.Checked = this.state.selectAll; - this.selectItem(item); - } - } - }; - - this.changePaginationLimit = function() { - PaginationService.setPaginationLimit(this.tableKey, this.state.paginatedItemLimit); - }; + /** + * Do not allow external items + */ + this.allowSelection = function(item) { + return !(item.External && item.Type === 2); + } this.$onInit = function() { - setDefaults(this); + this.setDefaults(); + this.prepareTableFromDataset(); var storedOrder = DatatableService.getDataTableOrder(this.tableKey); if (storedOrder !== null) { @@ -57,11 +24,16 @@ function (PaginationService, DatatableService) { var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); if (textFilter !== null) { this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; } }; - function setDefaults(ctrl) { - ctrl.showTextFilter = ctrl.showTextFilter ? ctrl.showTextFilter : false; - ctrl.state.reverseOrder = ctrl.reverseOrder ? ctrl.reverseOrder : false; - } }]); diff --git a/app/portainer/components/datatables/tags-datatable/tagsDatatable.html b/app/portainer/components/datatables/tags-datatable/tagsDatatable.html index e4eade921..a34d8b8a2 100644 --- a/app/portainer/components/datatables/tags-datatable/tagsDatatable.html +++ b/app/portainer/components/datatables/tags-datatable/tagsDatatable.html @@ -37,7 +37,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/teams-datatable/teamsDatatable.html b/app/portainer/components/datatables/teams-datatable/teamsDatatable.html index 0d056e512..268526737 100644 --- a/app/portainer/components/datatables/teams-datatable/teamsDatatable.html +++ b/app/portainer/components/datatables/teams-datatable/teamsDatatable.html @@ -37,7 +37,7 @@
- + {{ item.Name }} diff --git a/app/portainer/components/datatables/users-datatable/usersDatatable.html b/app/portainer/components/datatables/users-datatable/usersDatatable.html index f6848c7ba..74ce4b5b0 100644 --- a/app/portainer/components/datatables/users-datatable/usersDatatable.html +++ b/app/portainer/components/datatables/users-datatable/usersDatatable.html @@ -51,7 +51,7 @@
- + {{ item.Username }}