From 51285727e6046af3b05940d61a17864b07b9e144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Tue, 14 Jun 2022 10:53:12 +0200 Subject: [PATCH] Use signalling in datepicker banner service to improve load https://community.openproject.org/wp/42231 --- .../api-v3-work-package-cached-subresource.ts | 2 +- .../app/core/apiv3/paths/apiv3-resource.ts | 54 ++++++++++++++++--- .../datepicker/datepicker.modal.service.ts | 22 ++++---- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/core/apiv3/endpoints/work_packages/api-v3-work-package-cached-subresource.ts b/frontend/src/app/core/apiv3/endpoints/work_packages/api-v3-work-package-cached-subresource.ts index 175c6f9a78..7db4eb05d5 100644 --- a/frontend/src/app/core/apiv3/endpoints/work_packages/api-v3-work-package-cached-subresource.ts +++ b/frontend/src/app/core/apiv3/endpoints/work_packages/api-v3-work-package-cached-subresource.ts @@ -52,7 +52,7 @@ export class ApiV3WorkPackageCachedSubresource extends ApiV3GettableResource) { diff --git a/frontend/src/app/core/apiv3/paths/apiv3-resource.ts b/frontend/src/app/core/apiv3/paths/apiv3-resource.ts index 768ba6180c..a7ad4bca21 100644 --- a/frontend/src/app/core/apiv3/paths/apiv3-resource.ts +++ b/frontend/src/app/core/apiv3/paths/apiv3-resource.ts @@ -16,6 +16,7 @@ import { import { HalResource } from 'core-app/features/hal/resources/hal-resource'; import { CollectionResource } from 'core-app/features/hal/resources/collection-resource'; import { getPaginatedResults } from 'core-app/core/apiv3/helpers/get-paginated-results'; +import { HttpClient } from '@angular/common/http'; export class ApiV3ResourcePath extends SimpleResource { readonly injector = this.apiRoot.injector; @@ -25,7 +26,7 @@ export class ApiV3ResourcePath extends SimpleResource { constructor(protected apiRoot:ApiV3Service, readonly basePath:string, readonly id:string|number, - protected parent?:ApiV3ResourcePath|ApiV3ResourceCollection) { + protected parent?:ApiV3ResourcePath|ApiV3ResourceCollection>) { super(basePath, id); } @@ -33,8 +34,14 @@ export class ApiV3ResourcePath extends SimpleResource { * Build a singular resource from the current segment * * @param segment Additional segment to add to the current path + * @param cls Class to use as return type */ - protected subResource(segment:string, cls:Constructor = ApiV3GettableResource as any):R { + protected subResource( + segment:string, + // eslint-disable-next-line @typescript-eslint/no-use-before-define + cls:Constructor = ApiV3GettableResource as unknown as Constructor, + ):R { + // eslint-disable-next-line new-cap return new cls(this.apiRoot, this.path, segment, this); } } @@ -66,6 +73,8 @@ export class ApiV3GettableResourceCollection> extends SimpleResourceCollection { readonly injector = this.apiRoot.injector; + @InjectField() http:HttpClient; + @InjectField() halResourceService:HalResourceService; constructor(protected apiRoot:ApiV3Service, @@ -121,6 +130,37 @@ export class ApiV3ResourceCollection> exte * @param resourceClass The APIV3 resource class to instantiate */ public filtered>(filters:ApiV3FilterBuilder, params:{ [key:string]:string } = {}, resourceClass?:Constructor):R { + const url = this.applyParams(filters, params); + const cls = resourceClass || ApiV3GettableResourceCollection; + // eslint-disable-next-line new-cap + return new cls(this.apiRoot, url.pathname, url.search, this) as R; + } + + /** + * Signal the endpoint with a given set of filters and select params. + * Returns an observable response. + * + * @param filters filter object to filter with + * @param select The signalling parameters to request + * @param params additional URL params to append + */ + public signalled(filters:ApiV3FilterBuilder, select:string[], params:{ [key:string]:string } = {}):Observable { + const url = this.applyParams(filters, { ...params, select: select.join(',') }); + + return this + .http + .get(url.toString()); + } + + /** + * Apply the given parameters to our API path and return an URL instance. + * + * @param filters {ApiV3FilterBuilder} Filter to be passed to the API + * @param params {ApiV3ListParameters} input parameters to apply + * @return {URL} the applied params to the path. + * @protected + */ + protected applyParams(filters:ApiV3FilterBuilder, params:{ [key:string]:string } = {}):URL { const url = new URL(this.path, window.location.origin); if (url.searchParams.has('filters')) { @@ -136,17 +176,19 @@ export class ApiV3ResourceCollection> exte url.searchParams.set(key, params[key]); }); - const cls = resourceClass || ApiV3GettableResourceCollection; - // eslint-disable-next-line new-cap - return new cls(this.apiRoot, url.pathname, url.search, this) as R; + return url; } /** * Build a singular resource from the current segment * * @param segment Additional segment to add to the current path + * @param cls Class to use as return type */ - protected subResource>(segment:string, cls:Constructor = ApiV3GettableResource as any):R { + protected subResource>( + segment:string, + cls:Constructor = ApiV3GettableResource as unknown as Constructor, + ):R { // eslint-disable-next-line new-cap return new cls(this.apiRoot, this.path, segment, this); } diff --git a/frontend/src/app/shared/components/datepicker/datepicker.modal.service.ts b/frontend/src/app/shared/components/datepicker/datepicker.modal.service.ts index 33d4c57b63..67c6656c64 100644 --- a/frontend/src/app/shared/components/datepicker/datepicker.modal.service.ts +++ b/frontend/src/app/shared/components/datepicker/datepicker.modal.service.ts @@ -46,8 +46,8 @@ import { combineLatest, Observable, } from 'rxjs'; -import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource'; import { HalResource } from 'core-app/features/hal/resources/hal-resource'; +import { IHALCollection } from 'core-app/core/apiv3/types/hal-collection.type'; @Injectable() export class DatepickerModalService { @@ -55,23 +55,27 @@ export class DatepickerModalService { private changeset:WorkPackageChangeset = this.locals.changeset as WorkPackageChangeset; - precedingWorkPackages$:Observable = this + precedingWorkPackages$:Observable<{ id:string }[]> = this .apiV3Service .work_packages - .filtered(ApiV3Filter('precedes', '=', [this.changeset.id])) - .get() + .signalled( + ApiV3Filter('precedes', '=', [this.changeset.id]), + ['elements/id'], + ) .pipe( - map((collection) => collection.elements), + map((collection:IHALCollection<{ id:string }>) => collection._embedded.elements || []), shareReplay(1), ); - followingWorkPackages$:Observable = this + followingWorkPackages$:Observable<{ id:string }[]> = this .apiV3Service .work_packages - .filtered(ApiV3Filter('follows', '=', [this.changeset.id])) - .get() + .signalled( + ApiV3Filter('follows', '=', [this.changeset.id]), + ['elements/id'], + ) .pipe( - map((collection) => collection.elements), + map((collection:IHALCollection<{ id:string }>) => collection._embedded.elements || []), shareReplay(1), );