mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[DURACOM-303] prevent possibly long-lasting search and browse calls in SSR
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { BrowseByDatePageComponent } from './browse-by-date-page.component';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
@@ -9,7 +9,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BrowseService } from '../../core/browse/browse.service';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
import { RouterMock } from '../../shared/mocks/router.mock';
|
||||
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ChangeDetectorRef, NO_ERRORS_SCHEMA, PLATFORM_ID } from '@angular/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
@@ -24,6 +24,7 @@ import { APP_CONFIG } from '../../../config/app-config.interface';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { SortDirection } from '../../core/cache/models/sort-options.model';
|
||||
import { cold } from 'jasmine-marbles';
|
||||
import { Store } from "@ngrx/store";
|
||||
|
||||
describe('BrowseByDatePageComponent', () => {
|
||||
let comp: BrowseByDatePageComponent;
|
||||
@@ -95,7 +96,10 @@ describe('BrowseByDatePageComponent', () => {
|
||||
{ provide: Router, useValue: new RouterMock() },
|
||||
{ provide: PaginationService, useValue: paginationService },
|
||||
{ provide: ChangeDetectorRef, useValue: mockCdRef },
|
||||
{ provide: APP_CONFIG, useValue: environment }
|
||||
{ provide: APP_CONFIG, useValue: environment },
|
||||
{ provide: Store, useValue: {} },
|
||||
{ provide: APP_CONFIG, useValue: environment },
|
||||
{ provide: PLATFORM_ID, useValue: 'browser' },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
@@ -131,4 +135,33 @@ describe('BrowseByDatePageComponent', () => {
|
||||
//expect(comp.startsWithOptions[0]).toEqual(new Date().getUTCFullYear());
|
||||
expect(comp.startsWithOptions[0]).toEqual(1960);
|
||||
});
|
||||
|
||||
describe('when rendered in SSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'server';
|
||||
spyOn((comp as any).browseService, 'getBrowseEntriesFor');
|
||||
});
|
||||
|
||||
it('should not call getBrowseEntriesFor on init', (done) => {
|
||||
comp.ngOnInit();
|
||||
expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled();
|
||||
comp.loading$.subscribe((res) => {
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in CSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'browser';
|
||||
spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry()));
|
||||
});
|
||||
|
||||
it('should call getBrowseEntriesFor on init', fakeAsync(() => {
|
||||
comp.ngOnInit();
|
||||
tick(100);
|
||||
expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, Inject, PLATFORM_ID } from '@angular/core';
|
||||
import {
|
||||
BrowseByMetadataPageComponent,
|
||||
browseParamsToOptions
|
||||
@@ -11,6 +11,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
|
||||
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
|
||||
import { PaginationService } from '../../core/pagination/pagination.service';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||
import { isValidDate } from '../../shared/date.util';
|
||||
@@ -18,6 +19,7 @@ import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { isPlatformServer } from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: 'ds-browse-by-date-page',
|
||||
@@ -44,11 +46,16 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
|
||||
protected cdRef: ChangeDetectorRef,
|
||||
@Inject(APP_CONFIG) public appConfig: AppConfig,
|
||||
public dsoNameService: DSONameService,
|
||||
@Inject(PLATFORM_ID) public platformId: any,
|
||||
) {
|
||||
super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService);
|
||||
super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService, platformId);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.renderOnServerSide && isPlatformServer(this.platformId)) {
|
||||
this.loading$ = observableOf(false);
|
||||
return;
|
||||
}
|
||||
const sortConfig = new SortOptions('default', SortDirection.ASC);
|
||||
this.startsWithType = StartsWithType.date;
|
||||
this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig);
|
||||
|
@@ -3,7 +3,7 @@ import {
|
||||
browseParamsToOptions,
|
||||
getBrowseSearchOptions
|
||||
} from './browse-by-metadata-page.component';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
||||
import { BrowseService } from '../../core/browse/browse.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
@@ -13,7 +13,7 @@ import { EnumKeysPipe } from '../../shared/utils/enum-keys-pipe';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { NO_ERRORS_SCHEMA, PLATFORM_ID } from '@angular/core';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { PageInfo } from '../../core/shared/page-info.model';
|
||||
@@ -111,7 +111,8 @@ describe('BrowseByMetadataPageComponent', () => {
|
||||
{ provide: DSpaceObjectDataService, useValue: mockDsoService },
|
||||
{ provide: PaginationService, useValue: paginationService },
|
||||
{ provide: Router, useValue: new RouterMock() },
|
||||
{ provide: APP_CONFIG, useValue: environmentMock }
|
||||
{ provide: APP_CONFIG, useValue: environmentMock },
|
||||
{ provide: PLATFORM_ID, useValue: 'browser' },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
@@ -224,6 +225,35 @@ describe('BrowseByMetadataPageComponent', () => {
|
||||
expect(result.fetchThumbnail).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in SSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'server';
|
||||
spyOn((comp as any).browseService, 'getBrowseEntriesFor');
|
||||
});
|
||||
|
||||
it('should not call getBrowseEntriesFor on init', (done) => {
|
||||
comp.ngOnInit();
|
||||
expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled();
|
||||
comp.loading$.subscribe((res) => {
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in CSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'browser';
|
||||
spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry()));
|
||||
});
|
||||
|
||||
it('should call getBrowseEntriesFor on init', fakeAsync(() => {
|
||||
comp.ngOnInit();
|
||||
tick(100);
|
||||
expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
export function toRemoteData(objects: any[]): Observable<RemoteData<PaginatedList<any>>> {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { combineLatest as observableCombineLatest, Observable, Subscription, of as observableOf } from 'rxjs';
|
||||
import { Component, Inject, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, Inject, OnInit, OnDestroy, Input, PLATFORM_ID } from '@angular/core';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
@@ -37,7 +37,10 @@ export const BBM_PAGINATION_ID = 'bbm';
|
||||
* 'dc.contributor.*'
|
||||
*/
|
||||
export class BrowseByMetadataPageComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Defines whether to fetch search results during SSR execution
|
||||
*/
|
||||
@Input() renderOnServerSide = false;
|
||||
/**
|
||||
* The list of browse-entries to display
|
||||
*/
|
||||
@@ -134,6 +137,7 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy {
|
||||
protected router: Router,
|
||||
@Inject(APP_CONFIG) public appConfig: AppConfig,
|
||||
public dsoNameService: DSONameService,
|
||||
@Inject(PLATFORM_ID) public platformId: any,
|
||||
) {
|
||||
|
||||
this.fetchThumbnails = this.appConfig.browseBy.showThumbnails;
|
||||
@@ -146,7 +150,10 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy {
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
if (!this.renderOnServerSide && isPlatformServer(this.platformId)) {
|
||||
this.loading$ = observableOf(false);
|
||||
return;
|
||||
}
|
||||
const sortConfig = new SortOptions('default', SortDirection.ASC);
|
||||
this.updatePage(getBrowseSearchOptions(this.defaultBrowseId, this.paginationConfig, sortConfig));
|
||||
this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
|
||||
@@ -22,6 +22,7 @@ import { PaginationService } from '../../core/pagination/pagination.service';
|
||||
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
|
||||
import { APP_CONFIG } from '../../../config/app-config.interface';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { BrowseEntry } from "../../core/shared/browse-entry.model";
|
||||
|
||||
|
||||
describe('BrowseByTitlePageComponent', () => {
|
||||
@@ -97,4 +98,33 @@ describe('BrowseByTitlePageComponent', () => {
|
||||
expect(result.payload.page).toEqual(mockItems);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in SSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'server';
|
||||
spyOn((comp as any).browseService, 'getBrowseEntriesFor');
|
||||
});
|
||||
|
||||
it('should not call getBrowseEntriesFor on init', (done) => {
|
||||
comp.ngOnInit();
|
||||
expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled();
|
||||
comp.loading$.subscribe((res) => {
|
||||
expect(res).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in CSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'browser';
|
||||
spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry()));
|
||||
});
|
||||
|
||||
it('should call getBrowseEntriesFor on init', fakeAsync(() => {
|
||||
comp.ngOnInit();
|
||||
tick(100);
|
||||
expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { SearchComponent } from '../shared/search/search.component';
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Inject, PLATFORM_ID } from '@angular/core';
|
||||
import { pushInOut } from '../shared/animations/push';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
@@ -35,7 +35,8 @@ export class ConfigurationSearchPageComponent extends SearchComponent {
|
||||
protected routeService: RouteService,
|
||||
protected router: Router,
|
||||
@Inject(APP_CONFIG) protected appConfig: AppConfig,
|
||||
@Inject(PLATFORM_ID) public platformId: any,
|
||||
) {
|
||||
super(service, sidebarService, windowService, searchConfigService, routeService, router, appConfig);
|
||||
super(service, sidebarService, windowService, searchConfigService, routeService, router, appConfig, platformId);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA, PLATFORM_ID } from '@angular/core';
|
||||
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
@@ -216,6 +216,7 @@ export function configureSearchComponentTestingModule(compType, additionalDeclar
|
||||
useValue: searchConfigurationServiceStub
|
||||
},
|
||||
{ provide: APP_CONFIG, useValue: environment },
|
||||
{ provide: PLATFORM_ID, useValue: 'browser' },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(compType, {
|
||||
@@ -374,5 +375,34 @@ describe('SearchComponent', () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in SSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'server';
|
||||
});
|
||||
|
||||
it('should not call search method on init', (done) => {
|
||||
comp.ngOnInit();
|
||||
//Check that the first method from which the search depend upon is not being called
|
||||
expect(searchConfigurationServiceStub.getCurrentConfiguration).not.toHaveBeenCalled();
|
||||
comp.initialized$.subscribe((res) => {
|
||||
expect(res).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rendered in CSR', () => {
|
||||
beforeEach(() => {
|
||||
comp.platformId = 'browser';
|
||||
});
|
||||
|
||||
it('should call search method on init', fakeAsync(() => {
|
||||
comp.ngOnInit();
|
||||
tick(100);
|
||||
//Check that the last method from which the search depend upon is being called
|
||||
expect(searchServiceStub.search).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnInit, Output, OnDestroy } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Inject,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
OnDestroy,
|
||||
PLATFORM_ID
|
||||
} from '@angular/core';
|
||||
import { NavigationStart, Router } from '@angular/router';
|
||||
|
||||
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
|
||||
@@ -38,6 +48,7 @@ import { ITEM_MODULE_PATH } from '../../item-page/item-page-routing-paths';
|
||||
import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-routing-paths';
|
||||
import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routing-paths';
|
||||
import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface';
|
||||
import { isPlatformServer } from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search',
|
||||
@@ -176,6 +187,11 @@ export class SearchComponent implements OnDestroy, OnInit {
|
||||
*/
|
||||
@Input() scope: string;
|
||||
|
||||
/**
|
||||
* Defines whether to fetch search results during SSR execution
|
||||
*/
|
||||
@Input() renderOnServerSide = false;
|
||||
|
||||
/**
|
||||
* The current configuration used during the search
|
||||
*/
|
||||
@@ -285,6 +301,7 @@ export class SearchComponent implements OnDestroy, OnInit {
|
||||
protected routeService: RouteService,
|
||||
protected router: Router,
|
||||
@Inject(APP_CONFIG) protected appConfig: AppConfig,
|
||||
@Inject(PLATFORM_ID) public platformId: any,
|
||||
) {
|
||||
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||
}
|
||||
@@ -297,6 +314,11 @@ export class SearchComponent implements OnDestroy, OnInit {
|
||||
* If something changes, update the list of scopes for the dropdown
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
if (!this.renderOnServerSide && isPlatformServer(this.platformId)) {
|
||||
this.initialized$.next(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.useUniquePageId) {
|
||||
// Create an unique pagination id related to the instance of the SearchComponent
|
||||
this.paginationId = uniqueId(this.paginationId);
|
||||
|
Reference in New Issue
Block a user