From c5fd4426cd5e688ff65b38d2e4c177831e8ecc5c Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 21 Nov 2024 16:28:41 +0100 Subject: [PATCH 01/21] [DURACOM-303] prevent possibly long-lasting search and browse calls in SSR --- .../browse-by-date-page.component.spec.ts | 39 +++++++++++++++++-- .../browse-by-date-page.component.ts | 11 +++++- .../browse-by-metadata-page.component.spec.ts | 36 +++++++++++++++-- .../browse-by-metadata-page.component.ts | 13 +++++-- .../browse-by-title-page.component.spec.ts | 32 ++++++++++++++- .../configuration-search-page.component.ts | 5 ++- .../shared/search/search.component.spec.ts | 32 ++++++++++++++- src/app/shared/search/search.component.ts | 24 +++++++++++- 8 files changed, 176 insertions(+), 16 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index b19250edae..ac572c7b86 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -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(); + })); + }); }); diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 7e0b6f0f88..62bba4d86c 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -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); diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts index 2bdecc2670..8eda34cd62 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts @@ -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>> { diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index fe407a2fb0..4629982e65 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -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); diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts index e32c0ac430..9c9586032d 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts @@ -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(); + })); + }); }); diff --git a/src/app/search-page/configuration-search-page.component.ts b/src/app/search-page/configuration-search-page.component.ts index 9196dda025..13e4709ca0 100644 --- a/src/app/search-page/configuration-search-page.component.ts +++ b/src/app/search-page/configuration-search-page.component.ts @@ -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); } } diff --git a/src/app/shared/search/search.component.spec.ts b/src/app/shared/search/search.component.spec.ts index 8ffd832009..05d4fc6b85 100644 --- a/src/app/shared/search/search.component.spec.ts +++ b/src/app/shared/search/search.component.spec.ts @@ -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(); + })); + }); }); }); diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 5a848c9786..6040a47d6e 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -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); From 5868a3198f9d12d817ac845ea1d04c59aa756359 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 16:49:25 +0100 Subject: [PATCH 02/21] [DURACOM-303] fix missing imports --- .../browse-by-date-page.component.spec.ts | 1 + .../browse-by-metadata-page.component.ts | 1 + .../browse-by-title-page.component.ts | 11 +++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index ac572c7b86..d94e7df04f 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -25,6 +25,7 @@ import { environment } from '../../../environments/environment'; import { SortDirection } from '../../core/cache/models/sort-options.model'; import { cold } from 'jasmine-marbles'; import { Store } from "@ngrx/store"; +import { BrowseEntry } from "../../core/shared/browse-entry.model"; describe('BrowseByDatePageComponent', () => { let comp: BrowseByDatePageComponent; diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 4629982e65..e18841f9ca 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -22,6 +22,7 @@ import { Collection } from '../../core/shared/collection.model'; import { Community } from '../../core/shared/community.model'; import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { isPlatformServer } from "@angular/common"; export const BBM_PAGINATION_ID = 'bbm'; diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 11dc2a2a6a..0d8a2e32ed 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -1,5 +1,5 @@ import { combineLatest as observableCombineLatest } from 'rxjs'; -import { Component, Inject } from '@angular/core'; +import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { hasValue } from '../../shared/empty.util'; import { @@ -11,9 +11,11 @@ import { BrowseService } from '../../core/browse/browse.service'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; 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 { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { isPlatformServer } from "@angular/common"; @Component({ selector: 'ds-browse-by-title-page', @@ -32,11 +34,16 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { protected router: Router, @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('dc.title', SortDirection.ASC); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); From 39c5de6e18ff7e4baa78861b760990c775433562 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Tue, 26 Nov 2024 13:11:26 +0100 Subject: [PATCH 03/21] [DURACOM-303] implement skeleton component for search results --- package.json | 1 + .../search-results-skeleton.component.html | 12 +++++++ .../search-results-skeleton.component.scss | 0 .../search-results-skeleton.component.spec.ts | 27 ++++++++++++++ .../search-results-skeleton.component.ts | 36 +++++++++++++++++++ .../search-results.component.html | 7 +++- .../search-results.component.spec.ts | 2 ++ src/themes/custom/lazy-theme.module.ts | 4 +++ 8 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts diff --git a/package.json b/package.json index c2aa6d74dd..86a506c57a 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "ngx-infinite-scroll": "^15.0.0", "ngx-pagination": "6.0.3", "ngx-sortablejs": "^11.1.0", + "ngx-skeleton-loader": "^9.0.0", "ngx-ui-switch": "^14.1.0", "nouislider": "^15.8.1", "pem": "1.14.8", diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html new file mode 100644 index 0000000000..33f05985e1 --- /dev/null +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -0,0 +1,12 @@ +@for (result of loadingResults; track result) { +
+ @if(showThumbnails) { + + } + +
+ + +
+
+} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts new file mode 100644 index 0000000000..0ec74eb946 --- /dev/null +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts @@ -0,0 +1,27 @@ +import { + ComponentFixture, + TestBed, +} from '@angular/core/testing'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + +import { SearchResultsSkeletonComponent } from './search-results-skeleton.component'; + +describe('SearchResultsSkeletonComponent', () => { + let component: SearchResultsSkeletonComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SearchResultsSkeletonComponent, NgxSkeletonLoaderModule], + }) + .compileComponents(); + + fixture = TestBed.createComponent(SearchResultsSkeletonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts new file mode 100644 index 0000000000..d35c5d1733 --- /dev/null +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -0,0 +1,36 @@ +import { + Component, + Input, + OnInit, +} from '@angular/core'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + +import { hasValue } from '../../../empty.util'; + +@Component({ + selector: 'ds-search-results-skeleton', + standalone: true, + imports: [ + NgxSkeletonLoaderModule, + ], + templateUrl: './search-results-skeleton.component.html', + styleUrl: './search-results-skeleton.component.scss', +}) +export class SearchResultsSkeletonComponent implements OnInit { + @Input() + showThumbnails: boolean; + + @Input() + numberOfResults = 0; + + public loadingResults: number[]; + + ngOnInit() { + this.loadingResults = Array.from({ length: this.numberOfResults }, (_, i) => i + 1); + + if (!hasValue(this.showThumbnails)) { + // this is needed as the default value of show thumbnails is true but set in lower levels of the DOM. + this.showThumbnails = true; + } + } +} diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 1f1e58ea10..1ad0129d2d 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -19,7 +19,12 @@ (selectObject)="selectObject.emit($event)"> - + +
diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index 4cc4f84f65..cf4bcf61a5 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -7,6 +7,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { SearchResultsComponent } from './search-results.component'; import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub'; import { createFailedRemoteDataObject } from '../../remote-data.utils'; +import { SearchResultsSkeletonComponent } from "./search-results-skeleton/search-results-skeleton.component"; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; @@ -19,6 +20,7 @@ describe('SearchResultsComponent', () => { imports: [TranslateModule.forRoot(), NoopAnimationsModule], declarations: [ SearchResultsComponent, + SearchResultsSkeletonComponent, QueryParamsDirectiveStub], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index 73400e7880..1fe476c1e1 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -159,6 +159,9 @@ import { RequestCopyModule } from 'src/app/request-copy/request-copy.module'; import {UserMenuComponent} from './app/shared/auth-nav-menu/user-menu/user-menu.component'; import { BrowseByComponent } from './app/shared/browse-by/browse-by.component'; import { RegisterEmailFormComponent } from './app/register-email-form/register-email-form.component'; +import { + SearchResultsSkeletonComponent +} from "../../app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component"; const DECLARATIONS = [ FileSectionComponent, @@ -245,6 +248,7 @@ const DECLARATIONS = [ UserMenuComponent, BrowseByComponent, RegisterEmailFormComponent, + SearchResultsSkeletonComponent, ]; @NgModule({ From 126f3c71f4a2ad5a9f6b52b098ed1317e3c0d935 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Wed, 27 Nov 2024 16:01:41 +0100 Subject: [PATCH 04/21] [DURACOM-303] add skeleton loader for search results and filters --- .../search-filters.component.html | 6 ++++- .../search-filters.component.scss | 10 ++++++- .../search-filters.component.ts | 8 +++++- .../search-results-skeleton.component.html | 18 ++++++++++--- .../search-results-skeleton.component.scss | 27 +++++++++++++++++++ .../search-results-skeleton.component.ts | 3 +++ .../search-results.component.html | 2 +- src/app/shared/search/search.component.ts | 3 +++ src/config/search-page-config.interface.ts | 16 +++++++++++ src/styles/_custom_variables.scss | 11 ++++++++ .../styles/_theme_css_variable_overrides.scss | 1 + 11 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/config/search-page-config.interface.ts diff --git a/src/app/shared/search/search-filters/search-filters.component.html b/src/app/shared/search/search-filters/search-filters.component.html index c006d80c44..97f8c75234 100644 --- a/src/app/shared/search/search-filters/search-filters.component.html +++ b/src/app/shared/search/search-filters/search-filters.component.html @@ -1,7 +1,11 @@

{{"search.filters.head" | translate}}

-
+
+ + + + {{"search.filters.reset" | translate}} diff --git a/src/app/shared/search/search-filters/search-filters.component.scss b/src/app/shared/search/search-filters/search-filters.component.scss index b5b2816e89..a103119daf 100644 --- a/src/app/shared/search/search-filters/search-filters.component.scss +++ b/src/app/shared/search/search-filters/search-filters.component.scss @@ -1,2 +1,10 @@ @import '../../../../styles/variables'; -@import '../../../../styles/mixins'; \ No newline at end of file +@import '../../../../styles/mixins'; + +:host ::ng-deep { + ngx-skeleton-loader .skeleton-loader { + height: var(--ds-filters-skeleton-height); + margin-bottom: var(--ds-filters-skeleton-spacing); + padding: var(--ds-filters-skeleton-spacing); + } +} diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 766939226d..c960dfda56 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -12,6 +12,7 @@ import { SearchFilterService } from '../../../core/shared/search/search-filter.s import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../utils/route.utils'; import { hasValue } from '../../empty.util'; +import { APP_CONFIG, AppConfig } from "../../../../config/app-config.interface"; @Component({ selector: 'ds-search-filters', @@ -61,6 +62,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { searchLink: string; subs = []; + defaultFilterCount: number; /** * Initialize instance variables @@ -68,12 +70,16 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { * @param {SearchFilterService} filterService * @param {Router} router * @param {SearchConfigurationService} searchConfigService + * @param appConfig */ constructor( private searchService: SearchService, private filterService: SearchFilterService, private router: Router, - @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) { + @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, + @Inject(APP_CONFIG) protected appConfig: AppConfig, + ) { + this.defaultFilterCount = this.appConfig.search.defaultFilterCount ?? 5; } ngOnInit(): void { diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 33f05985e1..5972a54dc4 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -1,12 +1,24 @@ +
+
+ +
+
+ @for (result of loadingResults; track result) {
@if(showThumbnails) { - +
+ +
}
- - +
+ +
+
+ +
} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index e69de29bb2..c982d14fb0 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -0,0 +1,27 @@ +:host ::ng-deep { + .info-skeleton, .badge-skeleton, .text-skeleton{ + ngx-skeleton-loader .skeleton-loader { + height: var(--ds-search-skeleton-text-height); + } + } + + .badge-skeleton, .info-skeleton { + ngx-skeleton-loader .skeleton-loader { + width: var(--ds-search-skeleton-badge-width); + } + } + + .info-skeleton { + ngx-skeleton-loader .skeleton-loader { + width: var(--ds-search-skeleton-info-width); + } + } + + .thumbnail-skeleton { + ngx-skeleton-loader .skeleton-loader { + width: var(--ds-search-skeleton-thumbnail-width); + height: var(--ds-search-skeleton-thumbnail-height); + padding: var(--ds-search-skeleton-thumbnail-padding); + } + } +} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index d35c5d1733..fef1529460 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -23,6 +23,9 @@ export class SearchResultsSkeletonComponent implements OnInit { @Input() numberOfResults = 0; + @Input() + textLineCount = 2; + public loadingResults: number[]; ngOnInit() { diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 1ad0129d2d..a190b64752 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -20,7 +20,7 @@
diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 6040a47d6e..362257be0e 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -315,6 +315,9 @@ export class SearchComponent implements OnDestroy, OnInit { */ ngOnInit(): void { if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + this.subs.push(this.getSearchOptions().pipe(distinctUntilChanged()).subscribe((options) => { + this.searchOptions$.next(options); + })); this.initialized$.next(true); return; } diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts new file mode 100644 index 0000000000..7d582866e7 --- /dev/null +++ b/src/config/search-page-config.interface.ts @@ -0,0 +1,16 @@ +import { AdvancedSearchConfig } from './advance-search-config.interface'; +import { Config } from './config.interface'; + +export interface SearchConfig extends Config { + + /** + * List of standard filter to select in adding advanced Search + * Used by {@link UploadBitstreamComponent}. + */ + advancedFilters: AdvancedSearchConfig; + /** + * Number used to render n skeletons while the filters are loading + */ + defaultFilterCount?: number; + +} diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index aa67acac1c..96db246079 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -138,4 +138,15 @@ --green1: #1FB300; // This variable represents the success color for the Klaro cookie banner --button-text-color-cookie: #333; // This variable represents the text color for buttons in the Klaro cookie banner --very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button + + --ds-search-skeleton-text-height: 20px; + --ds-search-skeleton-thumbnail-height: 100px; + --ds-search-skeleton-thumbnail-width: 120px; + --ds-search-skeleton-thumbnail-padding: 1em; + --ds-search-skeleton-text-line-count: 2; + --ds-search-skeleton-badge-width: 75px; + --ds-search-skeleton-info-width: 200px; + + --ds-filters-skeleton-height: 40px; + --ds-filters-skeleton-spacing: 12px; } diff --git a/src/themes/dspace/styles/_theme_css_variable_overrides.scss b/src/themes/dspace/styles/_theme_css_variable_overrides.scss index d016ff4032..5978eadb28 100644 --- a/src/themes/dspace/styles/_theme_css_variable_overrides.scss +++ b/src/themes/dspace/styles/_theme_css_variable_overrides.scss @@ -18,6 +18,7 @@ /* set the next two properties as `--ds-header-navbar-border-bottom-*` in order to keep the bottom border of the header when navbar is expanded */ + --ds-expandable-navbar-border-top-color: #{$white}; --ds-expandable-navbar-border-top-height: 0; --ds-expandable-navbar-padding-top: 0; From 61eb14783e3995fe2beede1801b1027a62032f0b Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:03:47 +0100 Subject: [PATCH 05/21] [DURACOM-303] resolve conflicts --- src/config/app-config.interface.ts | 2 ++ src/config/default-app-config.ts | 5 +++++ src/config/search-page-config.interface.ts | 7 ------- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/config/app-config.interface.ts b/src/config/app-config.interface.ts index a2bf0cb876..8b8dcf74a7 100644 --- a/src/config/app-config.interface.ts +++ b/src/config/app-config.interface.ts @@ -23,6 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; +import { SearchConfig } from "./search-page-config.interface"; interface AppConfig extends Config { ui: UIServerConfig; @@ -50,6 +51,7 @@ interface AppConfig extends Config { vocabularies: FilterVocabularyConfig[]; comcolSelectionSort: DiscoverySortConfig; liveRegion: LiveRegionConfig; + search: SearchConfig } /** diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index a3a490538c..0915f90069 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -23,6 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; +import { SearchConfig } from "./search-page-config.interface"; export class DefaultAppConfig implements AppConfig { production = false; @@ -442,4 +443,8 @@ export class DefaultAppConfig implements AppConfig { messageTimeOutDurationMs: 30000, isVisible: false, }; + + search: SearchConfig = { + defaultFilterCount: 2 + } } diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts index 7d582866e7..cc63607f7f 100644 --- a/src/config/search-page-config.interface.ts +++ b/src/config/search-page-config.interface.ts @@ -1,13 +1,6 @@ -import { AdvancedSearchConfig } from './advance-search-config.interface'; import { Config } from './config.interface'; export interface SearchConfig extends Config { - - /** - * List of standard filter to select in adding advanced Search - * Used by {@link UploadBitstreamComponent}. - */ - advancedFilters: AdvancedSearchConfig; /** * Number used to render n skeletons while the filters are loading */ From d6f0f02c1aaf437126289ac6ed0180ea266ac8ab Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 28 Nov 2024 13:54:48 +0100 Subject: [PATCH 06/21] [DURACOM-303] minor restyle of skeleton for mobile --- .../search-results-skeleton.component.html | 6 +++--- .../search-results-skeleton.component.scss | 5 +++++ .../search/search-results/search-results.component.html | 2 +- src/config/default-app-config.ts | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 5972a54dc4..4bc70d1263 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -1,11 +1,11 @@ -
-
+
+
@for (result of loadingResults; track result) { -
+
@if(showThumbnails) {
diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index c982d14fb0..02711a33b6 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -25,3 +25,8 @@ } } } + +.result-row { + margin-right: 0; + margin-left: 0; +} diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index a190b64752..1ad0129d2d 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -20,7 +20,7 @@
diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 0915f90069..7ed4168217 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -445,6 +445,6 @@ export class DefaultAppConfig implements AppConfig { }; search: SearchConfig = { - defaultFilterCount: 2 + defaultFilterCount: 5 } } From 312a2a7f58decb141822c81fc5e4c86b10331f2f Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 28 Nov 2024 15:01:00 +0100 Subject: [PATCH 07/21] [DURACOM-303] fix lint and tests --- .../search/search-filters/search-filters.component.spec.ts | 4 +++- .../search/search-results/search-results.component.spec.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filters.component.spec.ts b/src/app/shared/search/search-filters/search-filters.component.spec.ts index 522459b603..c8ad89910c 100644 --- a/src/app/shared/search/search-filters/search-filters.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filters.component.spec.ts @@ -9,6 +9,8 @@ import { SearchFiltersComponent } from './search-filters.component'; import { SearchService } from '../../../core/shared/search/search.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; +import { APP_CONFIG } from "../../../../config/app-config.interface"; +import { environment } from "../../../../environments/environment"; describe('SearchFiltersComponent', () => { let comp: SearchFiltersComponent; @@ -37,7 +39,7 @@ describe('SearchFiltersComponent', () => { { provide: SearchService, useValue: searchServiceStub }, { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: SearchFilterService, useValue: searchFiltersStub }, - + { provide: APP_CONFIG, useValue: environment }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(SearchFiltersComponent, { diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index cf4bcf61a5..dc961c97cb 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -65,7 +65,7 @@ describe('SearchResultsComponent', () => { it('should display link with new search where query is quoted if search return a error 400', () => { (comp as any).searchResults = createFailedRemoteDataObject('Error', 400); - (comp as any).searchConfig = { query: 'foobar' }; + (comp as any).searchConfig = { query: 'foobar', pagination: { pageSize: 10 } }; fixture.detectChanges(); const linkDes = fixture.debugElement.queryAll(By.directive(QueryParamsDirectiveStub)); From b482b58d530b946b4e3376acb406e1ee04c68059 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 20 Dec 2024 15:36:06 +0100 Subject: [PATCH 08/21] [DURACOM-303] adapt tests --- .../browse-by-date-page.component.spec.ts | 12 ++++++------ .../browse-by-title-page.component.spec.ts | 17 ++++++++++------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index d94e7df04f..2fe673f821 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -140,12 +140,12 @@ describe('BrowseByDatePageComponent', () => { describe('when rendered in SSR', () => { beforeEach(() => { comp.platformId = 'server'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + spyOn((comp as any).browseService, 'getBrowseItemsFor'); }); - it('should not call getBrowseEntriesFor on init', (done) => { + it('should not call getBrowseItemsFor on init', (done) => { comp.ngOnInit(); - expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).not.toHaveBeenCalled(); comp.loading$.subscribe((res) => { expect(res).toBeFalsy(); done(); @@ -156,13 +156,13 @@ describe('BrowseByDatePageComponent', () => { describe('when rendered in CSR', () => { beforeEach(() => { comp.platformId = 'browser'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + spyOn((comp as any).browseService, 'getBrowseItemsFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); }); - it('should call getBrowseEntriesFor on init', fakeAsync(() => { + it('should call getBrowseItemsFor on init', fakeAsync(() => { comp.ngOnInit(); tick(100); - expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).toHaveBeenCalled(); })); }); }); diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts index 9c9586032d..653ad596c5 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts @@ -64,7 +64,8 @@ describe('BrowseByTitlePageComponent', () => { const activatedRouteStub = Object.assign(new ActivatedRouteStub(), { params: observableOf({}), - data: observableOf({ metadata: 'title' }) + queryParams: observableOf({}), + data: observableOf({ metadata: 'title' }), }); const paginationService = new PaginationServiceStub(); @@ -102,12 +103,13 @@ describe('BrowseByTitlePageComponent', () => { describe('when rendered in SSR', () => { beforeEach(() => { comp.platformId = 'server'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + spyOn((comp as any).browseService, 'getBrowseItemsFor'); + fixture.detectChanges(); }); - it('should not call getBrowseEntriesFor on init', (done) => { + it('should not call getBrowseItemsFor on init', (done) => { comp.ngOnInit(); - expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).not.toHaveBeenCalled(); comp.loading$.subscribe((res) => { expect(res).toBeFalsy(); done(); @@ -118,13 +120,14 @@ describe('BrowseByTitlePageComponent', () => { describe('when rendered in CSR', () => { beforeEach(() => { comp.platformId = 'browser'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + fixture.detectChanges(); + spyOn((comp as any).browseService, 'getBrowseItemsFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); }); - it('should call getBrowseEntriesFor on init', fakeAsync(() => { + it('should call getBrowseItemsFor on init', fakeAsync(() => { comp.ngOnInit(); tick(100); - expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).toHaveBeenCalled(); })); }); }); From 6756a78ba03944a8ee28a582a89480fd2a3fc3e4 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 12:01:50 +0100 Subject: [PATCH 09/21] [DURACOM-303] restyle skeleton, add filter badge skeleton --- .../search-filters/search-filters.component.scss | 2 ++ .../search-results-skeleton.component.scss | 7 +++++++ .../search-results/search-results.component.html | 11 +++++++++++ .../search-results/search-results.component.scss | 10 ++++++++++ .../search/search-results/search-results.component.ts | 9 +++++++++ src/styles/_custom_variables.scss | 6 ++++-- 6 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/app/shared/search/search-results/search-results.component.scss diff --git a/src/app/shared/search/search-filters/search-filters.component.scss b/src/app/shared/search/search-filters/search-filters.component.scss index a103119daf..6170b9281c 100644 --- a/src/app/shared/search/search-filters/search-filters.component.scss +++ b/src/app/shared/search/search-filters/search-filters.component.scss @@ -6,5 +6,7 @@ height: var(--ds-filters-skeleton-height); margin-bottom: var(--ds-filters-skeleton-spacing); padding: var(--ds-filters-skeleton-spacing); + background-color: var(--bs-light); + box-shadow: none; } } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index 02711a33b6..1a111f9dd9 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -22,8 +22,15 @@ width: var(--ds-search-skeleton-thumbnail-width); height: var(--ds-search-skeleton-thumbnail-height); padding: var(--ds-search-skeleton-thumbnail-padding); + margin-right: var(--ds-search-skeleton-thumbnail-margin); + border-radius: 0; } } + + ngx-skeleton-loader .skeleton-loader { + background-color: var(--bs-light); + box-shadow: none; + } } .result-row { diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 1ad0129d2d..d812561ea7 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,3 +1,13 @@ +@if ((filters$ | async).length > 0 && isLoading()) { +
+
+
+ +
+
+
+} +

{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

@@ -19,6 +29,7 @@ (selectObject)="selectObject.emit($event)">
+ ; + /** * The link type of the listed search results */ @@ -104,6 +109,10 @@ export class SearchResultsComponent { @Output() selectObject: EventEmitter = new EventEmitter(); + constructor(private searchConfigService: SearchConfigurationService) { + this.filters$ = this.searchConfigService.getCurrentFilters(); + } + /** * Check if search results are loading */ diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 96db246079..d64f1c6acd 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -140,11 +140,13 @@ --very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button --ds-search-skeleton-text-height: 20px; - --ds-search-skeleton-thumbnail-height: 100px; - --ds-search-skeleton-thumbnail-width: 120px; + --ds-search-skeleton-thumbnail-height: 125px; + --ds-search-skeleton-thumbnail-width: 90px; --ds-search-skeleton-thumbnail-padding: 1em; + --ds-search-skeleton-thumbnail-margin: 1em; --ds-search-skeleton-text-line-count: 2; --ds-search-skeleton-badge-width: 75px; + --ds-search-skeleton-filter-badge-width: 200px; --ds-search-skeleton-info-width: 200px; --ds-filters-skeleton-height: 40px; From 8ee05f43521462b85f041c1c903f5eb7f52d94bd Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:11:13 +0100 Subject: [PATCH 10/21] [DURACOM-303] fix missing url link --- src/app/shared/search/search-results/search-results.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index e4ebf2819b..296d73f9d8 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -22,6 +22,7 @@ export interface SelectionConfig { @Component({ selector: 'ds-search-results', + styleUrls: ['./search-results.component.scss'], templateUrl: './search-results.component.html', animations: [ fadeIn, From 99656f1357438695385820f2c95d4ca5a58993b9 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 12:54:40 +0100 Subject: [PATCH 11/21] [DURACOM-303] add loop for filters count --- .../search/search-results/search-results.component.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index d812561ea7..643cf5eb4b 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,8 +1,12 @@ @if ((filters$ | async).length > 0 && isLoading()) {
-
- +
+ @for (filter of (filters$| async); track filter.key) { +
+ +
+ }
From 9467838066cb48906dcda334919f468fea59efbe Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 18:08:20 +0100 Subject: [PATCH 12/21] [DURACOM-303] add grid layout, make SSR enabling configurable, minor restyle of skeletons --- config/config.example.yml | 12 +++++- .../browse-by-metadata-page.component.ts | 4 +- .../search-filter/search-filter.component.ts | 7 +++- .../search-filters.component.html | 9 +++-- .../search-filters.component.ts | 11 +++++ .../search-results-skeleton.component.html | 40 ++++++++++++------- .../search-results-skeleton.component.scss | 20 ++++++++++ .../search-results-skeleton.component.ts | 17 ++++++++ .../search-results.component.html | 10 ++--- .../search-results.component.scss | 9 ++++- .../search-results.component.ts | 6 ++- src/app/shared/search/search.component.ts | 2 + src/environments/environment.production.ts | 4 +- src/environments/environment.test.ts | 2 + src/environments/environment.ts | 4 +- src/styles/_custom_variables.scss | 2 + 16 files changed, 127 insertions(+), 32 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index c1d7f967a4..0a039a40ad 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -25,6 +25,14 @@ ssr: inlineCriticalCss: false # Path prefixes to enable SSR for. By default these are limited to paths of primary DSpace objects. paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ] + # Whether to enable rendering of Search component on SSR. + # If set to true the component will be included in the HTML returned from the server side rendering. + # If set to false the component will not be included in the HTML returned from the server side rendering. + enableSearchComponent: false, + # Whether to enable rendering of Browse component on SSR. + # If set to true the component will be included in the HTML returned from the server side rendering. + # If set to false the component will not be included in the HTML returned from the server side rendering. + enableBrowseComponent: false, # The REST API server settings # NOTE: these settings define which (publicly available) REST API to use. They are usually @@ -84,7 +92,7 @@ cache: anonymousCache: # Maximum number of pages to cache. Default is zero (0) which means anonymous user cache is disabled. # As all pages are cached in server memory, increasing this value will increase memory needs. - # Individual cached pages are usually small (<100KB), so a value of max=1000 would only require ~100MB of memory. + # Individual cached pages are usually small (<100KB), so a value of max=1000 would only require ~100MB of memory. max: 0 # Amount of time after which cached pages are considered stale (in ms). After becoming stale, the cached # copy is automatically refreshed on the next request. @@ -394,7 +402,7 @@ vocabularies: vocabulary: 'srsc' enabled: true -# Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query. +# Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query. comcolSelectionSort: sortField: 'dc.title' sortDirection: 'ASC' diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index e18841f9ca..7f14f45b2c 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -23,6 +23,7 @@ import { Community } from '../../core/shared/community.model'; import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { isPlatformServer } from "@angular/common"; +import { environment } from "../../../environments/environment"; export const BBM_PAGINATION_ID = 'bbm'; @@ -147,7 +148,8 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); - } + this.renderOnServerSide = environment.ssr.enableBrowseComponent; + } ngOnInit(): void { diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts index 67e8906bb5..6f88d3924a 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; @@ -43,6 +43,8 @@ export class SearchFilterComponent implements OnInit { */ @Input() scope: string; + @Output() isVisibilityComputed = new EventEmitter(); + /** * True when the filter is 100% collapsed in the UI */ @@ -99,6 +101,9 @@ export class SearchFilterComponent implements OnInit { this.filterService.expand(this.filter.name); } }); + this.active$.pipe(take(1)).subscribe(() => { + this.isVisibilityComputed.emit(true); + }) } /** diff --git a/src/app/shared/search/search-filters/search-filters.component.html b/src/app/shared/search/search-filters/search-filters.component.html index 97f8c75234..45875ad7ae 100644 --- a/src/app/shared/search/search-filters/search-filters.component.html +++ b/src/app/shared/search/search-filters/search-filters.component.html @@ -1,11 +1,12 @@

{{"search.filters.head" | translate}}

-
+
- +
- + + - + {{"search.filters.reset" | translate}} diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index c960dfda56..28f351cb6c 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -61,6 +61,11 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { */ searchLink: string; + /** + * Filters for which visibility has been computed + */ + filtersWithComputedVisibility = 0; + subs = []; defaultFilterCount: number; @@ -114,4 +119,10 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { } }); } + + countFiltersWithComputedVisibility(computed: boolean) { + if (computed) { + this.filtersWithComputedVisibility += 1; + } + } } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 4bc70d1263..84a67f4358 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -1,24 +1,36 @@
-
+
-@for (result of loadingResults; track result) { -
- @if(showThumbnails) { -
- +@if((viewMode$ | async) === ViewMode.ListElement) { + @for (result of loadingResults; track result) { +
+ @if(showThumbnails) { +
+ +
+ } +
+
+ +
+
+ +
+
+
+ } +} @else if ((viewMode$ | async) === ViewMode.GridElement) { +
+ @for (result of loadingResults; track result) { +
+
+ +
} -
-
- -
-
- -
-
} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index 1a111f9dd9..e05e4be6d8 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -1,4 +1,6 @@ :host ::ng-deep { + --ds-wrapper-grid-spacing: calc(var(--bs-spacer) / 2); + .info-skeleton, .badge-skeleton, .text-skeleton{ ngx-skeleton-loader .skeleton-loader { height: var(--ds-search-skeleton-text-height); @@ -27,13 +29,31 @@ } } + .card-skeleton { + ngx-skeleton-loader .skeleton-loader { + height: var(--ds-search-skeleton-card-height); + } + } + ngx-skeleton-loader .skeleton-loader { background-color: var(--bs-light); box-shadow: none; } + + .card-columns { + margin-left: calc(-1 * var(--ds-wrapper-grid-spacing)); + margin-right: calc(-1 * var(--ds-wrapper-grid-spacing)); + column-gap: 0; + + .card-column { + padding-left: var(--ds-wrapper-grid-spacing); + padding-right: var(--ds-wrapper-grid-spacing); + } + } } .result-row { margin-right: 0; margin-left: 0; } + diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index fef1529460..d2896460e1 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -1,10 +1,17 @@ +import { + AsyncPipe, + NgForOf, +} from '@angular/common'; import { Component, Input, OnInit, } from '@angular/core'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { Observable } from 'rxjs'; +import { SearchService } from '../../../../core/shared/search/search.service'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; import { hasValue } from '../../../empty.util'; @Component({ @@ -12,6 +19,8 @@ import { hasValue } from '../../../empty.util'; standalone: true, imports: [ NgxSkeletonLoaderModule, + AsyncPipe, + NgForOf, ], templateUrl: './search-results-skeleton.component.html', styleUrl: './search-results-skeleton.component.scss', @@ -26,8 +35,16 @@ export class SearchResultsSkeletonComponent implements OnInit { @Input() textLineCount = 2; + public viewMode$: Observable; + public loadingResults: number[]; + protected readonly ViewMode = ViewMode; + + constructor(private searchService: SearchService) { + this.viewMode$ = searchService.getViewMode(); + } + ngOnInit() { this.loadingResults = Array.from({ length: this.numberOfResults }, (_, i) => i + 1); diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 643cf5eb4b..71839d009b 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,12 +1,10 @@ -@if ((filters$ | async).length > 0 && isLoading()) { +@if ((activeFilters$ | async).length > 0 && (appliedFilters$ | async).length === 0) {
-
- @for (filter of (filters$| async); track filter.key) { -
- +
+
+
- }
diff --git a/src/app/shared/search/search-results/search-results.component.scss b/src/app/shared/search/search-results/search-results.component.scss index 4bf3f8325e..6e369c729b 100644 --- a/src/app/shared/search/search-results/search-results.component.scss +++ b/src/app/shared/search/search-results/search-results.component.scss @@ -4,7 +4,14 @@ background-color: var(--bs-light); box-shadow: none; width: var(--ds-search-skeleton-filter-badge-width); - height: var(--ds-search-skeleton-text-height); + height: var(--ds-search-skeleton-badge-height); + margin-bottom: 0; + margin-right: calc(var(--bs-spacer) / 4); } } + + .filters-badge-skeleton-container { + display: flex; + max-height: var(--ds-search-skeleton-badge-height); + } } diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index 296d73f9d8..1faf8dd778 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -14,6 +14,7 @@ import { PaginatedSearchOptions } from '../models/paginated-search-options.model import { SearchFilter } from "../models/search-filter.model"; import { Observable } from "rxjs"; import { SearchConfigurationService } from "../../../core/shared/search/search-configuration.service"; +import { SearchService } from "../../../core/shared/search/search.service"; export interface SelectionConfig { repeatable: boolean; @@ -110,7 +111,10 @@ export class SearchResultsComponent { @Output() selectObject: EventEmitter = new EventEmitter(); - constructor(private searchConfigService: SearchConfigurationService) { + constructor( + protected searchConfigService: SearchConfigurationService, + protected searchService: SearchService, + ) { this.filters$ = this.searchConfigService.getCurrentFilters(); } diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 362257be0e..1e8811aa86 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -49,6 +49,7 @@ import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-ro 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"; +import { environment } from 'src/environments/environment'; @Component({ selector: 'ds-search', @@ -304,6 +305,7 @@ export class SearchComponent implements OnDestroy, OnInit { @Inject(PLATFORM_ID) public platformId: any, ) { this.isXsOrSm$ = this.windowService.isXsOrSm(); + this.renderOnServerSide = environment.universal.enableSearchComponent; } /** diff --git a/src/environments/environment.production.ts b/src/environments/environment.production.ts index 46a93519df..c3cb74651b 100644 --- a/src/environments/environment.production.ts +++ b/src/environments/environment.production.ts @@ -10,5 +10,7 @@ export const environment: Partial = { time: false, inlineCriticalCss: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], - } + enableSearchComponent: false, + enableBrowseComponent: false, + }, }; diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index e872285f61..ea49f5eb10 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -13,6 +13,8 @@ export const environment: BuildConfig = { time: false, inlineCriticalCss: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], + enableSearchComponent: false, + enableBrowseComponent: false, }, // Angular Universal server settings. diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 25af371e47..419238f264 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -15,7 +15,9 @@ export const environment: Partial = { time: false, inlineCriticalCss: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], - } + enableSearchComponent: false, + enableBrowseComponent: false, + }, }; /* diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index d64f1c6acd..d47f5d2dfa 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -140,6 +140,7 @@ --very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button --ds-search-skeleton-text-height: 20px; + --ds-search-skeleton-badge-height: 18px; --ds-search-skeleton-thumbnail-height: 125px; --ds-search-skeleton-thumbnail-width: 90px; --ds-search-skeleton-thumbnail-padding: 1em; @@ -148,6 +149,7 @@ --ds-search-skeleton-badge-width: 75px; --ds-search-skeleton-filter-badge-width: 200px; --ds-search-skeleton-info-width: 200px; + --ds-search-skeleton-card-height: 435px; --ds-filters-skeleton-height: 40px; --ds-filters-skeleton-spacing: 12px; From 53335658e0874b84841473307d9cd546bd369962 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:29:37 +0100 Subject: [PATCH 13/21] [DURACOM-303] adapt interface for ssr --- .../browse-by-metadata-page.component.ts | 2 +- src/config/universal-config.interface.ts | 9 +++++++++ src/environments/environment.test.ts | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 7f14f45b2c..06a29aad1a 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -148,7 +148,7 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); - this.renderOnServerSide = environment.ssr.enableBrowseComponent; + this.renderOnServerSide = environment.universal.enableBrowseComponent; } diff --git a/src/config/universal-config.interface.ts b/src/config/universal-config.interface.ts index e54168823f..e3f7f399a9 100644 --- a/src/config/universal-config.interface.ts +++ b/src/config/universal-config.interface.ts @@ -18,4 +18,13 @@ export interface UniversalConfig extends Config { * Paths to enable SSR for. Defaults to the home page and paths in the sitemap. */ paths: Array; + /** + * Whether to enable rendering of search component on SSR + */ + enableSearchComponent: boolean; + + /** + * Whether to enable rendering of browse component on SSR + */ + enableBrowseComponent: boolean; } diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index ea49f5eb10..4f832e1ac4 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -323,4 +323,8 @@ export const environment: BuildConfig = { messageTimeOutDurationMs: 30000, isVisible: false, }, + + search: { + defaultFilterCount: 5 + } }; From 2c28f7526366450022d7533e1952463fdc31ce52 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 18:20:58 +0100 Subject: [PATCH 14/21] [DURACOM-303] refactor param, add example of configuration --- config/config.example.yml | 9 +++++++++ .../search/search-filters/search-filters.component.ts | 2 +- src/config/search-page-config.interface.ts | 5 ++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index 0a039a40ad..6674bc5334 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -420,3 +420,12 @@ liveRegion: messageTimeOutDurationMs: 30000 # The visibility of the live region. Setting this to true is only useful for debugging purposes. isVisible: false + + +# Search settings +search: + # Number used to render n UI elements called loading skeletons that act as placeholders. + # These elements indicate that some content will be loaded in their stead. + # Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. + # e.g. If we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. + defaultFiltersCount: 5 diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 28f351cb6c..4667694edd 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -84,7 +84,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, @Inject(APP_CONFIG) protected appConfig: AppConfig, ) { - this.defaultFilterCount = this.appConfig.search.defaultFilterCount ?? 5; + this.defaultFilterCount = this.appConfig.search.defaultFiltersCount ?? 5; } ngOnInit(): void { diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts index cc63607f7f..0f4a145868 100644 --- a/src/config/search-page-config.interface.ts +++ b/src/config/search-page-config.interface.ts @@ -2,7 +2,10 @@ import { Config } from './config.interface'; export interface SearchConfig extends Config { /** - * Number used to render n skeletons while the filters are loading + * Number used to render n UI elements called loading skeletons that act as placeholders. + * These elements indicate that some content will be loaded in their stead. + * Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. + * For instance f we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. */ defaultFilterCount?: number; From 311f648c3f8707fdaa8124a9ddb355e7ff227876 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 13 Jan 2025 10:51:53 +0100 Subject: [PATCH 15/21] [DURACOM-303] rename variable, minor code refactor --- .../shared/search/search-filters/search-filters.component.ts | 2 +- .../search-results-skeleton.component.spec.ts | 5 +++++ .../search-results-skeleton.component.ts | 2 +- src/app/shared/testing/search-configuration-service.stub.ts | 4 ++++ src/config/default-app-config.ts | 2 +- src/config/search-page-config.interface.ts | 4 ++-- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 4667694edd..1f08a5ac5d 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -84,7 +84,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, @Inject(APP_CONFIG) protected appConfig: AppConfig, ) { - this.defaultFilterCount = this.appConfig.search.defaultFiltersCount ?? 5; + this.defaultFilterCount = this.appConfig.search.filterPlaceholdersCount ?? 5; } ngOnInit(): void { diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts index 0ec74eb946..68c8db5a8e 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts @@ -4,6 +4,8 @@ import { } from '@angular/core/testing'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { SearchService } from '../../../../core/shared/search/search.service'; +import { SearchServiceStub } from '../../../testing/search-service.stub'; import { SearchResultsSkeletonComponent } from './search-results-skeleton.component'; describe('SearchResultsSkeletonComponent', () => { @@ -13,6 +15,9 @@ describe('SearchResultsSkeletonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [SearchResultsSkeletonComponent, NgxSkeletonLoaderModule], + providers: [ + { provide: SearchService, useValue: new SearchServiceStub() }, + ], }) .compileComponents(); diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index d2896460e1..28a603cfa3 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -42,7 +42,7 @@ export class SearchResultsSkeletonComponent implements OnInit { protected readonly ViewMode = ViewMode; constructor(private searchService: SearchService) { - this.viewMode$ = searchService.getViewMode(); + this.viewMode$ = this.searchService.getViewMode(); } ngOnInit() { diff --git a/src/app/shared/testing/search-configuration-service.stub.ts b/src/app/shared/testing/search-configuration-service.stub.ts index 78b358f0d4..ef72e40041 100644 --- a/src/app/shared/testing/search-configuration-service.stub.ts +++ b/src/app/shared/testing/search-configuration-service.stub.ts @@ -13,6 +13,10 @@ export class SearchConfigurationServiceStub { return observableOf([]); } + getCurrentFilters() { + return observableOf([]); + } + getCurrentScope(a) { return observableOf('test-id'); } diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 7ed4168217..2384942e3b 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -445,6 +445,6 @@ export class DefaultAppConfig implements AppConfig { }; search: SearchConfig = { - defaultFilterCount: 5 + filterPlaceholdersCount: 5 } } diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts index 0f4a145868..410876cde2 100644 --- a/src/config/search-page-config.interface.ts +++ b/src/config/search-page-config.interface.ts @@ -5,8 +5,8 @@ export interface SearchConfig extends Config { * Number used to render n UI elements called loading skeletons that act as placeholders. * These elements indicate that some content will be loaded in their stead. * Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. - * For instance f we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. + * For instance if we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. */ - defaultFilterCount?: number; + filterPlaceholdersCount?: number; } From 32364e4f68e8153ecb1143bc9d2827a9789d6f16 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 13 Jan 2025 17:31:12 +0100 Subject: [PATCH 16/21] [DURACOM-303] add override possibility with input --- .../browse-by-metadata-page.component.ts | 3 +-- src/app/shared/search/search.component.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 06a29aad1a..5575b153db 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -148,12 +148,11 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); - this.renderOnServerSide = environment.universal.enableBrowseComponent; } ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { this.loading$ = observableOf(false); return; } diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 1e8811aa86..e69a183408 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -305,7 +305,6 @@ export class SearchComponent implements OnDestroy, OnInit { @Inject(PLATFORM_ID) public platformId: any, ) { this.isXsOrSm$ = this.windowService.isXsOrSm(); - this.renderOnServerSide = environment.universal.enableSearchComponent; } /** @@ -316,7 +315,7 @@ 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)) { + if (!this.renderOnServerSide && !environment.universal.enableSearchComponent && isPlatformServer(this.platformId)) { this.subs.push(this.getSearchOptions().pipe(distinctUntilChanged()).subscribe((options) => { this.searchOptions$.next(options); })); From 8a4e8f60451ef83c8f5f9ee95f1c874424408a73 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 20 Jan 2025 13:16:36 +0100 Subject: [PATCH 17/21] [DURACOM-303] fix SSR check on template and on components missing the environment config. Add descriptive comment for skeleton component. Fix JS error on SSR. --- .../browse-by-date-page/browse-by-date-page.component.ts | 3 ++- .../browse-by-metadata-page.component.spec.ts | 6 +++--- .../browse-by-metadata-page.component.ts | 7 ++++++- .../search-results-skeleton.component.ts | 3 +++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 62bba4d86c..86a2f3dfa3 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -20,6 +20,7 @@ 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"; +import { environment } from "../../../environments/environment"; @Component({ selector: 'ds-browse-by-date-page', @@ -52,7 +53,7 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { } ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { this.loading$ = observableOf(false); return; } diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts index 8eda34cd62..4ea68eaa0c 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts @@ -228,8 +228,8 @@ describe('BrowseByMetadataPageComponent', () => { describe('when rendered in SSR', () => { beforeEach(() => { - comp.platformId = 'server'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + comp.ssrRenderingDisabled = true; + spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(null)); }); it('should not call getBrowseEntriesFor on init', (done) => { @@ -244,7 +244,7 @@ describe('BrowseByMetadataPageComponent', () => { describe('when rendered in CSR', () => { beforeEach(() => { - comp.platformId = 'browser'; + comp.ssrRenderingDisabled = false; spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); }); diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 5575b153db..a7357aaaf3 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -131,6 +131,10 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { * Observable determining if the loading animation needs to be shown */ loading$ = observableOf(true); + /** + * Whether this component should be rendered or not in SSR + */ + ssrRenderingDisabled = false; public constructor(protected route: ActivatedRoute, protected browseService: BrowseService, @@ -148,11 +152,12 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); + this.ssrRenderingDisabled = !this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId); } ngOnInit(): void { - if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { + if (this.ssrRenderingDisabled) { this.loading$ = observableOf(false); return; } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index 28a603cfa3..16df026cfd 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -25,6 +25,9 @@ import { hasValue } from '../../../empty.util'; templateUrl: './search-results-skeleton.component.html', styleUrl: './search-results-skeleton.component.scss', }) +/** + * Component to show placeholders for search results while loading, to give a loading feedback to the user without layout shifting. + */ export class SearchResultsSkeletonComponent implements OnInit { @Input() showThumbnails: boolean; From 171a971572cc9c634677376c6063bd0f54487dfe Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:41:38 +0100 Subject: [PATCH 18/21] [DURACOM-303] resolve conflicts --- .../browse-by-metadata-page.component.html | 2 +- .../browse-by-title-page/browse-by-title-page.component.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html index a6abd5a7a4..9628de44b2 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 0d8a2e32ed..74a109574c 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -16,6 +16,7 @@ import { PaginationComponentOptions } from '../../shared/pagination/pagination-c import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { isPlatformServer } from "@angular/common"; +import { environment } from "../../../environments/environment"; @Component({ selector: 'ds-browse-by-title-page', @@ -40,7 +41,7 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { } ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { this.loading$ = observableOf(false); return; } From 483b97d9c187f415f5d3ad7579c4e4b773dbd782 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Tue, 21 Jan 2025 11:01:54 +0100 Subject: [PATCH 19/21] [DURACOM-303] refactor thumbnail's skeleton style --- .../search-results-skeleton.component.html | 12 +++++++----- .../search-results-skeleton.component.scss | 11 ++++------- .../search-results-skeleton.component.ts | 19 +++++++++++++++---- src/styles/_custom_variables.scss | 3 --- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 84a67f4358..a42bda0674 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -5,14 +5,16 @@
@if((viewMode$ | async) === ViewMode.ListElement) { - @for (result of loadingResults; track result) { -
+ @for (result of loadingResults; track result; let first = $first) { +
@if(showThumbnails) { -
- +
+
+ +
} -
+
diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index e05e4be6d8..9345f1ab43 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -20,12 +20,13 @@ } .thumbnail-skeleton { + max-width: var(--ds-thumbnail-max-width); + height: 100%; + ngx-skeleton-loader .skeleton-loader { - width: var(--ds-search-skeleton-thumbnail-width); - height: var(--ds-search-skeleton-thumbnail-height); - padding: var(--ds-search-skeleton-thumbnail-padding); margin-right: var(--ds-search-skeleton-thumbnail-margin); border-radius: 0; + height: 100%; } } @@ -52,8 +53,4 @@ } } -.result-row { - margin-right: 0; - margin-left: 0; -} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index 16df026cfd..3fba70b119 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -29,17 +29,28 @@ import { hasValue } from '../../../empty.util'; * Component to show placeholders for search results while loading, to give a loading feedback to the user without layout shifting. */ export class SearchResultsSkeletonComponent implements OnInit { + /** + * Whether the search result contains thumbnail + */ @Input() showThumbnails: boolean; - + /** + * The number of search result loaded in the current page + */ @Input() numberOfResults = 0; - + /** + * How many placeholder are displayed for the search result text + */ @Input() textLineCount = 2; - + /** + * The view mode of the search page + */ public viewMode$: Observable; - + /** + * Array built from numberOfResults to count and iterate based on index + */ public loadingResults: number[]; protected readonly ViewMode = ViewMode; diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index d47f5d2dfa..3c3244549e 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -141,9 +141,6 @@ --ds-search-skeleton-text-height: 20px; --ds-search-skeleton-badge-height: 18px; - --ds-search-skeleton-thumbnail-height: 125px; - --ds-search-skeleton-thumbnail-width: 90px; - --ds-search-skeleton-thumbnail-padding: 1em; --ds-search-skeleton-thumbnail-margin: 1em; --ds-search-skeleton-text-line-count: 2; --ds-search-skeleton-badge-width: 75px; From 990f00b129c2b7f23e8ac41904d4778b4e07e702 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 18:26:28 +0100 Subject: [PATCH 20/21] [DURACOM-303] adapt solution to older version of angular --- package.json | 2 +- .../browse-by-date-page.component.spec.ts | 4 +-- .../browse-by-date-page.component.ts | 4 +-- .../browse-by-metadata-page.component.ts | 4 +-- .../browse-by-title-page.component.spec.ts | 2 +- .../browse-by-title-page.component.ts | 4 +-- .../search-filter/search-filter.component.ts | 12 ++++---- .../search-filters.component.html | 3 +- .../search-filters.component.spec.ts | 4 +-- .../search-filters.component.ts | 15 ++++++---- .../search-results-skeleton.component.html | 30 +++++++++---------- .../search-results-skeleton.component.ts | 13 +------- .../search-results.component.html | 12 -------- .../search-results.component.spec.ts | 2 +- .../search-results.component.ts | 8 ++--- src/app/shared/search/search.component.ts | 2 +- src/app/shared/search/search.module.ts | 9 +++++- src/config/app-config.interface.ts | 2 +- src/config/default-app-config.ts | 4 +-- src/environments/environment.test.ts | 2 +- src/themes/custom/lazy-theme.module.ts | 7 ++--- yarn.lock | 15 ++++++++++ 22 files changed, 82 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index 86a506c57a..76ae2d5827 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "ngx-infinite-scroll": "^15.0.0", "ngx-pagination": "6.0.3", "ngx-sortablejs": "^11.1.0", - "ngx-skeleton-loader": "^9.0.0", + "ngx-skeleton-loader": "^7.0.0", "ngx-ui-switch": "^14.1.0", "nouislider": "^15.8.1", "pem": "1.14.8", diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index 2fe673f821..f64091e41f 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -24,8 +24,8 @@ 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"; -import { BrowseEntry } from "../../core/shared/browse-entry.model"; +import { Store } from '@ngrx/store'; +import { BrowseEntry } from '../../core/shared/browse-entry.model'; describe('BrowseByDatePageComponent', () => { let comp: BrowseByDatePageComponent; diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 86a2f3dfa3..afb58e6ad2 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -19,8 +19,8 @@ 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"; -import { environment } from "../../../environments/environment"; +import { isPlatformServer } from '@angular/common'; +import { environment } from '../../../environments/environment'; @Component({ selector: 'ds-browse-by-date-page', diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index a7357aaaf3..52cf3b9d7b 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -22,8 +22,8 @@ import { Collection } from '../../core/shared/collection.model'; import { Community } from '../../core/shared/community.model'; import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; -import { isPlatformServer } from "@angular/common"; -import { environment } from "../../../environments/environment"; +import { isPlatformServer } from '@angular/common'; +import { environment } from '../../../environments/environment'; export const BBM_PAGINATION_ID = 'bbm'; diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts index 653ad596c5..1b8eb352a3 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts @@ -22,7 +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"; +import { BrowseEntry } from '../../core/shared/browse-entry.model'; describe('BrowseByTitlePageComponent', () => { diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 74a109574c..518fdf8c15 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -15,8 +15,8 @@ import { of as observableOf } from 'rxjs'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; -import { isPlatformServer } from "@angular/common"; -import { environment } from "../../../environments/environment"; +import { isPlatformServer } from '@angular/common'; +import { environment } from '../../../environments/environment'; @Component({ selector: 'ds-browse-by-title-page', diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts index 6f88d3924a..a440652fe5 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts @@ -93,7 +93,9 @@ export class SearchFilterComponent implements OnInit { */ ngOnInit() { this.selectedValues$ = this.getSelectedValues(); - this.active$ = this.isActive(); + this.active$ = this.isActive().pipe( + startWith(true) + ); this.collapsed$ = this.isCollapsed(); this.initializeFilter(); this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { @@ -101,9 +103,9 @@ export class SearchFilterComponent implements OnInit { this.filterService.expand(this.filter.name); } }); - this.active$.pipe(take(1)).subscribe(() => { + this.isActive().pipe(take(1)).subscribe(() => { this.isVisibilityComputed.emit(true); - }) + }); } /** @@ -192,7 +194,7 @@ export class SearchFilterComponent implements OnInit { } )); } - }), - startWith(true)); + }) + ); } } diff --git a/src/app/shared/search/search-filters/search-filters.component.html b/src/app/shared/search/search-filters/search-filters.component.html index 45875ad7ae..e1e54c683d 100644 --- a/src/app/shared/search/search-filters/search-filters.component.html +++ b/src/app/shared/search/search-filters/search-filters.component.html @@ -1,6 +1,7 @@

{{"search.filters.head" | translate}}

-
+
diff --git a/src/app/shared/search/search-filters/search-filters.component.spec.ts b/src/app/shared/search/search-filters/search-filters.component.spec.ts index c8ad89910c..864d7b583e 100644 --- a/src/app/shared/search/search-filters/search-filters.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filters.component.spec.ts @@ -9,8 +9,8 @@ import { SearchFiltersComponent } from './search-filters.component'; import { SearchService } from '../../../core/shared/search/search.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; -import { APP_CONFIG } from "../../../../config/app-config.interface"; -import { environment } from "../../../../environments/environment"; +import { APP_CONFIG } from '../../../../config/app-config.interface'; +import { environment } from '../../../../environments/environment'; describe('SearchFiltersComponent', () => { let comp: SearchFiltersComponent; diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 1f08a5ac5d..b491f21177 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { BehaviorSubject, Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { map, tap } from 'rxjs/operators'; import { SearchService } from '../../../core/shared/search/search.service'; import { RemoteData } from '../../../core/data/remote-data'; @@ -12,7 +12,7 @@ import { SearchFilterService } from '../../../core/shared/search/search-filter.s import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../utils/route.utils'; import { hasValue } from '../../empty.util'; -import { APP_CONFIG, AppConfig } from "../../../../config/app-config.interface"; +import { APP_CONFIG, AppConfig } from '../../../../config/app-config.interface'; @Component({ selector: 'ds-search-filters', @@ -88,10 +88,13 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => { - Object.keys(filters).forEach((f) => filters[f] = null); - return filters; - })); + this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe( + tap(() => this.filtersWithComputedVisibility = 0), + map((filters) => { + Object.keys(filters).forEach((f) => filters[f] = null); + return filters; + }) + ); this.searchLink = this.getSearchLink(); } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index a42bda0674..bd98040257 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -4,16 +4,14 @@
-@if((viewMode$ | async) === ViewMode.ListElement) { - @for (result of loadingResults; track result; let first = $first) { -
- @if(showThumbnails) { -
-
- -
+ + +
+
+
+
- } +
@@ -23,16 +21,18 @@
- } -} @else if ((viewMode$ | async) === ViewMode.GridElement) { +
+
+ +
- @for (result of loadingResults; track result) { +
- } - +
-} +
+ diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index 3fba70b119..179b26f1fd 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -1,13 +1,8 @@ -import { - AsyncPipe, - NgForOf, -} from '@angular/common'; import { Component, Input, OnInit, } from '@angular/core'; -import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Observable } from 'rxjs'; import { SearchService } from '../../../../core/shared/search/search.service'; @@ -16,14 +11,8 @@ import { hasValue } from '../../../empty.util'; @Component({ selector: 'ds-search-results-skeleton', - standalone: true, - imports: [ - NgxSkeletonLoaderModule, - AsyncPipe, - NgForOf, - ], templateUrl: './search-results-skeleton.component.html', - styleUrl: './search-results-skeleton.component.scss', + styleUrls: ['./search-results-skeleton.component.scss'], }) /** * Component to show placeholders for search results while loading, to give a loading feedback to the user without layout shifting. diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 71839d009b..a2bc91195c 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,15 +1,3 @@ -@if ((activeFilters$ | async).length > 0 && (appliedFilters$ | async).length === 0) { -
-
-
-
- -
-
-
-
-} -

{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index dc961c97cb..c2b181038a 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -7,7 +7,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { SearchResultsComponent } from './search-results.component'; import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub'; import { createFailedRemoteDataObject } from '../../remote-data.utils'; -import { SearchResultsSkeletonComponent } from "./search-results-skeleton/search-results-skeleton.component"; +import { SearchResultsSkeletonComponent } from './search-results-skeleton/search-results-skeleton.component'; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index 1faf8dd778..9050ce9cd0 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -11,10 +11,10 @@ import { CollectionElementLinkType } from '../../object-collection/collection-el import { ViewMode } from '../../../core/shared/view-mode.model'; import { Context } from '../../../core/shared/context.model'; import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; -import { SearchFilter } from "../models/search-filter.model"; -import { Observable } from "rxjs"; -import { SearchConfigurationService } from "../../../core/shared/search/search-configuration.service"; -import { SearchService } from "../../../core/shared/search/search.service"; +import { SearchFilter } from '../models/search-filter.model'; +import { Observable } from 'rxjs'; +import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; +import { SearchService } from '../../../core/shared/search/search.service'; export interface SelectionConfig { repeatable: boolean; diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index e69a183408..527d2d2719 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -48,7 +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"; +import { isPlatformServer } from '@angular/common'; import { environment } from 'src/environments/environment'; @Component({ diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts index 69500999a8..e2075a5f56 100644 --- a/src/app/shared/search/search.module.ts +++ b/src/app/shared/search/search.module.ts @@ -34,6 +34,10 @@ import { ThemedSearchSettingsComponent } from './search-settings/themed-search-s import { NouisliderModule } from 'ng2-nouislider'; import { ThemedSearchFiltersComponent } from './search-filters/themed-search-filters.component'; import { ThemedSearchSidebarComponent } from './search-sidebar/themed-search-sidebar.component'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { + SearchResultsSkeletonComponent +} from './search-results/search-results-skeleton/search-results-skeleton.component'; const COMPONENTS = [ SearchComponent, @@ -62,6 +66,7 @@ const COMPONENTS = [ ThemedSearchSettingsComponent, ThemedSearchFiltersComponent, ThemedSearchSidebarComponent, + SearchResultsSkeletonComponent ]; const ENTRY_COMPONENTS = [ @@ -74,6 +79,7 @@ const ENTRY_COMPONENTS = [ SearchFacetSelectedOptionComponent, SearchFacetRangeOptionComponent, SearchAuthorityFilterComponent, + SearchResultsSkeletonComponent ]; /** @@ -93,11 +99,12 @@ export const MODELS = [ imports: [ CommonModule, TranslateModule.forChild({ - missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MissingTranslationHelper }, + missingTranslationHandler: {provide: MissingTranslationHandler, useClass: MissingTranslationHelper}, useDefaultLang: true }), SharedModule.withEntryComponents(), NouisliderModule, + NgxSkeletonLoaderModule, ], exports: [ ...COMPONENTS diff --git a/src/config/app-config.interface.ts b/src/config/app-config.interface.ts index 8b8dcf74a7..af78d4ab88 100644 --- a/src/config/app-config.interface.ts +++ b/src/config/app-config.interface.ts @@ -23,7 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; -import { SearchConfig } from "./search-page-config.interface"; +import { SearchConfig } from './search-page-config.interface'; interface AppConfig extends Config { ui: UIServerConfig; diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 2384942e3b..de4f3bd56e 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -23,7 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; -import { SearchConfig } from "./search-page-config.interface"; +import { SearchConfig } from './search-page-config.interface'; export class DefaultAppConfig implements AppConfig { production = false; @@ -446,5 +446,5 @@ export class DefaultAppConfig implements AppConfig { search: SearchConfig = { filterPlaceholdersCount: 5 - } + }; } diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index 4f832e1ac4..e6ffe85df6 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -325,6 +325,6 @@ export const environment: BuildConfig = { }, search: { - defaultFilterCount: 5 + filterPlaceholdersCount: 5 } }; diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index 1fe476c1e1..546d2dccbf 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -159,9 +159,8 @@ import { RequestCopyModule } from 'src/app/request-copy/request-copy.module'; import {UserMenuComponent} from './app/shared/auth-nav-menu/user-menu/user-menu.component'; import { BrowseByComponent } from './app/shared/browse-by/browse-by.component'; import { RegisterEmailFormComponent } from './app/register-email-form/register-email-form.component'; -import { - SearchResultsSkeletonComponent -} from "../../app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component"; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + const DECLARATIONS = [ FileSectionComponent, @@ -248,7 +247,6 @@ const DECLARATIONS = [ UserMenuComponent, BrowseByComponent, RegisterEmailFormComponent, - SearchResultsSkeletonComponent, ]; @NgModule({ @@ -309,6 +307,7 @@ const DECLARATIONS = [ NgxGalleryModule, FormModule, RequestCopyModule, + NgxSkeletonLoaderModule ], declarations: DECLARATIONS, exports: [ diff --git a/yarn.lock b/yarn.lock index 7760902b72..39661b8d43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8415,6 +8415,14 @@ ngx-pagination@6.0.3: dependencies: tslib "^2.3.0" +ngx-skeleton-loader@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ngx-skeleton-loader/-/ngx-skeleton-loader-7.0.0.tgz#3b1325025a7208a20f3a0fdba6e578532a09cfcd" + integrity sha512-myc6GNcNhyksZrimIFkCxeihi0kQ8JhQVZiGbtiIv4gYrnnRk5nXbs3kYitK8E8OstHG+jlsmRofqGBxuIsYTA== + dependencies: + perf-marks "^1.13.4" + tslib "^2.0.0" + ngx-sortablejs@^11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/ngx-sortablejs/-/ngx-sortablejs-11.1.0.tgz" @@ -9060,6 +9068,13 @@ pend@~1.2.0: resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== +perf-marks@^1.13.4: + version "1.14.2" + resolved "https://registry.yarnpkg.com/perf-marks/-/perf-marks-1.14.2.tgz#7511c24239b9c2071717993a33ec3057f387b8c7" + integrity sha512-N0/bQcuTlETpgox/DsXS1voGjqaoamMoiyhncgeW3rSHy/qw8URVgmPRYfFDQns/+C6yFUHDbeSBGL7ixT6Y4A== + dependencies: + tslib "^2.1.0" + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" From 8a4f24fc31bd1fad18f63cb71a0f377a51f63d87 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 27 Jan 2025 09:34:42 +0100 Subject: [PATCH 21/21] [DURACOM-303] adapt tests dependencies and template variable --- .../search-results-skeleton.component.html | 2 +- .../search-results-skeleton.component.spec.ts | 3 ++- .../search-results/search-results.component.spec.ts | 11 ++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index bd98040257..c318eea2e1 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -5,7 +5,7 @@
- +
diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts index 68c8db5a8e..86277181fe 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts @@ -14,7 +14,8 @@ describe('SearchResultsSkeletonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [SearchResultsSkeletonComponent, NgxSkeletonLoaderModule], + imports: [NgxSkeletonLoaderModule], + declarations: [SearchResultsSkeletonComponent], providers: [ { provide: SearchService, useValue: new SearchServiceStub() }, ], diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index c2b181038a..1ef596a4ed 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -8,6 +8,10 @@ import { SearchResultsComponent } from './search-results.component'; import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub'; import { createFailedRemoteDataObject } from '../../remote-data.utils'; import { SearchResultsSkeletonComponent } from './search-results-skeleton/search-results-skeleton.component'; +import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; +import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; +import { SearchService } from '../../../core/shared/search/search.service'; +import { SearchServiceStub } from '../../testing/search-service.stub'; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; @@ -21,7 +25,12 @@ describe('SearchResultsComponent', () => { declarations: [ SearchResultsComponent, SearchResultsSkeletonComponent, - QueryParamsDirectiveStub], + QueryParamsDirectiveStub + ], + providers: [ + { provide: SearchConfigurationService, useValue: new SearchConfigurationServiceStub() }, + { provide: SearchService, useValue: new SearchServiceStub() }, + ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); }));