1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 07:49:41 +02:00

feat(datatables): auto refresh on datatables (#2974)

* feat(datatables): auto refresh on datatables

* feat(datatables): auto refresh implementation on docker related resources
This commit is contained in:
xAt0mZ 2019-07-22 12:54:59 +02:00 committed by GitHub
parent cc487ae68a
commit 03c82cac69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 577 additions and 29 deletions

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="actionBar" authorization="DockerConfigDelete, DockerConfigCreate"> <div class="actionBar" authorization="DockerConfigDelete, DockerConfigCreate">
<button type="button" class="btn btn-sm btn-danger" authorization="DockerConfigDelete" <button type="button" class="btn btn-sm btn-danger" authorization="DockerConfigDelete"

View file

@ -9,6 +9,7 @@ angular.module('portainer.docker').component('configsDatatable', {
orderBy: '@', orderBy: '@',
reverseOrder: '<', reverseOrder: '<',
showOwnershipColumn: '<', showOwnershipColumn: '<',
removeAction: '<' removeAction: '<',
refreshCallback: '<'
} }
}); });

View file

@ -69,6 +69,27 @@
<input id="setting_container_trunc" type="checkbox" ng-model="$ctrl.settings.truncateContainerName" ng-change="$ctrl.onSettingsContainerNameTruncateChange()"/> <input id="setting_container_trunc" type="checkbox" ng-model="$ctrl.settings.truncateContainerName" ng-change="$ctrl.onSettingsContainerNameTruncateChange()"/>
<label for="setting_container_trunc">Truncate container name</label> <label for="setting_container_trunc">Truncate container name</label>
</div> </div>
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div> </div>
<div authorization="DockerContainerStats, DockerContainerLogs, DockerExecStart, DockerContainerInspect, DockerTaskInspect, DockerTaskLogs, DockerContainerAttach"> <div authorization="DockerContainerStats, DockerContainerLogs, DockerExecStart, DockerContainerInspect, DockerTaskInspect, DockerTaskLogs, DockerContainerAttach">
<div class="menuHeader"> <div class="menuHeader">

View file

@ -11,6 +11,7 @@ angular.module('portainer.docker').component('containersDatatable', {
showOwnershipColumn: '<', showOwnershipColumn: '<',
showHostColumn: '<', showHostColumn: '<',
showAddAction: '<', showAddAction: '<',
offlineMode: '<' offlineMode: '<',
refreshCallback: '<'
} }
}); });

View file

@ -15,8 +15,7 @@ function ($scope, $controller, DatatableService, EndpointProvider) {
publicURL: EndpointProvider.endpointPublicURL() publicURL: EndpointProvider.endpointPublicURL()
}); });
this.settings = { this.settings = Object.assign(this.settings, {
open: false,
truncateContainerName: true, truncateContainerName: true,
containerNameTruncateSize: 32, containerNameTruncateSize: 32,
showQuickActionStats: true, showQuickActionStats: true,
@ -24,7 +23,7 @@ function ($scope, $controller, DatatableService, EndpointProvider) {
showQuickActionExec: true, showQuickActionExec: true,
showQuickActionInspect: true, showQuickActionInspect: true,
showQuickActionAttach: false showQuickActionAttach: false
}; });
this.filters = { this.filters = {
state: { state: {
@ -197,6 +196,7 @@ function ($scope, $controller, DatatableService, EndpointProvider) {
this.settings = storedSettings; this.settings = storedSettings;
this.settings.open = false; this.settings.open = false;
} }
this.onSettingsRepeaterChange();
var storedColumnVisibility = DatatableService.getColumnVisibilitySettings(this.tableKey); var storedColumnVisibility = DatatableService.getColumnVisibilitySettings(this.tableKey);
if (storedColumnVisibility !== null) { if (storedColumnVisibility !== null) {

View file

@ -128,6 +128,13 @@ angular.module('portainer.docker')
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
} }
]); ]);

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="DockerImageDelete, DockerImageBuild, DockerImageLoad, DockerImageGet"> <div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="DockerImageDelete, DockerImageBuild, DockerImageLoad, DockerImageGet">
<div class="btn-group" authorization="DockerImageDelete"> <div class="btn-group" authorization="DockerImageDelete">

View file

@ -13,6 +13,7 @@ angular.module('portainer.docker').component('imagesDatatable', {
downloadAction: '<', downloadAction: '<',
forceRemoveAction: '<', forceRemoveAction: '<',
exportInProgress: '<', exportInProgress: '<',
offlineMode: '<' offlineMode: '<',
refreshCallback: '<'
} }
}); });

View file

@ -58,5 +58,13 @@ function ($scope, $controller, DatatableService) {
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
}]); }]);

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="DockerNetworkDelete, DockerNetworkCreate"> <div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="DockerNetworkDelete, DockerNetworkCreate">
<button type="button" class="btn btn-sm btn-danger" authorization="DockerNetworkDelete" <button type="button" class="btn btn-sm btn-danger" authorization="DockerNetworkDelete"

View file

@ -11,6 +11,7 @@ angular.module('portainer.docker').component('networksDatatable', {
showOwnershipColumn: '<', showOwnershipColumn: '<',
showHostColumn: '<', showHostColumn: '<',
removeAction: '<', removeAction: '<',
offlineMode: '<' offlineMode: '<',
refreshCallback: '<'
} }
}); });

View file

@ -38,6 +38,13 @@ angular.module('portainer.docker')
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
} }
]); ]);

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="searchBar"> <div class="searchBar">
<i class="fa fa-search searchIcon" aria-hidden="true"></i> <i class="fa fa-search searchIcon" aria-hidden="true"></i>

View file

@ -9,6 +9,7 @@ angular.module('portainer.docker').component('nodesDatatable', {
orderBy: '@', orderBy: '@',
reverseOrder: '<', reverseOrder: '<',
showIpAddressColumn: '<', showIpAddressColumn: '<',
accessToNodeDetails: '<' accessToNodeDetails: '<',
refreshCallback: '<'
} }
}); });

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="actionBar" authorization="DockerSecretDelete, DockerSecretCreate"> <div class="actionBar" authorization="DockerSecretDelete, DockerSecretCreate">
<button type="button" class="btn btn-sm btn-danger" authorization="DockerSecretDelete" <button type="button" class="btn btn-sm btn-danger" authorization="DockerSecretDelete"

View file

@ -9,6 +9,7 @@ angular.module('portainer.docker').component('secretsDatatable', {
orderBy: '@', orderBy: '@',
reverseOrder: '<', reverseOrder: '<',
showOwnershipColumn: '<', showOwnershipColumn: '<',
removeAction: '<' removeAction: '<',
refreshCallback: '<'
} }
}); });

View file

@ -79,6 +79,13 @@ angular.module('portainer.docker')
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
} }
]); ]);

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<services-datatable-actions <services-datatable-actions
selected-items="$ctrl.state.selectedItems" selected-items="$ctrl.state.selectedItems"

View file

@ -14,6 +14,7 @@ angular.module('portainer.docker').component('servicesDatatable', {
showUpdateAction: '<', showUpdateAction: '<',
showAddAction: '<', showAddAction: '<',
showStackColumn: '<', showStackColumn: '<',
showTaskLogsButton: '<' showTaskLogsButton: '<',
refreshCallback: '<'
} }
}); });

View file

@ -92,5 +92,12 @@ function ($scope, $controller, DatatableService, EndpointProvider) {
if (storedExpandedItems !== null) { if (storedExpandedItems !== null) {
this.expandItems(storedExpandedItems); this.expandItems(storedExpandedItems);
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
}]); }]);

View file

@ -35,5 +35,12 @@ function ($scope, $controller, DatatableService) {
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
}]); }]);

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="DockerVolumeDelete, DockerVolumeCreate"> <div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="DockerVolumeDelete, DockerVolumeCreate">
<button type="button" class="btn btn-sm btn-danger" authorization="DockerVolumeDelete" <button type="button" class="btn btn-sm btn-danger" authorization="DockerVolumeDelete"

View file

@ -12,6 +12,7 @@ angular.module('portainer.docker').component('volumesDatatable', {
showHostColumn: '<', showHostColumn: '<',
removeAction: '<', removeAction: '<',
showBrowseAction: '<', showBrowseAction: '<',
offlineMode: '<' offlineMode: '<',
refreshCallback: '<'
} }
}); });

View file

@ -58,5 +58,12 @@ function ($scope, $controller, DatatableService) {
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
}]); }]);

View file

@ -15,6 +15,7 @@
order-by="Name" order-by="Name"
show-ownership-column="applicationState.application.authentication" show-ownership-column="applicationState.application.authentication"
remove-action="ctrl.removeAction" remove-action="ctrl.removeAction"
refresh-callback="ctrl.getConfigs"
></configs-datatable> ></configs-datatable>
</div> </div>
</div> </div>

View file

@ -11,10 +11,15 @@ class ConfigsController {
this.removeAction = this.removeAction.bind(this); this.removeAction = this.removeAction.bind(this);
this.removeActionAsync = this.removeActionAsync.bind(this); this.removeActionAsync = this.removeActionAsync.bind(this);
this.getConfigs = this.getConfigs.bind(this);
this.getConfigsAsync = this.getConfigsAsync.bind(this);
} }
async $onInit() { getConfigs() {
this.configs = []; return this.$async(this.getConfigsAsync);
}
async getConfigsAsync() {
try { try {
this.configs = await this.ConfigService.configs(); this.configs = await this.ConfigService.configs();
} catch (err) { } catch (err) {
@ -22,6 +27,11 @@ class ConfigsController {
} }
} }
async $onInit() {
this.configs = [];
this.getConfigs();
}
removeAction(selectedItems) { removeAction(selectedItems) {
return this.$async(this.removeActionAsync, selectedItems); return this.$async(this.removeActionAsync, selectedItems);
} }

View file

@ -17,6 +17,7 @@
show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'"
show-add-action="true" show-add-action="true"
offline-mode="offlineMode" offline-mode="offlineMode"
refresh-callback="getContainers"
></containers-datatable> ></containers-datatable>
</div> </div>
</div> </div>

View file

@ -4,7 +4,9 @@ function ($scope, ContainerService, Notifications, EndpointProvider) {
$scope.offlineMode = false; $scope.offlineMode = false;
function initView() { $scope.getContainers = getContainers;
function getContainers() {
ContainerService.containers(1) ContainerService.containers(1)
.then(function success(data) { .then(function success(data) {
$scope.containers = data; $scope.containers = data;
@ -16,5 +18,9 @@ function ($scope, ContainerService, Notifications, EndpointProvider) {
}); });
} }
function initView() {
getContainers();
}
initView(); initView();
}]); }]);

View file

@ -64,6 +64,7 @@
force-remove-action="confirmRemovalAction" force-remove-action="confirmRemovalAction"
export-in-progress="state.exportInProgress" export-in-progress="state.exportInProgress"
offline-mode="offlineMode" offline-mode="offlineMode"
refresh-callback="getImages"
></images-datatable> ></images-datatable>
</div> </div>
</div> </div>

View file

@ -117,7 +117,8 @@ function ($scope, $state, ImageService, Notifications, ModalService, HttpRequest
$scope.offlineMode = false; $scope.offlineMode = false;
function initView() { $scope.getImages = getImages;
function getImages() {
ImageService.images(true) ImageService.images(true)
.then(function success(data) { .then(function success(data) {
$scope.images = data; $scope.images = data;
@ -129,5 +130,9 @@ function ($scope, $state, ImageService, Notifications, ModalService, HttpRequest
}); });
} }
function initView() {
getImages();
}
initView(); initView();
}]); }]);

View file

@ -17,6 +17,7 @@
show-ownership-column="applicationState.application.authentication" show-ownership-column="applicationState.application.authentication"
show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'"
offline-mode="offlineMode" offline-mode="offlineMode"
refresh-callback="getNetworks"
></networks-datatable> ></networks-datatable>
</div> </div>
</div> </div>

View file

@ -26,7 +26,9 @@ function ($scope, $state, NetworkService, Notifications, HttpRequestHelper, Endp
$scope.offlineMode = false; $scope.offlineMode = false;
function initView() { $scope.getNetworks = getNetworks;
function getNetworks() {
NetworkService.networks(true, true, true) NetworkService.networks(true, true, true)
.then(function success(data) { .then(function success(data) {
$scope.networks = data; $scope.networks = data;
@ -38,5 +40,9 @@ function ($scope, $state, NetworkService, Notifications, HttpRequestHelper, Endp
}); });
} }
function initView() {
getNetworks();
}
initView(); initView();
}]); }]);

View file

@ -15,6 +15,7 @@
order-by="Name" order-by="Name"
show-ownership-column="applicationState.application.authentication" show-ownership-column="applicationState.application.authentication"
remove-action="removeAction" remove-action="removeAction"
refresh-callback="getSecrets"
></secrets-datatable> ></secrets-datatable>
</div> </div>
</div> </div>

View file

@ -23,7 +23,9 @@ function ($scope, $state, SecretService, Notifications) {
}); });
}; };
function initView() { $scope.getSecrets = getSecrets;
function getSecrets() {
SecretService.secrets() SecretService.secrets()
.then(function success(data) { .then(function success(data) {
$scope.secrets = data; $scope.secrets = data;
@ -34,5 +36,9 @@ function ($scope, $state, SecretService, Notifications) {
}); });
} }
function initView() {
getSecrets();
}
initView(); initView();
}]); }]);

View file

@ -20,6 +20,7 @@
show-task-logs-button="applicationState.endpoint.apiVersion >= 1.30" show-task-logs-button="applicationState.endpoint.apiVersion >= 1.30"
show-add-action="true" show-add-action="true"
show-stack-column="true" show-stack-column="true"
refresh-callback="getServices"
></services-datatable> ></services-datatable>
</div> </div>
</div> </div>

View file

@ -2,7 +2,8 @@ angular.module('portainer.docker')
.controller('ServicesController', ['$q', '$scope', 'ServiceService', 'ServiceHelper', 'Notifications', 'TaskService', 'TaskHelper', 'NodeService', 'ContainerService', .controller('ServicesController', ['$q', '$scope', 'ServiceService', 'ServiceHelper', 'Notifications', 'TaskService', 'TaskHelper', 'NodeService', 'ContainerService',
function ($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; var agentProxy = $scope.applicationState.endpoint.mode.agentProxy;
$q.all({ $q.all({
@ -38,5 +39,9 @@ function ($q, $scope, ServiceService, ServiceHelper, Notifications, TaskService,
}); });
} }
function initView() {
getServices();
}
initView(); initView();
}]); }]);

View file

@ -52,6 +52,7 @@
order-by="Hostname" order-by="Hostname"
show-ip-address-column="applicationState.endpoint.apiVersion >= 1.25" show-ip-address-column="applicationState.endpoint.apiVersion >= 1.25"
access-to-node-details="!applicationState.application.authentication || isAdmin" access-to-node-details="!applicationState.application.authentication || isAdmin"
refresh-callback="getNodes"
></nodes-datatable> ></nodes-datatable>
</div> </div>
</div> </div>

View file

@ -58,6 +58,21 @@ function ($q, $scope, SystemService, NodeService, Notifications, StateManager, A
$scope.totalMemory = memory; $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() { function initView() {
if (StateManager.getState().application.authentication) { if (StateManager.getState().application.authentication) {
$scope.isAdmin = Authentication.isAdmin(); $scope.isAdmin = Authentication.isAdmin();
@ -66,16 +81,13 @@ function ($q, $scope, SystemService, NodeService, Notifications, StateManager, A
var provider = $scope.applicationState.endpoint.mode.provider; var provider = $scope.applicationState.endpoint.mode.provider;
$q.all({ $q.all({
version: SystemService.version(), version: SystemService.version(),
info: SystemService.info(), info: SystemService.info()
nodes: provider !== 'DOCKER_SWARM_MODE' || NodeService.nodes()
}) })
.then(function success(data) { .then(function success(data) {
$scope.docker = data.version; $scope.docker = data.version;
$scope.info = data.info; $scope.info = data.info;
if (provider === 'DOCKER_SWARM_MODE') { if (provider === 'DOCKER_SWARM_MODE') {
var nodes = data.nodes; getNodes();
processTotalCPUAndMemory(nodes);
$scope.nodes = nodes;
} else { } else {
extractSwarmInfo(data.info); extractSwarmInfo(data.info);
} }

View file

@ -18,6 +18,7 @@
show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'"
show-browse-action="applicationState.endpoint.mode.agentProxy" show-browse-action="applicationState.endpoint.mode.agentProxy"
offline-mode="offlineMode" offline-mode="offlineMode"
refresh-callback="getVolumes"
></volumes-datatable> ></volumes-datatable>
</div> </div>
</div> </div>

View file

@ -26,7 +26,8 @@ function ($q, $scope, $state, VolumeService, ServiceService, VolumeHelper, Notif
$scope.offlineMode = false; $scope.offlineMode = false;
function initView() { $scope.getVolumes = getVolumes;
function getVolumes() {
var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointProvider = $scope.applicationState.endpoint.mode.provider;
var endpointRole = $scope.applicationState.endpoint.mode.role; var endpointRole = $scope.applicationState.endpoint.mode.role;
@ -53,5 +54,9 @@ function ($q, $scope, $state, VolumeService, ServiceService, VolumeHelper, Notif
}); });
} }
function initView() {
getVolumes();
}
initView(); initView();
}]); }]);

View file

@ -30,6 +30,13 @@ angular.module('portainer.docker')
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
} }
]); ]);

View file

@ -44,5 +44,12 @@ function($scope, $controller, clipboard, Notifications, StoridgeNodeService, Dat
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
}]); }]);

View file

@ -34,6 +34,13 @@ angular.module('portainer.app')
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
} }
]); ]);

View file

@ -6,8 +6,8 @@ function isBetween(value, a, b) {
} }
angular.module('portainer.app') angular.module('portainer.app')
.controller('GenericDatatableController', ['PaginationService', 'DatatableService', 'PAGINATION_MAX_ITEMS', .controller('GenericDatatableController', ['$interval', 'PaginationService', 'DatatableService', 'PAGINATION_MAX_ITEMS',
function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) { function ($interval, PaginationService, DatatableService, PAGINATION_MAX_ITEMS) {
this.state = { this.state = {
selectAll: false, selectAll: false,
@ -20,6 +20,13 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) {
selectedItems: [] selectedItems: []
}; };
this.settings = {
open: false,
repeater: {
autoRefresh: false,
refreshRate: '30'
}
}
this.onTextFilterChange = function() { this.onTextFilterChange = function() {
DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); 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 * Override this method to execute code after selection changed on datatable
*/ */
this.onSelectionChanged = function () { this.onSelectionChanged = function() {
return; return;
} }
@ -131,5 +138,47 @@ function (PaginationService, DatatableService, PAGINATION_MAX_ITEMS) {
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; 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
*/
}]); }]);

View file

@ -34,6 +34,13 @@ angular.module('portainer.app')
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
} }
]); ]);

View file

@ -5,6 +5,44 @@
<div class="toolBarTitle"> <div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }} <i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div> </div>
<div class="settings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><i class="fa fa-cog" aria-hidden="true"></i> Settings</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader">
Table settings
</div>
<div class="menuContent">
<div>
<div class="md-checkbox">
<input id="setting_auto_refresh" type="checkbox" ng-model="$ctrl.settings.repeater.autoRefresh" ng-change="$ctrl.onSettingsRepeaterChange()"/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate">
Refresh rate
</label>
<select id="settings_refresh_rate" ng-model="$ctrl.settings.repeater.refreshRate" ng-change="$ctrl.onSettingsRepeaterChange()" class="small-select">
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none;"></i>
</span>
</div>
</div>
</div>
<div>
<a type="button" class="btn btn-default btn-sm" ng-click="$ctrl.settings.open = false;">Close</a>
</div>
</div>
</div>
</span>
</div>
</div> </div>
<div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="PortainerStackCreate, PortainerStackDelete"> <div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="PortainerStackCreate, PortainerStackDelete">
<button type="button" class="btn btn-sm btn-danger" authorization="PortainerStackDelete" <button type="button" class="btn btn-sm btn-danger" authorization="PortainerStackDelete"

View file

@ -10,6 +10,7 @@ angular.module('portainer.app').component('stacksDatatable', {
reverseOrder: '<', reverseOrder: '<',
showOwnershipColumn: '<', showOwnershipColumn: '<',
removeAction: '<', removeAction: '<',
offlineMode: '<' offlineMode: '<',
refreshCallback: '<'
} }
}); });

View file

@ -34,6 +34,13 @@ function ($scope, $controller, DatatableService) {
if (this.filters && this.filters.state) { if (this.filters && this.filters.state) {
this.filters.state.open = false; this.filters.state.open = false;
} }
var storedSettings = DatatableService.getDataTableSettings(this.tableKey);
if (storedSettings !== null) {
this.settings = storedSettings;
this.settings.open = false;
}
this.onSettingsRepeaterChange();
}; };
}]); }]);

View file

@ -16,6 +16,7 @@
remove-action="removeAction" remove-action="removeAction"
show-ownership-column="applicationState.application.authentication" show-ownership-column="applicationState.application.authentication"
offline-mode="offlineMode" offline-mode="offlineMode"
refresh-callback="getStacks"
></stacks-datatable> ></stacks-datatable>
</div> </div>
</div> </div>

View file

@ -35,7 +35,8 @@ function ($scope, $state, Notifications, StackService, ModalService, EndpointPro
$scope.offlineMode = false; $scope.offlineMode = false;
function initView() { $scope.getStacks = getStacks;
function getStacks() {
var endpointMode = $scope.applicationState.endpoint.mode; var endpointMode = $scope.applicationState.endpoint.mode;
var endpointId = EndpointProvider.endpointID(); var endpointId = EndpointProvider.endpointID();
@ -55,5 +56,9 @@ function ($scope, $state, Notifications, StackService, ModalService, EndpointPro
}); });
} }
function initView() {
getStacks();
}
initView(); initView();
}]); }]);

View file

@ -560,6 +560,17 @@ ul.sidebar .sidebar-list .sidebar-sublist a.active {
display: none; 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 { .bootbox-form .checkbox i {
margin-left: 21px; margin-left: 21px;
} }