diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.html b/app/docker/components/datatables/configs-datatable/configsDatatable.html index 4e127d605..846fdbee4 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.html +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.html @@ -5,6 +5,44 @@
{{ $ctrl.titleText }}
+
+ + Settings + + +
+
+
+ + +
+
+ + + + + +
+
diff --git a/app/docker/components/datatables/images-datatable/imagesDatatable.js b/app/docker/components/datatables/images-datatable/imagesDatatable.js index fdc8ff994..c440cb737 100644 --- a/app/docker/components/datatables/images-datatable/imagesDatatable.js +++ b/app/docker/components/datatables/images-datatable/imagesDatatable.js @@ -13,6 +13,7 @@ angular.module('portainer.docker').component('imagesDatatable', { downloadAction: '<', forceRemoveAction: '<', exportInProgress: '<', - offlineMode: '<' + offlineMode: '<', + refreshCallback: '<' } }); diff --git a/app/docker/components/datatables/images-datatable/imagesDatatableController.js b/app/docker/components/datatables/images-datatable/imagesDatatableController.js index afd0a0930..b487efd5b 100644 --- a/app/docker/components/datatables/images-datatable/imagesDatatableController.js +++ b/app/docker/components/datatables/images-datatable/imagesDatatableController.js @@ -58,5 +58,13 @@ function ($scope, $controller, DatatableService) { if (this.filters && this.filters.state) { this.filters.state.open = false; } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + + this.onSettingsRepeaterChange(); }; }]); diff --git a/app/docker/components/datatables/networks-datatable/networksDatatable.html b/app/docker/components/datatables/networks-datatable/networksDatatable.html index 1a7deb6de..c2347d9cd 100644 --- a/app/docker/components/datatables/networks-datatable/networksDatatable.html +++ b/app/docker/components/datatables/networks-datatable/networksDatatable.html @@ -5,6 +5,44 @@
{{ $ctrl.titleText }}
+
+ + Settings + + +
+
+ + Settings + + +
+
+ + Settings + + +
{{ $ctrl.titleText }} +
+ + Settings + + +
diff --git a/app/docker/views/configs/configsController.js b/app/docker/views/configs/configsController.js index fc047501f..41cd2e313 100644 --- a/app/docker/views/configs/configsController.js +++ b/app/docker/views/configs/configsController.js @@ -11,10 +11,15 @@ class ConfigsController { this.removeAction = this.removeAction.bind(this); this.removeActionAsync = this.removeActionAsync.bind(this); + this.getConfigs = this.getConfigs.bind(this); + this.getConfigsAsync = this.getConfigsAsync.bind(this); } - async $onInit() { - this.configs = []; + getConfigs() { + return this.$async(this.getConfigsAsync); + } + + async getConfigsAsync() { try { this.configs = await this.ConfigService.configs(); } catch (err) { @@ -22,6 +27,11 @@ class ConfigsController { } } + async $onInit() { + this.configs = []; + this.getConfigs(); + } + removeAction(selectedItems) { return this.$async(this.removeActionAsync, selectedItems); } diff --git a/app/docker/views/containers/containers.html b/app/docker/views/containers/containers.html index 88c6d0b6a..91695618b 100644 --- a/app/docker/views/containers/containers.html +++ b/app/docker/views/containers/containers.html @@ -17,6 +17,7 @@ show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-add-action="true" offline-mode="offlineMode" + refresh-callback="getContainers" > diff --git a/app/docker/views/containers/containersController.js b/app/docker/views/containers/containersController.js index f054f9025..06e1022c3 100644 --- a/app/docker/views/containers/containersController.js +++ b/app/docker/views/containers/containersController.js @@ -4,7 +4,9 @@ function ($scope, ContainerService, Notifications, EndpointProvider) { $scope.offlineMode = false; - function initView() { + $scope.getContainers = getContainers; + + function getContainers() { ContainerService.containers(1) .then(function success(data) { $scope.containers = data; @@ -16,5 +18,9 @@ function ($scope, ContainerService, Notifications, EndpointProvider) { }); } + function initView() { + getContainers(); + } + initView(); }]); diff --git a/app/docker/views/images/images.html b/app/docker/views/images/images.html index db1b0f7ff..d1cfba39a 100644 --- a/app/docker/views/images/images.html +++ b/app/docker/views/images/images.html @@ -64,6 +64,7 @@ force-remove-action="confirmRemovalAction" export-in-progress="state.exportInProgress" offline-mode="offlineMode" + refresh-callback="getImages" > diff --git a/app/docker/views/images/imagesController.js b/app/docker/views/images/imagesController.js index 382747c49..8369d0e67 100644 --- a/app/docker/views/images/imagesController.js +++ b/app/docker/views/images/imagesController.js @@ -117,7 +117,8 @@ function ($scope, $state, ImageService, Notifications, ModalService, HttpRequest $scope.offlineMode = false; - function initView() { + $scope.getImages = getImages; + function getImages() { ImageService.images(true) .then(function success(data) { $scope.images = data; @@ -129,5 +130,9 @@ function ($scope, $state, ImageService, Notifications, ModalService, HttpRequest }); } + function initView() { + getImages(); + } + initView(); }]); diff --git a/app/docker/views/networks/networks.html b/app/docker/views/networks/networks.html index c547d54ba..497d95cde 100644 --- a/app/docker/views/networks/networks.html +++ b/app/docker/views/networks/networks.html @@ -17,6 +17,7 @@ show-ownership-column="applicationState.application.authentication" show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" offline-mode="offlineMode" + refresh-callback="getNetworks" > diff --git a/app/docker/views/networks/networksController.js b/app/docker/views/networks/networksController.js index 77c7647d9..f2f79b395 100644 --- a/app/docker/views/networks/networksController.js +++ b/app/docker/views/networks/networksController.js @@ -26,7 +26,9 @@ function ($scope, $state, NetworkService, Notifications, HttpRequestHelper, Endp $scope.offlineMode = false; - function initView() { + $scope.getNetworks = getNetworks; + + function getNetworks() { NetworkService.networks(true, true, true) .then(function success(data) { $scope.networks = data; @@ -38,5 +40,9 @@ function ($scope, $state, NetworkService, Notifications, HttpRequestHelper, Endp }); } + function initView() { + getNetworks(); + } + initView(); }]); diff --git a/app/docker/views/secrets/secrets.html b/app/docker/views/secrets/secrets.html index 850e44fd1..76c8205d7 100644 --- a/app/docker/views/secrets/secrets.html +++ b/app/docker/views/secrets/secrets.html @@ -15,6 +15,7 @@ order-by="Name" show-ownership-column="applicationState.application.authentication" remove-action="removeAction" + refresh-callback="getSecrets" > diff --git a/app/docker/views/secrets/secretsController.js b/app/docker/views/secrets/secretsController.js index e69111375..98f44e5e3 100644 --- a/app/docker/views/secrets/secretsController.js +++ b/app/docker/views/secrets/secretsController.js @@ -23,7 +23,9 @@ function ($scope, $state, SecretService, Notifications) { }); }; - function initView() { + $scope.getSecrets = getSecrets; + + function getSecrets() { SecretService.secrets() .then(function success(data) { $scope.secrets = data; @@ -34,5 +36,9 @@ function ($scope, $state, SecretService, Notifications) { }); } + function initView() { + getSecrets(); + } + initView(); }]); diff --git a/app/docker/views/services/services.html b/app/docker/views/services/services.html index 4e666ae73..d56bd2622 100644 --- a/app/docker/views/services/services.html +++ b/app/docker/views/services/services.html @@ -20,6 +20,7 @@ show-task-logs-button="applicationState.endpoint.apiVersion >= 1.30" show-add-action="true" show-stack-column="true" + refresh-callback="getServices" > diff --git a/app/docker/views/services/servicesController.js b/app/docker/views/services/servicesController.js index fa0cafe86..1c4f4a126 100644 --- a/app/docker/views/services/servicesController.js +++ b/app/docker/views/services/servicesController.js @@ -2,7 +2,8 @@ angular.module('portainer.docker') .controller('ServicesController', ['$q', '$scope', 'ServiceService', 'ServiceHelper', 'Notifications', 'TaskService', 'TaskHelper', 'NodeService', 'ContainerService', function ($q, $scope, ServiceService, ServiceHelper, Notifications, TaskService, TaskHelper, NodeService, ContainerService) { - function initView() { + $scope.getServices = getServices; + function getServices() { var agentProxy = $scope.applicationState.endpoint.mode.agentProxy; $q.all({ @@ -38,5 +39,9 @@ function ($q, $scope, ServiceService, ServiceHelper, Notifications, TaskService, }); } + function initView() { + getServices(); + } + initView(); }]); diff --git a/app/docker/views/swarm/swarm.html b/app/docker/views/swarm/swarm.html index aa2f9db20..271b3ef92 100644 --- a/app/docker/views/swarm/swarm.html +++ b/app/docker/views/swarm/swarm.html @@ -52,6 +52,7 @@ order-by="Hostname" show-ip-address-column="applicationState.endpoint.apiVersion >= 1.25" access-to-node-details="!applicationState.application.authentication || isAdmin" + refresh-callback="getNodes" > diff --git a/app/docker/views/swarm/swarmController.js b/app/docker/views/swarm/swarmController.js index 62cf3a347..ec7a18c37 100644 --- a/app/docker/views/swarm/swarmController.js +++ b/app/docker/views/swarm/swarmController.js @@ -58,6 +58,21 @@ function ($q, $scope, SystemService, NodeService, Notifications, StateManager, A $scope.totalMemory = memory; } + $scope.getNodes = getNodes; + function getNodes() { + var provider = $scope.applicationState.endpoint.mode.provider; + if (provider === 'DOCKER_SWARM_MODE') { + NodeService.nodes().then(function(data) { + var nodes = data; + processTotalCPUAndMemory(nodes); + $scope.nodes = nodes; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to retrieve cluster details'); + }); + } + } + function initView() { if (StateManager.getState().application.authentication) { $scope.isAdmin = Authentication.isAdmin(); @@ -66,16 +81,13 @@ function ($q, $scope, SystemService, NodeService, Notifications, StateManager, A var provider = $scope.applicationState.endpoint.mode.provider; $q.all({ version: SystemService.version(), - info: SystemService.info(), - nodes: provider !== 'DOCKER_SWARM_MODE' || NodeService.nodes() + info: SystemService.info() }) .then(function success(data) { $scope.docker = data.version; $scope.info = data.info; if (provider === 'DOCKER_SWARM_MODE') { - var nodes = data.nodes; - processTotalCPUAndMemory(nodes); - $scope.nodes = nodes; + getNodes(); } else { extractSwarmInfo(data.info); } diff --git a/app/docker/views/volumes/volumes.html b/app/docker/views/volumes/volumes.html index 958246e49..c31b7ac3b 100644 --- a/app/docker/views/volumes/volumes.html +++ b/app/docker/views/volumes/volumes.html @@ -18,6 +18,7 @@ show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-browse-action="applicationState.endpoint.mode.agentProxy" offline-mode="offlineMode" + refresh-callback="getVolumes" > diff --git a/app/docker/views/volumes/volumesController.js b/app/docker/views/volumes/volumesController.js index 3ab620266..0cad1b914 100644 --- a/app/docker/views/volumes/volumesController.js +++ b/app/docker/views/volumes/volumesController.js @@ -26,7 +26,8 @@ function ($q, $scope, $state, VolumeService, ServiceService, VolumeHelper, Notif $scope.offlineMode = false; - function initView() { + $scope.getVolumes = getVolumes; + function getVolumes() { var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointRole = $scope.applicationState.endpoint.mode.role; @@ -53,5 +54,9 @@ function ($q, $scope, $state, VolumeService, ServiceService, VolumeHelper, Notif }); } + function initView() { + getVolumes(); + } + initView(); }]); diff --git a/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js b/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js index b70bae033..132b3a810 100644 --- a/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js +++ b/app/integrations/storidge/components/drives-datatable/storidgeDrivesDatatableController.js @@ -30,6 +30,13 @@ angular.module('portainer.docker') if (this.filters && this.filters.state) { this.filters.state.open = false; } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + this.onSettingsRepeaterChange(); }; } ]); \ No newline at end of file diff --git a/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js b/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js index c3b2e635d..d21b0d6d2 100644 --- a/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js +++ b/app/integrations/storidge/components/nodes-datatable/storidgeNodesDatatableController.js @@ -44,5 +44,12 @@ function($scope, $controller, clipboard, Notifications, StoridgeNodeService, Dat if (this.filters && this.filters.state) { this.filters.state.open = false; } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + this.onSettingsRepeaterChange(); }; }]); diff --git a/app/portainer/components/access-datatable/accessDatatableController.js b/app/portainer/components/access-datatable/accessDatatableController.js index de143c72d..317b6c5a4 100644 --- a/app/portainer/components/access-datatable/accessDatatableController.js +++ b/app/portainer/components/access-datatable/accessDatatableController.js @@ -34,6 +34,13 @@ angular.module('portainer.app') if (this.filters && this.filters.state) { this.filters.state.open = false; } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + this.onSettingsRepeaterChange(); }; } ]); \ No newline at end of file diff --git a/app/portainer/components/datatables/genericDatatableController.js b/app/portainer/components/datatables/genericDatatableController.js index 21af10060..7cb5d0143 100644 --- a/app/portainer/components/datatables/genericDatatableController.js +++ b/app/portainer/components/datatables/genericDatatableController.js @@ -6,8 +6,8 @@ function isBetween(value, a, b) { } angular.module('portainer.app') -.controller('GenericDatatableController', ['PaginationService', 'DatatableService', 'PAGINATION_MAX_ITEMS', -function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { +.controller('GenericDatatableController', ['$interval', 'PaginationService', 'DatatableService', 'PAGINATION_MAX_ITEMS', +function ($interval, PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { this.state = { selectAll: false, @@ -20,6 +20,13 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { selectedItems: [] }; + this.settings = { + open: false, + repeater: { + autoRefresh: false, + refreshRate: '30' + } + } this.onTextFilterChange = function() { DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); @@ -87,7 +94,7 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { /** * Override this method to execute code after selection changed on datatable */ - this.onSelectionChanged = function () { + this.onSelectionChanged = function() { return; } @@ -131,5 +138,47 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { if (this.filters && this.filters.state) { this.filters.state.open = false; } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + this.onSettingsRepeaterChange(); }; + + /** + * REPEATER SECTION + */ + this.repeater = undefined; + + this.$onDestroy = function() { + this.stopRepeater(); + }; + + this.stopRepeater = function() { + if (angular.isDefined(this.repeater)) { + $interval.cancel(this.repeater); + this.repeater = undefined; + } + } + + this.startRepeater = function() { + this.repeater = $interval(() => { + this.refreshCallback(); + }, this.settings.repeater.refreshRate * 1000); + } + + this.onSettingsRepeaterChange = function() { + this.stopRepeater(); + if (angular.isDefined(this.refreshCallback) && this.settings.repeater.autoRefresh) { + this.startRepeater(); + $('#refreshRateChange').show(); + $('#refreshRateChange').fadeOut(1500); + } + DatatableService.setDataTableSettings(this.tableKey, this.settings); + } + /** + * !REPEATER SECTION + */ }]); diff --git a/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js b/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js index 498e72ff3..edf2665d3 100644 --- a/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js +++ b/app/portainer/components/datatables/schedules-datatable/schedulesDatatableController.js @@ -34,6 +34,13 @@ angular.module('portainer.app') if (this.filters && this.filters.state) { this.filters.state.open = false; } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + this.onSettingsRepeaterChange(); }; } ]); diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html index 6bd6852f3..480888746 100644 --- a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html +++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html @@ -5,6 +5,44 @@
{{ $ctrl.titleText }}
+
+ + Settings + + +
diff --git a/app/portainer/views/stacks/stacksController.js b/app/portainer/views/stacks/stacksController.js index 3c331a8f6..868720b5d 100644 --- a/app/portainer/views/stacks/stacksController.js +++ b/app/portainer/views/stacks/stacksController.js @@ -35,7 +35,8 @@ function ($scope, $state, Notifications, StackService, ModalService, EndpointPro $scope.offlineMode = false; - function initView() { + $scope.getStacks = getStacks; + function getStacks() { var endpointMode = $scope.applicationState.endpoint.mode; var endpointId = EndpointProvider.endpointID(); @@ -55,5 +56,9 @@ function ($scope, $state, Notifications, StackService, ModalService, EndpointPro }); } + function initView() { + getStacks(); + } + initView(); }]); diff --git a/assets/css/app.css b/assets/css/app.css index 48a153f38..f397a0a2f 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -560,6 +560,17 @@ ul.sidebar .sidebar-list .sidebar-sublist a.active { display: none; } +.small-select { + display: inline-block; + padding: 0px 6px; + margin-left: 10px; + color: #555555; + background-color: #fff; + background-image: none; + border-radius: 4px; + font-size: 14px; +} + .bootbox-form .checkbox i { margin-left: 21px; }