mirror of https://github.com/portainer/portainer
				
				
				
			fix(ui): namespace caching issue EE-5273 (#8710)
* fix namespace caching issue * fix(apps): add loading state [EE-5273] * rm endpoint provider * fix(namespace): remove caching [EE-5273] * variable typo --------- Co-authored-by: testa113 <testa113>pull/8736/head
							parent
							
								
									e063cba81b
								
							
						
					
					
						commit
						ab1a8c1d6a
					
				|  | @ -244,6 +244,7 @@ | |||
|       </thead> | ||||
|       <tbody> | ||||
|         <tr | ||||
|           ng-show="!$ctrl.isAppsLoading" | ||||
|           ng-click="$ctrl.expandItem(item, !$ctrl.isItemExpanded(item))" | ||||
|           dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.applyFilters | filter:$ctrl.state.textFilter | filter:$ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))" | ||||
|           ng-class="{ active: item.Checked, interactive: $ctrl.isExpandable(item), 'secondary-body': !$ctrl.isPrimary }" | ||||
|  | @ -335,16 +336,16 @@ | |||
|             </span> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr ng-if="!$ctrl.dataset"> | ||||
|         <tr ng-if="$ctrl.isAppsLoading"> | ||||
|           <td colspan="8" class="text-muted text-center">Loading...</td> | ||||
|         </tr> | ||||
|         <tr ng-if="$ctrl.state.filteredDataSet.length === 0"> | ||||
|         <tr ng-if="$ctrl.state.filteredDataSet.length === 0 && !$ctrl.isAppsLoading"> | ||||
|           <td colspan="8" class="text-muted text-center">No application available.</td> | ||||
|         </tr> | ||||
|       </tbody> | ||||
|     </table> | ||||
|   </div> | ||||
|   <div ng-if="$ctrl.isPrimary" class="footer pl-5" ng-if="$ctrl.dataset"> | ||||
|   <div class="footer pl-5" ng-if="$ctrl.isPrimary && $ctrl.dataset"> | ||||
|     <div class="infoBar !ml-0" ng-if="$ctrl.state.selectedItemCount !== 0"> {{ $ctrl.state.selectedItemCount }} item(s) selected </div> | ||||
|     <div class="paginationControls"> | ||||
|       <form class="form-inline"> | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ angular.module('portainer.kubernetes').component('kubernetesApplicationsDatatabl | |||
|     namespaces: '<', | ||||
|     namespace: '<', | ||||
|     onChangeNamespaceDropdown: '<', | ||||
|     isAppsLoading: '<', | ||||
|     isSystemResources: '<', | ||||
|     setSystemResources: '<', | ||||
|   }, | ||||
|  |  | |||
|  | @ -168,6 +168,7 @@ | |||
|       </thead> | ||||
|       <tbody> | ||||
|         <tr | ||||
|           ng-show="!$ctrl.isAppsLoading" | ||||
|           dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))" | ||||
|           ng-class="{ active: item.Checked, 'datatable-highlighted': item.Highlighted }" | ||||
|           ng-click="$ctrl.expandItem(item, !item.Expanded)" | ||||
|  | @ -220,10 +221,10 @@ | |||
|             > | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr ng-if="!$ctrl.dataset"> | ||||
|         <tr ng-if="$ctrl.isAppsLoading"> | ||||
|           <td colspan="5" class="text-muted text-center">Loading...</td> | ||||
|         </tr> | ||||
|         <tr ng-if="$ctrl.state.filteredDataSet.length === 0"> | ||||
|         <tr ng-if="$ctrl.state.filteredDataSet.length === 0 && !$ctrl.isAppsLoading"> | ||||
|           <td colspan="5" class="text-muted text-center">No stack available.</td> | ||||
|         </tr> | ||||
|       </tbody> | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ angular.module('portainer.kubernetes').component('kubernetesApplicationsStacksDa | |||
|     namespaces: '<', | ||||
|     namespace: '<', | ||||
|     onChangeNamespaceDropdown: '<', | ||||
|     isAppsLoading: '<', | ||||
|     isSystemResources: '<', | ||||
|     setSystemResources: '<', | ||||
|   }, | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ class KubernetesNamespaceService { | |||
|     this.deleteAsync = this.deleteAsync.bind(this); | ||||
|     this.getJSONAsync = this.getJSONAsync.bind(this); | ||||
|     this.updateFinalizeAsync = this.updateFinalizeAsync.bind(this); | ||||
|     this.refreshCacheAsync = this.refreshCacheAsync.bind(this); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|  | @ -81,20 +80,13 @@ class KubernetesNamespaceService { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   async get(name, refreshCache = false) { | ||||
|   async get(name) { | ||||
|     if (name) { | ||||
|       return this.$async(this.getAsync, name); | ||||
|     } | ||||
|     const cachedAllowedNamespaces = this.LocalStorage.getAllowedNamespaces(); | ||||
|     if (!cachedAllowedNamespaces || refreshCache) { | ||||
|       const allowedNamespaces = await this.getAllAsync(); | ||||
|       this.LocalStorage.storeAllowedNamespaces(allowedNamespaces); | ||||
|       updateNamespaces(allowedNamespaces); | ||||
|       return allowedNamespaces; | ||||
|     } else { | ||||
|       updateNamespaces(cachedAllowedNamespaces); | ||||
|       return cachedAllowedNamespaces; | ||||
|     } | ||||
|     const allowedNamespaces = await this.getAllAsync(); | ||||
|     updateNamespaces(allowedNamespaces); | ||||
|     return allowedNamespaces; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|  | @ -105,7 +97,6 @@ class KubernetesNamespaceService { | |||
|       const payload = KubernetesNamespaceConverter.createPayload(namespace); | ||||
|       const params = {}; | ||||
|       const data = await this.KubernetesNamespaces().create(params, payload).$promise; | ||||
|       await this.refreshCacheAsync(); | ||||
|       return data; | ||||
|     } catch (err) { | ||||
|       throw new PortainerError('Unable to create namespace', err); | ||||
|  | @ -116,14 +107,6 @@ class KubernetesNamespaceService { | |||
|     return this.$async(this.createAsync, namespace); | ||||
|   } | ||||
| 
 | ||||
|   async refreshCacheAsync() { | ||||
|     this.LocalStorage.deleteAllowedNamespaces(); | ||||
|     const allowedNamespaces = await this.getAllAsync(); | ||||
|     this.LocalStorage.storeAllowedNamespaces(allowedNamespaces); | ||||
|     updateNamespaces(allowedNamespaces); | ||||
|     return allowedNamespaces; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * DELETE | ||||
|    */ | ||||
|  |  | |||
|  | @ -36,8 +36,8 @@ export function KubernetesResourcePoolService( | |||
|   } | ||||
| 
 | ||||
|   // getting the quota for all namespaces is costly by default, so disable getting it by default
 | ||||
|   async function getAll({ getQuota = false, refreshCache = false }) { | ||||
|     const namespaces = await KubernetesNamespaceService.get('', refreshCache); | ||||
|   async function getAll({ getQuota = false }) { | ||||
|     const namespaces = await KubernetesNamespaceService.get(); | ||||
|     const pools = await Promise.all( | ||||
|       _.map(namespaces, async (namespace) => { | ||||
|         const name = namespace.Name; | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ | |||
|                 namespaces="ctrl.state.namespaces" | ||||
|                 namespace="ctrl.state.namespaceName" | ||||
|                 on-change-namespace-dropdown="(ctrl.onChangeNamespaceDropdown)" | ||||
|                 is-apps-loading="ctrl.state.isAppsLoading" | ||||
|                 is-system-resources="ctrl.state.isSystemResources" | ||||
|                 set-system-resources="(ctrl.setSystemResources)" | ||||
|               > | ||||
|  | @ -38,6 +39,7 @@ | |||
|                 namespaces="ctrl.state.namespaces" | ||||
|                 namespace="ctrl.state.namespaceName" | ||||
|                 on-change-namespace-dropdown="(ctrl.onChangeNamespaceDropdown)" | ||||
|                 is-apps-loading="ctrl.state.isAppsLoading" | ||||
|                 is-system-resources="ctrl.state.isSystemResources" | ||||
|                 set-system-resources="(ctrl.setSystemResources)" | ||||
|               > | ||||
|  |  | |||
|  | @ -143,15 +143,14 @@ class KubernetesApplicationsController { | |||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   onChangeNamespaceDropdown(namespaceName) { | ||||
|     this.state.namespaceName = namespaceName; | ||||
|     // save the selected namespaceName in local storage with the key 'kubernetes_namespace_filter_${environmentId}_${userID}'
 | ||||
|     this.LocalStorage.storeNamespaceFilter(this.endpoint.Id, this.user.ID, namespaceName); | ||||
|     this.getApplicationsAsync(); | ||||
|   onChangeNamespaceDropdown(namespace) { | ||||
|     this.state.namespaceName = namespace; | ||||
|     return this.$async(this.getApplicationsAsync); | ||||
|   } | ||||
| 
 | ||||
|   async getApplicationsAsync() { | ||||
|     try { | ||||
|       this.state.isAppsLoading = true; | ||||
|       const [applications, configurations] = await Promise.all([ | ||||
|         this.KubernetesApplicationService.get(this.state.namespaceName), | ||||
|         this.KubernetesConfigurationService.get(this.state.namespaceName), | ||||
|  | @ -166,6 +165,8 @@ class KubernetesApplicationsController { | |||
|       this.$scope.$apply(); | ||||
|     } catch (err) { | ||||
|       this.Notifications.error('Failure', err, 'Unable to retrieve applications'); | ||||
|     } finally { | ||||
|       this.state.isAppsLoading = false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -290,7 +290,6 @@ | |||
|             <!-- table --> | ||||
|             <kubernetes-application-services-table | ||||
|               services="ctrl.application.Services" | ||||
|               namespaces="ctrl.allNamespaces" | ||||
|               application="ctrl.application" | ||||
|               public-url="ctrl.state.publicUrl" | ||||
|             ></kubernetes-application-services-table> | ||||
|  |  | |||
|  | @ -221,7 +221,6 @@ class KubernetesResourcePoolController { | |||
|           return; | ||||
|         } | ||||
|         await this.KubernetesResourcePoolService.toggleSystem(this.endpoint.Id, namespaceName, !this.isSystem); | ||||
|         await this.KubernetesNamespaceService.refreshCacheAsync(); | ||||
| 
 | ||||
|         this.Notifications.success('Namespace successfully updated', namespaceName); | ||||
|         this.$state.reload(this.$state.current); | ||||
|  |  | |||
|  | @ -21,7 +21,6 @@ class KubernetesResourcePoolsController { | |||
|   } | ||||
| 
 | ||||
|   async onReload() { | ||||
|     await this.KubernetesNamespaceService.refreshCacheAsync(); | ||||
|     this.$state.reload(this.$state.current); | ||||
|   } | ||||
| 
 | ||||
|  | @ -50,7 +49,6 @@ class KubernetesResourcePoolsController { | |||
|       } finally { | ||||
|         --actionCount; | ||||
|         if (actionCount === 0) { | ||||
|           await this.KubernetesNamespaceService.refreshCacheAsync(); | ||||
|           this.$state.reload(this.$state.current); | ||||
|         } | ||||
|       } | ||||
|  | @ -77,7 +75,7 @@ class KubernetesResourcePoolsController { | |||
| 
 | ||||
|   async getResourcePoolsAsync() { | ||||
|     try { | ||||
|       this.resourcePools = await this.KubernetesResourcePoolService.get('', { getQuota: true, refreshCache: true }); | ||||
|       this.resourcePools = await this.KubernetesResourcePoolService.get('', { getQuota: true }); | ||||
|     } catch (err) { | ||||
|       this.Notifications.error('Failure', err, 'Unable to retreive namespaces'); | ||||
|     } | ||||
|  |  | |||
|  | @ -127,15 +127,6 @@ angular.module('portainer.app').factory('LocalStorage', [ | |||
|       getKubernetesSummaryToggle() { | ||||
|         return localStorageService.get('kubernetes_summary_expanded'); | ||||
|       }, | ||||
|       storeAllowedNamespaces: function (namespaces) { | ||||
|         localStorageService.set('ALLOWED_NAMESPACES', namespaces); | ||||
|       }, | ||||
|       getAllowedNamespaces: function () { | ||||
|         return localStorageService.get('ALLOWED_NAMESPACES'); | ||||
|       }, | ||||
|       deleteAllowedNamespaces: function () { | ||||
|         localStorageService.remove('ALLOWED_NAMESPACES'); | ||||
|       }, | ||||
|     }; | ||||
|   }, | ||||
| ]); | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ export function useNamespaces(environmentId: EnvironmentId) { | |||
|     async () => { | ||||
|       const namespaces = await getNamespaces(environmentId); | ||||
|       const namespaceNames = Object.keys(namespaces); | ||||
|       // use seflsubjectaccess reviews to avoid forbidden requests
 | ||||
|       // use selfsubjectaccess reviews to avoid forbidden requests
 | ||||
|       const allNamespaceAccessReviews = await Promise.all( | ||||
|         namespaceNames.map((namespaceName) => | ||||
|           getSelfSubjectAccessReview(environmentId, namespaceName) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Prabhat Khera
						Prabhat Khera