commit
						4e57e31284
					
				| @ -711,10 +711,10 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
|      * @param newCourses New courses. | ||||
|      * @return Whether it has meaningful changes. | ||||
|      */ | ||||
|     protected coursesHaveMeaningfulChanges( | ||||
|     protected async coursesHaveMeaningfulChanges( | ||||
|         previousCourses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], | ||||
|         newCourses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], | ||||
|     ): boolean { | ||||
|     ): Promise<boolean> { | ||||
|         if (previousCourses.length !== newCourses.length) { | ||||
|             return true; | ||||
|         } | ||||
| @ -746,10 +746,10 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
|      * @param newCourses New courses. | ||||
|      * @return Whether it has meaningful changes. | ||||
|      */ | ||||
|     protected customFilterCoursesHaveMeaningfulChanges( | ||||
|     protected async customFilterCoursesHaveMeaningfulChanges( | ||||
|         previousCourses: CoreCourseSummaryData[], | ||||
|         newCourses: CoreCourseSummaryData[], | ||||
|     ): boolean { | ||||
|     ): Promise<boolean> { | ||||
|         if (previousCourses.length !== newCourses.length) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -29,6 +29,7 @@ export class PageLoadWatcher { | ||||
|     protected ongoingRequests = 0; | ||||
|     protected components = new Set<AsyncComponent>(); | ||||
|     protected loadedTimeout?: number; | ||||
|     protected hasChangesPromises: Promise<boolean>[] = []; | ||||
| 
 | ||||
|     constructor( | ||||
|         protected loadsManager: PageLoadsManager, | ||||
| @ -97,7 +98,7 @@ export class PageLoadWatcher { | ||||
|      */ | ||||
|     watchRequest<T>( | ||||
|         observable: WSObservable<T>, | ||||
|         hasMeaningfulChanges?: (previousValue: T, newValue: T) => boolean, | ||||
|         hasMeaningfulChanges?: (previousValue: T, newValue: T) => Promise<boolean>, | ||||
|     ): Promise<T> { | ||||
|         const promisedValue = new CorePromisedValue<T>(); | ||||
|         let subscription: Subscription | null = null; | ||||
| @ -124,9 +125,11 @@ export class PageLoadWatcher { | ||||
|                 } | ||||
| 
 | ||||
|                 // Second value, it means data was updated in background. Compare data.
 | ||||
|                 if (hasMeaningfulChanges?.(firstValue, value)) { | ||||
|                     this.hasChanges = true; | ||||
|                 if (!hasMeaningfulChanges) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 this.hasChangesPromises.push(CoreUtils.ignoreErrors(hasMeaningfulChanges(firstValue, value), false)); | ||||
|             }, | ||||
|             error: (error) => { | ||||
|                 promisedValue.reject(error); | ||||
| @ -150,8 +153,11 @@ export class PageLoadWatcher { | ||||
|         // It seems load has finished. Wait to make sure no new component has been rendered and started loading.
 | ||||
|         // If a new component or a new request starts the timeout will be cancelled, no need to double check it.
 | ||||
|         clearTimeout(this.loadedTimeout); | ||||
|         this.loadedTimeout = window.setTimeout(() => { | ||||
|             // Loading finished.
 | ||||
|         this.loadedTimeout = window.setTimeout(async () => { | ||||
|             // Loading finished. Calculate has changes.
 | ||||
|             const values = await Promise.all(this.hasChangesPromises); | ||||
|             this.hasChanges = this.hasChanges || values.includes(true); | ||||
| 
 | ||||
|             this.loadsManager.onPageLoaded(this); | ||||
|         }, 100); | ||||
|     } | ||||
|  | ||||
| @ -125,7 +125,7 @@ export class CoreSite { | ||||
|     protected lastAutoLogin = 0; | ||||
|     protected offlineDisabled = false; | ||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||
|     protected ongoingRequests: { [cacheId: string]: WSObservable<any> } = {}; | ||||
|     protected ongoingRequests: Record<string, Record<OngoingRequestType, WSObservable<any> | undefined>> = {}; | ||||
|     protected requestQueue: RequestQueueItem[] = []; | ||||
|     protected requestQueueTimeout: number | null = null; | ||||
|     protected tokenPluginFileWorks?: boolean; | ||||
| @ -636,9 +636,10 @@ export class CoreSite { | ||||
| 
 | ||||
|         const cacheId = this.getCacheId(method, data); | ||||
| 
 | ||||
|         // Check for an ongoing identical request if we're not ignoring cache.
 | ||||
|         if (preSets.getFromCache && this.ongoingRequests[cacheId] !== undefined) { | ||||
|             return this.ongoingRequests[cacheId]; | ||||
|         // Check for an ongoing identical request.
 | ||||
|         const ongoingRequest = this.getOngoingRequest<T>(cacheId, preSets); | ||||
|         if (ongoingRequest) { | ||||
|             return ongoingRequest; | ||||
|         } | ||||
| 
 | ||||
|         const observable = this.performRequest<T>(method, data, preSets, wsPreSets).pipe( | ||||
| @ -646,18 +647,68 @@ export class CoreSite { | ||||
|             map((data) => CoreUtils.clone(data)), | ||||
|         ); | ||||
| 
 | ||||
|         this.ongoingRequests[cacheId] = observable; | ||||
|         this.setOngoingRequest(cacheId, preSets, observable); | ||||
| 
 | ||||
|         return observable.pipe( | ||||
|             finalize(() => { | ||||
|                 // Clear the ongoing request unless it has changed (e.g. a new request that ignores cache).
 | ||||
|                 if (this.ongoingRequests[cacheId] === observable) { | ||||
|                     delete this.ongoingRequests[cacheId]; | ||||
|                 } | ||||
|                 this.clearOngoingRequest(cacheId, preSets, observable); | ||||
|             }), | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get an ongoing request if there's one already. | ||||
|      * | ||||
|      * @param cacheId Cache ID. | ||||
|      * @param preSets Presets. | ||||
|      * @return Ongoing request if it exists. | ||||
|      */ | ||||
|     protected getOngoingRequest<T = unknown>(cacheId: string, preSets: CoreSiteWSPreSets): WSObservable<T> | undefined { | ||||
|         if (preSets.updateInBackground) { | ||||
|             return this.ongoingRequests[cacheId]?.[OngoingRequestType.UPDATE_IN_BACKGROUND]; | ||||
|         } else if (preSets.getFromCache) { // Only reuse ongoing request when using cache.
 | ||||
|             return this.ongoingRequests[cacheId]?.[OngoingRequestType.STANDARD]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Store an ongoing request in memory. | ||||
|      * | ||||
|      * @param cacheId Cache ID. | ||||
|      * @param preSets Presets. | ||||
|      * @param request Request to store. | ||||
|      */ | ||||
|     protected setOngoingRequest<T = unknown>(cacheId: string, preSets: CoreSiteWSPreSets, request: WSObservable<T>): void { | ||||
|         this.ongoingRequests[cacheId] = this.ongoingRequests[cacheId] ?? {}; | ||||
| 
 | ||||
|         if (preSets.updateInBackground) { | ||||
|             this.ongoingRequests[cacheId][OngoingRequestType.UPDATE_IN_BACKGROUND] = request; | ||||
|         } else { | ||||
|             this.ongoingRequests[cacheId][OngoingRequestType.STANDARD] = request; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Clear the ongoing request unless it has changed (e.g. a new request that ignores cache). | ||||
|      * | ||||
|      * @param cacheId Cache ID. | ||||
|      * @param preSets Presets. | ||||
|      * @param request Current request. | ||||
|      */ | ||||
|     protected clearOngoingRequest<T = unknown>(cacheId: string, preSets: CoreSiteWSPreSets, request: WSObservable<T>): void { | ||||
|         this.ongoingRequests[cacheId] = this.ongoingRequests[cacheId] ?? {}; | ||||
| 
 | ||||
|         if (preSets.updateInBackground) { | ||||
|             if (this.ongoingRequests[cacheId][OngoingRequestType.UPDATE_IN_BACKGROUND] === request) { | ||||
|                 delete this.ongoingRequests[cacheId][OngoingRequestType.UPDATE_IN_BACKGROUND]; | ||||
|             } | ||||
|         } else { | ||||
|             if (this.ongoingRequests[cacheId][OngoingRequestType.STANDARD] === request) { | ||||
|                 delete this.ongoingRequests[cacheId][OngoingRequestType.STANDARD]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Perform a request, getting the response either from cache or WebService. | ||||
|      * | ||||
| @ -1640,8 +1691,11 @@ export class CoreSite { | ||||
|         } | ||||
| 
 | ||||
|         // Check for an ongoing identical request if we're not ignoring cache.
 | ||||
|         if (cachePreSets.getFromCache && this.ongoingRequests[cacheId] !== undefined) { | ||||
|             return await firstValueFrom(this.ongoingRequests[cacheId]); | ||||
| 
 | ||||
|         // Check for an ongoing identical request.
 | ||||
|         const ongoingRequest = this.getOngoingRequest<CoreSitePublicConfigResponse>(cacheId, cachePreSets); | ||||
|         if (ongoingRequest) { | ||||
|             return firstValueFrom(ongoingRequest); | ||||
|         } | ||||
| 
 | ||||
|         const subject = new Subject<CoreSitePublicConfigResponse>(); | ||||
| @ -1649,14 +1703,11 @@ export class CoreSite { | ||||
|             // Return a clone of the original object, this may prevent errors if in the callback the object is modified.
 | ||||
|             map((data) => CoreUtils.clone(data)), | ||||
|             finalize(() => { | ||||
|                 // Clear the ongoing request unless it has changed (e.g. a new request that ignores cache).
 | ||||
|                 if (this.ongoingRequests[cacheId] === observable) { | ||||
|                     delete this.ongoingRequests[cacheId]; | ||||
|                 } | ||||
|                 this.clearOngoingRequest(cacheId, cachePreSets, observable); | ||||
|             }), | ||||
|         ); | ||||
| 
 | ||||
|         this.ongoingRequests[cacheId] = observable; | ||||
|         this.setOngoingRequest(cacheId, cachePreSets, observable); | ||||
| 
 | ||||
|         this.getFromCache<CoreSitePublicConfigResponse>(method, {}, cachePreSets, false) | ||||
|             .then(cachedData => cachedData.response) | ||||
| @ -1916,16 +1967,16 @@ export class CoreSite { | ||||
|                 // Return the requested setting.
 | ||||
|                 for (const x in config.settings) { | ||||
|                     if (config.settings[x].name == name) { | ||||
|                         return config.settings[x].value; | ||||
|                         return String(config.settings[x].value); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 throw new CoreError('Site config not found: ' + name); | ||||
|             } else { | ||||
|                 // Return all settings in the same array.
 | ||||
|                 const settings = {}; | ||||
|                 const settings: CoreSiteConfig = {}; | ||||
|                 config.settings.forEach((setting) => { | ||||
|                     settings[setting.name] = setting.value; | ||||
|                     settings[setting.name] = String(setting.value); | ||||
|                 }); | ||||
| 
 | ||||
|                 return settings; | ||||
| @ -2686,7 +2737,7 @@ export enum CoreSiteInfoUserHomepage { | ||||
| export type CoreSiteConfigResponse = { | ||||
|     settings: { // Settings.
 | ||||
|         name: string; // The name of the setting.
 | ||||
|         value: string; // The value of the setting.
 | ||||
|         value: string | number; // The value of the setting.
 | ||||
|     }[]; | ||||
|     warnings?: CoreWSExternalWarning[]; | ||||
| }; | ||||
| @ -2804,3 +2855,11 @@ type WSCachedError = { | ||||
|  * Otherwise, it will only return 1 value, either coming from cache or from the server. After this, it will complete. | ||||
|  */ | ||||
| export type WSObservable<T> = Observable<T>; | ||||
| 
 | ||||
| /** | ||||
|  * Type of ongoing requests stored in memory to avoid duplicating them. | ||||
|  */ | ||||
| enum OngoingRequestType { | ||||
|     STANDARD = 0, | ||||
|     UPDATE_IN_BACKGROUND = 1, | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user