121787: Get rid of multiple unnecessary requests on browse by pages

This commit is contained in:
Koen Pauwels
2024-12-02 14:51:08 +01:00
committed by Jens Vannerum
parent b454e49553
commit a105bcd6f4
8 changed files with 60 additions and 26 deletions

View File

@@ -18,7 +18,10 @@ import {
combineLatest as observableCombineLatest, combineLatest as observableCombineLatest,
Observable, Observable,
} from 'rxjs'; } from 'rxjs';
import { map } from 'rxjs/operators'; import {
map,
take,
} from 'rxjs/operators';
import { ThemedBrowseByComponent } from 'src/app/shared/browse-by/themed-browse-by.component'; import { ThemedBrowseByComponent } from 'src/app/shared/browse-by/themed-browse-by.component';
import { import {
@@ -53,7 +56,6 @@ import { VarDirective } from '../../shared/utils/var.directive';
import { import {
BrowseByMetadataComponent, BrowseByMetadataComponent,
browseParamsToOptions, browseParamsToOptions,
getBrowseSearchOptions,
} from '../browse-by-metadata/browse-by-metadata.component'; } from '../browse-by-metadata/browse-by-metadata.component';
@Component({ @Component({
@@ -104,15 +106,18 @@ export class BrowseByDateComponent extends BrowseByMetadataComponent implements
ngOnInit(): void { ngOnInit(): void {
const sortConfig = new SortOptions('default', SortDirection.ASC); const sortConfig = new SortOptions('default', SortDirection.ASC);
this.startsWithType = StartsWithType.date; this.startsWithType = StartsWithType.date;
// include the thumbnail configuration in browse search options
this.updatePage(getBrowseSearchOptions(this.defaultBrowseId, this.paginationConfig, sortConfig, this.fetchThumbnails));
this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig);
this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig);
this.subs.push( this.subs.push(
observableCombineLatest([this.route.params, this.route.queryParams, this.scope$, this.route.data, observableCombineLatest(
this.currentPagination$, this.currentSort$]).pipe( [ this.route.params.pipe(take(1)),
map(([routeParams, queryParams, scope, data, currentPage, currentSort]) => { this.route.queryParams,
return [Object.assign({}, routeParams, queryParams, data), scope, currentPage, currentSort]; this.scope$,
this.currentPagination$,
this.currentSort$,
]).pipe(
map(([routeParams, queryParams, scope, currentPage, currentSort]) => {
return [Object.assign({}, routeParams, queryParams), scope, currentPage, currentSort];
}), }),
).subscribe(([params, scope, currentPage, currentSort]: [Params, string, PaginationComponentOptions, SortOptions]) => { ).subscribe(([params, scope, currentPage, currentSort]: [Params, string, PaginationComponentOptions, SortOptions]) => {
const metadataKeys = params.browseDefinition ? params.browseDefinition.metadataKeys : this.defaultMetadataKeys; const metadataKeys = params.browseDefinition ? params.browseDefinition.metadataKeys : this.defaultMetadataKeys;

View File

@@ -23,7 +23,10 @@ import {
of as observableOf, of as observableOf,
Subscription, Subscription,
} from 'rxjs'; } from 'rxjs';
import { map } from 'rxjs/operators'; import {
map,
take,
} from 'rxjs/operators';
import { ThemedBrowseByComponent } from 'src/app/shared/browse-by/themed-browse-by.component'; import { ThemedBrowseByComponent } from 'src/app/shared/browse-by/themed-browse-by.component';
import { import {
@@ -216,7 +219,13 @@ export class BrowseByMetadataComponent implements OnInit, OnChanges, OnDestroy {
this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig);
this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig);
this.subs.push( this.subs.push(
observableCombineLatest([this.route.params, this.route.queryParams, this.scope$, this.currentPagination$, this.currentSort$]).pipe( observableCombineLatest(
[ this.route.params.pipe(take(1)),
this.route.queryParams,
this.scope$,
this.currentPagination$,
this.currentSort$,
]).pipe(
map(([routeParams, queryParams, scope, currentPage, currentSort]) => { map(([routeParams, queryParams, scope, currentPage, currentSort]) => {
return [Object.assign({}, routeParams, queryParams), scope, currentPage, currentSort]; return [Object.assign({}, routeParams, queryParams), scope, currentPage, currentSort];
}), }),

View File

@@ -23,7 +23,7 @@ import { BrowseBySwitcherComponent } from '../browse-by-switcher/browse-by-switc
}) })
export class BrowseByPageComponent implements OnInit { export class BrowseByPageComponent implements OnInit {
browseByType$: Observable<BrowseByDataType>; browseByType$: Observable<{type: BrowseByDataType }>;
constructor( constructor(
protected route: ActivatedRoute, protected route: ActivatedRoute,
@@ -35,7 +35,7 @@ export class BrowseByPageComponent implements OnInit {
*/ */
ngOnInit(): void { ngOnInit(): void {
this.browseByType$ = this.route.data.pipe( this.browseByType$ = this.route.data.pipe(
map((data: { browseDefinition: BrowseDefinition }) => data.browseDefinition.getRenderType()), map((data: { browseDefinition: BrowseDefinition }) => ({ type: data.browseDefinition.getRenderType() })),
); );
} }

View File

@@ -85,7 +85,7 @@ describe('BrowseBySwitcherComponent', () => {
types.forEach((type: NonHierarchicalBrowseDefinition) => { types.forEach((type: NonHierarchicalBrowseDefinition) => {
describe(`when switching to a browse-by page for "${type.id}"`, () => { describe(`when switching to a browse-by page for "${type.id}"`, () => {
beforeEach(async () => { beforeEach(async () => {
comp.browseByType = type.dataType; comp.browseByType = type as any;
comp.ngOnChanges({ comp.ngOnChanges({
browseByType: new SimpleChange(undefined, type.dataType, true), browseByType: new SimpleChange(undefined, type.dataType, true),
}); });

View File

@@ -24,7 +24,7 @@ export class BrowseBySwitcherComponent extends AbstractComponentLoaderComponent<
@Input() context: Context; @Input() context: Context;
@Input() browseByType: BrowseByDataType; @Input() browseByType: { type: BrowseByDataType };
@Input() displayTitle: boolean; @Input() displayTitle: boolean;
@@ -43,7 +43,7 @@ export class BrowseBySwitcherComponent extends AbstractComponentLoaderComponent<
]; ];
public getComponent(): GenericConstructor<Component> { public getComponent(): GenericConstructor<Component> {
return getComponentByBrowseByType(this.browseByType, this.context, this.themeService.getThemeName()); return getComponentByBrowseByType(this.browseByType.type, this.context, this.themeService.getThemeName());
} }
} }

View File

@@ -9,7 +9,10 @@ import {
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { combineLatest as observableCombineLatest } from 'rxjs'; import { combineLatest as observableCombineLatest } from 'rxjs';
import { map } from 'rxjs/operators'; import {
map,
take,
} from 'rxjs/operators';
import { import {
SortDirection, SortDirection,
@@ -28,7 +31,6 @@ import { VarDirective } from '../../shared/utils/var.directive';
import { import {
BrowseByMetadataComponent, BrowseByMetadataComponent,
browseParamsToOptions, browseParamsToOptions,
getBrowseSearchOptions,
} from '../browse-by-metadata/browse-by-metadata.component'; } from '../browse-by-metadata/browse-by-metadata.component';
@Component({ @Component({
@@ -58,12 +60,16 @@ export class BrowseByTitleComponent extends BrowseByMetadataComponent implements
ngOnInit(): void { ngOnInit(): void {
const sortConfig = new SortOptions('dc.title', SortDirection.ASC); const sortConfig = new SortOptions('dc.title', SortDirection.ASC);
// include the thumbnail configuration in browse search options
this.updatePage(getBrowseSearchOptions(this.defaultBrowseId, this.paginationConfig, sortConfig, this.fetchThumbnails));
this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig);
this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig);
this.subs.push( this.subs.push(
observableCombineLatest([this.route.params, this.route.queryParams, this.scope$, this.currentPagination$, this.currentSort$]).pipe( observableCombineLatest(
[ this.route.params.pipe(take(1)),
this.route.queryParams,
this.scope$,
this.currentPagination$,
this.currentSort$,
]).pipe(
map(([routeParams, queryParams, scope, currentPage, currentSort]) => { map(([routeParams, queryParams, scope, currentPage, currentSort]) => {
return [Object.assign({}, routeParams, queryParams), scope, currentPage, currentSort]; return [Object.assign({}, routeParams, queryParams), scope, currentPage, currentSort];
}), }),

View File

@@ -7,7 +7,9 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { import {
combineLatest, combineLatest,
combineLatest as observableCombineLatest, combineLatest as observableCombineLatest,
mergeMap,
Observable, Observable,
of as observableOf,
} from 'rxjs'; } from 'rxjs';
import { import {
filter, filter,
@@ -17,6 +19,7 @@ import {
} from 'rxjs/operators'; } from 'rxjs/operators';
import { PUBLICATION_CLAIMS_PATH } from './admin/admin-notifications/admin-notifications-routing-paths'; import { PUBLICATION_CLAIMS_PATH } from './admin/admin-notifications/admin-notifications-routing-paths';
import { AuthService } from './core/auth/auth.service';
import { BrowseService } from './core/browse/browse.service'; import { BrowseService } from './core/browse/browse.service';
import { ConfigurationDataService } from './core/data/configuration-data.service'; import { ConfigurationDataService } from './core/data/configuration-data.service';
import { AuthorizationDataService } from './core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from './core/data/feature-authorization/authorization-data.service';
@@ -62,6 +65,7 @@ export class MenuResolverService {
protected modalService: NgbModal, protected modalService: NgbModal,
protected scriptDataService: ScriptDataService, protected scriptDataService: ScriptDataService,
protected configurationDataService: ConfigurationDataService, protected configurationDataService: ConfigurationDataService,
protected authService: AuthService,
) { ) {
} }
@@ -71,7 +75,7 @@ export class MenuResolverService {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return combineLatest([ return combineLatest([
this.createPublicMenu$(), this.createPublicMenu$(),
this.createAdminMenu$(), this.createAdminMenuIfLoggedIn$(),
]).pipe( ]).pipe(
map((menusDone: boolean[]) => menusDone.every(Boolean)), map((menusDone: boolean[]) => menusDone.every(Boolean)),
); );
@@ -147,6 +151,15 @@ export class MenuResolverService {
return this.waitForMenu$(MenuID.PUBLIC); return this.waitForMenu$(MenuID.PUBLIC);
} }
/**
* Initialize all menu sections and items for {@link MenuID.ADMIN}, only if the user is logged in.
*/
createAdminMenuIfLoggedIn$() {
return this.authService.isAuthenticated().pipe(
mergeMap((isAuthenticated) => isAuthenticated ? this.createAdminMenu$() : observableOf(true)),
);
}
/** /**
* Initialize all menu sections and items for {@link MenuID.ADMIN} * Initialize all menu sections and items for {@link MenuID.ADMIN}
*/ */
@@ -156,8 +169,6 @@ export class MenuResolverService {
this.createExportMenuSections(); this.createExportMenuSections();
this.createImportMenuSections(); this.createImportMenuSections();
this.createAccessControlMenuSections(); this.createAccessControlMenuSections();
this.createReportMenuSections();
return this.waitForMenu$(MenuID.ADMIN); return this.waitForMenu$(MenuID.ADMIN);
} }

View File

@@ -26,7 +26,9 @@ import { ConfigurationDataServiceStub } from './shared/testing/configuration-dat
import { MenuServiceStub } from './shared/testing/menu-service.stub'; import { MenuServiceStub } from './shared/testing/menu-service.stub';
import { createPaginatedList } from './shared/testing/utils.test'; import { createPaginatedList } from './shared/testing/utils.test';
import createSpy = jasmine.createSpy; import createSpy = jasmine.createSpy;
import { AuthService } from './core/auth/auth.service';
import { MenuResolverService } from './menu-resolver.service'; import { MenuResolverService } from './menu-resolver.service';
import { AuthServiceStub } from './shared/testing/auth-service.stub';
const BOOLEAN = { t: true, f: false }; const BOOLEAN = { t: true, f: false };
const MENU_STATE = { const MENU_STATE = {
@@ -80,6 +82,7 @@ describe('menuResolver', () => {
{ provide: ScriptDataService, useValue: scriptService }, { provide: ScriptDataService, useValue: scriptService },
{ provide: ConfigurationDataService, useValue: configurationDataService }, { provide: ConfigurationDataService, useValue: configurationDataService },
{ provide: NgbModal, useValue: mockNgbModal }, { provide: NgbModal, useValue: mockNgbModal },
{ provide: AuthService, useValue: AuthServiceStub },
MenuResolverService, MenuResolverService,
], ],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
@@ -94,19 +97,19 @@ describe('menuResolver', () => {
describe('resolve', () => { describe('resolve', () => {
it('should create all menus', (done) => { it('should create all menus', (done) => {
spyOn(resolver, 'createPublicMenu$').and.returnValue(observableOf(true)); spyOn(resolver, 'createPublicMenu$').and.returnValue(observableOf(true));
spyOn(resolver, 'createAdminMenu$').and.returnValue(observableOf(true)); spyOn(resolver, 'createAdminMenuIfLoggedIn$').and.returnValue(observableOf(true));
resolver.resolve(null, null).subscribe(resolved => { resolver.resolve(null, null).subscribe(resolved => {
expect(resolved).toBeTrue(); expect(resolved).toBeTrue();
expect(resolver.createPublicMenu$).toHaveBeenCalled(); expect(resolver.createPublicMenu$).toHaveBeenCalled();
expect(resolver.createAdminMenu$).toHaveBeenCalled(); expect(resolver.createAdminMenuIfLoggedIn$).toHaveBeenCalled();
done(); done();
}); });
}); });
it('should return an Observable that emits true as soon as all menus are created', () => { it('should return an Observable that emits true as soon as all menus are created', () => {
spyOn(resolver, 'createPublicMenu$').and.returnValue(cold('--(t|)', BOOLEAN)); spyOn(resolver, 'createPublicMenu$').and.returnValue(cold('--(t|)', BOOLEAN));
spyOn(resolver, 'createAdminMenu$').and.returnValue(cold('----(t|)', BOOLEAN)); spyOn(resolver, 'createAdminMenuIfLoggedIn$').and.returnValue(cold('----(t|)', BOOLEAN));
expect(resolver.resolve(null, null)).toBeObservable(cold('----(t|)', BOOLEAN)); expect(resolver.resolve(null, null)).toBeObservable(cold('----(t|)', BOOLEAN));
}); });