commit
						4e57e31284
					
				| @ -711,10 +711,10 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | |||||||
|      * @param newCourses New courses. |      * @param newCourses New courses. | ||||||
|      * @return Whether it has meaningful changes. |      * @return Whether it has meaningful changes. | ||||||
|      */ |      */ | ||||||
|     protected coursesHaveMeaningfulChanges( |     protected async coursesHaveMeaningfulChanges( | ||||||
|         previousCourses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], |         previousCourses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], | ||||||
|         newCourses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], |         newCourses: CoreEnrolledCourseDataWithExtraInfoAndOptions[], | ||||||
|     ): boolean { |     ): Promise<boolean> { | ||||||
|         if (previousCourses.length !== newCourses.length) { |         if (previousCourses.length !== newCourses.length) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| @ -746,10 +746,10 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | |||||||
|      * @param newCourses New courses. |      * @param newCourses New courses. | ||||||
|      * @return Whether it has meaningful changes. |      * @return Whether it has meaningful changes. | ||||||
|      */ |      */ | ||||||
|     protected customFilterCoursesHaveMeaningfulChanges( |     protected async customFilterCoursesHaveMeaningfulChanges( | ||||||
|         previousCourses: CoreCourseSummaryData[], |         previousCourses: CoreCourseSummaryData[], | ||||||
|         newCourses: CoreCourseSummaryData[], |         newCourses: CoreCourseSummaryData[], | ||||||
|     ): boolean { |     ): Promise<boolean> { | ||||||
|         if (previousCourses.length !== newCourses.length) { |         if (previousCourses.length !== newCourses.length) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ export class PageLoadWatcher { | |||||||
|     protected ongoingRequests = 0; |     protected ongoingRequests = 0; | ||||||
|     protected components = new Set<AsyncComponent>(); |     protected components = new Set<AsyncComponent>(); | ||||||
|     protected loadedTimeout?: number; |     protected loadedTimeout?: number; | ||||||
|  |     protected hasChangesPromises: Promise<boolean>[] = []; | ||||||
| 
 | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         protected loadsManager: PageLoadsManager, |         protected loadsManager: PageLoadsManager, | ||||||
| @ -97,7 +98,7 @@ export class PageLoadWatcher { | |||||||
|      */ |      */ | ||||||
|     watchRequest<T>( |     watchRequest<T>( | ||||||
|         observable: WSObservable<T>, |         observable: WSObservable<T>, | ||||||
|         hasMeaningfulChanges?: (previousValue: T, newValue: T) => boolean, |         hasMeaningfulChanges?: (previousValue: T, newValue: T) => Promise<boolean>, | ||||||
|     ): Promise<T> { |     ): Promise<T> { | ||||||
|         const promisedValue = new CorePromisedValue<T>(); |         const promisedValue = new CorePromisedValue<T>(); | ||||||
|         let subscription: Subscription | null = null; |         let subscription: Subscription | null = null; | ||||||
| @ -124,9 +125,11 @@ export class PageLoadWatcher { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // Second value, it means data was updated in background. Compare data.
 |                 // Second value, it means data was updated in background. Compare data.
 | ||||||
|                 if (hasMeaningfulChanges?.(firstValue, value)) { |                 if (!hasMeaningfulChanges) { | ||||||
|                     this.hasChanges = true; |                     return; | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 this.hasChangesPromises.push(CoreUtils.ignoreErrors(hasMeaningfulChanges(firstValue, value), false)); | ||||||
|             }, |             }, | ||||||
|             error: (error) => { |             error: (error) => { | ||||||
|                 promisedValue.reject(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.
 |         // 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.
 |         // If a new component or a new request starts the timeout will be cancelled, no need to double check it.
 | ||||||
|         clearTimeout(this.loadedTimeout); |         clearTimeout(this.loadedTimeout); | ||||||
|         this.loadedTimeout = window.setTimeout(() => { |         this.loadedTimeout = window.setTimeout(async () => { | ||||||
|             // Loading finished.
 |             // Loading finished. Calculate has changes.
 | ||||||
|  |             const values = await Promise.all(this.hasChangesPromises); | ||||||
|  |             this.hasChanges = this.hasChanges || values.includes(true); | ||||||
|  | 
 | ||||||
|             this.loadsManager.onPageLoaded(this); |             this.loadsManager.onPageLoaded(this); | ||||||
|         }, 100); |         }, 100); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -125,7 +125,7 @@ export class CoreSite { | |||||||
|     protected lastAutoLogin = 0; |     protected lastAutoLogin = 0; | ||||||
|     protected offlineDisabled = false; |     protected offlineDisabled = false; | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 |     // 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 requestQueue: RequestQueueItem[] = []; | ||||||
|     protected requestQueueTimeout: number | null = null; |     protected requestQueueTimeout: number | null = null; | ||||||
|     protected tokenPluginFileWorks?: boolean; |     protected tokenPluginFileWorks?: boolean; | ||||||
| @ -636,9 +636,10 @@ export class CoreSite { | |||||||
| 
 | 
 | ||||||
|         const cacheId = this.getCacheId(method, data); |         const cacheId = this.getCacheId(method, data); | ||||||
| 
 | 
 | ||||||
|         // Check for an ongoing identical request if we're not ignoring cache.
 |         // Check for an ongoing identical request.
 | ||||||
|         if (preSets.getFromCache && this.ongoingRequests[cacheId] !== undefined) { |         const ongoingRequest = this.getOngoingRequest<T>(cacheId, preSets); | ||||||
|             return this.ongoingRequests[cacheId]; |         if (ongoingRequest) { | ||||||
|  |             return ongoingRequest; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const observable = this.performRequest<T>(method, data, preSets, wsPreSets).pipe( |         const observable = this.performRequest<T>(method, data, preSets, wsPreSets).pipe( | ||||||
| @ -646,18 +647,68 @@ export class CoreSite { | |||||||
|             map((data) => CoreUtils.clone(data)), |             map((data) => CoreUtils.clone(data)), | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         this.ongoingRequests[cacheId] = observable; |         this.setOngoingRequest(cacheId, preSets, observable); | ||||||
| 
 | 
 | ||||||
|         return observable.pipe( |         return observable.pipe( | ||||||
|             finalize(() => { |             finalize(() => { | ||||||
|                 // Clear the ongoing request unless it has changed (e.g. a new request that ignores cache).
 |                 this.clearOngoingRequest(cacheId, preSets, observable); | ||||||
|                 if (this.ongoingRequests[cacheId] === observable) { |  | ||||||
|                     delete this.ongoingRequests[cacheId]; |  | ||||||
|                 } |  | ||||||
|             }), |             }), | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 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. |      * 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.
 |         // 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>(); |         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.
 |             // Return a clone of the original object, this may prevent errors if in the callback the object is modified.
 | ||||||
|             map((data) => CoreUtils.clone(data)), |             map((data) => CoreUtils.clone(data)), | ||||||
|             finalize(() => { |             finalize(() => { | ||||||
|                 // Clear the ongoing request unless it has changed (e.g. a new request that ignores cache).
 |                 this.clearOngoingRequest(cacheId, cachePreSets, observable); | ||||||
|                 if (this.ongoingRequests[cacheId] === observable) { |  | ||||||
|                     delete this.ongoingRequests[cacheId]; |  | ||||||
|                 } |  | ||||||
|             }), |             }), | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         this.ongoingRequests[cacheId] = observable; |         this.setOngoingRequest(cacheId, cachePreSets, observable); | ||||||
| 
 | 
 | ||||||
|         this.getFromCache<CoreSitePublicConfigResponse>(method, {}, cachePreSets, false) |         this.getFromCache<CoreSitePublicConfigResponse>(method, {}, cachePreSets, false) | ||||||
|             .then(cachedData => cachedData.response) |             .then(cachedData => cachedData.response) | ||||||
| @ -1916,16 +1967,16 @@ export class CoreSite { | |||||||
|                 // Return the requested setting.
 |                 // Return the requested setting.
 | ||||||
|                 for (const x in config.settings) { |                 for (const x in config.settings) { | ||||||
|                     if (config.settings[x].name == name) { |                     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); |                 throw new CoreError('Site config not found: ' + name); | ||||||
|             } else { |             } else { | ||||||
|                 // Return all settings in the same array.
 |                 // Return all settings in the same array.
 | ||||||
|                 const settings = {}; |                 const settings: CoreSiteConfig = {}; | ||||||
|                 config.settings.forEach((setting) => { |                 config.settings.forEach((setting) => { | ||||||
|                     settings[setting.name] = setting.value; |                     settings[setting.name] = String(setting.value); | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 return settings; |                 return settings; | ||||||
| @ -2686,7 +2737,7 @@ export enum CoreSiteInfoUserHomepage { | |||||||
| export type CoreSiteConfigResponse = { | export type CoreSiteConfigResponse = { | ||||||
|     settings: { // Settings.
 |     settings: { // Settings.
 | ||||||
|         name: string; // The name of the setting.
 |         name: string; // The name of the setting.
 | ||||||
|         value: string; // The value of the setting.
 |         value: string | number; // The value of the setting.
 | ||||||
|     }[]; |     }[]; | ||||||
|     warnings?: CoreWSExternalWarning[]; |     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. |  * 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>; | 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