From 22e87a5f5a875b41e38c1ef834b9c7a9b8cea458 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 2 Feb 2024 17:40:32 +0100 Subject: [PATCH 1/2] 111639: Added scope @Input() and made the search facets & search results use that scope --- .../shared/search/search-filter.service.ts | 1 + .../search-facet-filter-wrapper.component.ts | 9 ++++- .../search-facet-filter.component.spec.ts | 2 ++ .../search-facet-filter.component.ts | 12 +++++-- .../search-filter.component.html | 1 + .../search-filter/search-filter.component.ts | 10 +++++- .../search-hierarchy-filter.component.spec.ts | 4 ++- .../search-hierarchy-filter.component.ts | 6 ++-- .../search-range-filter.component.spec.ts | 2 ++ .../search-range-filter.component.ts | 4 ++- .../search-filters.component.html | 2 +- .../shared/search/search.component.spec.ts | 26 ++------------ src/app/shared/search/search.component.ts | 31 +++++++++++------ .../shared/search/themed-search.component.ts | 34 +++++++++++++++++-- 14 files changed, 97 insertions(+), 47 deletions(-) diff --git a/src/app/core/shared/search/search-filter.service.ts b/src/app/core/shared/search/search-filter.service.ts index 80ba200d383..bf232cb141b 100644 --- a/src/app/core/shared/search/search-filter.service.ts +++ b/src/app/core/shared/search/search-filter.service.ts @@ -27,6 +27,7 @@ const filterStateSelector = (state: SearchFiltersState) => state.searchFilter; export const FILTER_CONFIG: InjectionToken = new InjectionToken('filterConfig'); export const IN_PLACE_SEARCH: InjectionToken = new InjectionToken('inPlaceSearch'); export const REFRESH_FILTER: InjectionToken> = new InjectionToken('refreshFilters'); +export const SCOPE: InjectionToken = new InjectionToken('scope'); /** * Service that performs all actions that have to do with search filters and facets diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts index 0aa131d4282..f635c027b5c 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -4,6 +4,7 @@ import { FilterType } from '../../../models/filter-type.model'; import { SearchFilterConfig } from '../../../models/search-filter-config.model'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, REFRESH_FILTER } from '../../../../../core/shared/search/search-filter.service'; @@ -35,6 +36,11 @@ export class SearchFacetFilterWrapperComponent implements OnInit { */ @Input() refreshFilters: BehaviorSubject; + /** + * The current scope + */ + @Input() scope: string; + /** * The constructor of the search facet filter that should be rendered, based on the filter config's type */ @@ -56,7 +62,8 @@ export class SearchFacetFilterWrapperComponent implements OnInit { providers: [ { provide: FILTER_CONFIG, useFactory: () => (this.filterConfig), deps: [] }, { provide: IN_PLACE_SEARCH, useFactory: () => (this.inPlaceSearch), deps: [] }, - { provide: REFRESH_FILTER, useFactory: () => (this.refreshFilters), deps: [] } + { provide: REFRESH_FILTER, useFactory: () => (this.refreshFilters), deps: [] }, + { provide: SCOPE, useFactory: () => (this.scope), deps: [] }, ], parent: this.injector }); diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index 92d2e5265ba..fc348722e55 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -4,6 +4,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, REFRESH_FILTER, SearchFilterService @@ -99,6 +100,7 @@ describe('SearchFacetFilterComponent', () => { { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: IN_PLACE_SEARCH, useValue: false }, { provide: REFRESH_FILTER, useValue: new BehaviorSubject(false) }, + { provide: SCOPE, useValue: undefined }, { provide: SearchFilterService, useValue: { getSelectedValuesForFilter: () => observableOf(selectedValues), diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index 2b2eb9b11a7..994b488d9c7 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -22,6 +22,7 @@ import { SearchFilterConfig } from '../../../models/search-filter-config.model'; import { SearchService } from '../../../../../core/shared/search/search.service'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, REFRESH_FILTER, SearchFilterService @@ -104,7 +105,9 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService, @Inject(IN_PLACE_SEARCH) public inPlaceSearch: boolean, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, - @Inject(REFRESH_FILTER) public refreshFilters: BehaviorSubject) { + @Inject(REFRESH_FILTER) public refreshFilters: BehaviorSubject, + @Inject(SCOPE) public scope: string, + ) { } /** @@ -114,8 +117,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { this.currentUrl = this.router.url; this.filterValues$ = new BehaviorSubject(createPendingRemoteDataObject()); this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged()); - - this.searchOptions$ = this.searchConfigService.searchOptions; + this.searchOptions$ = this.searchConfigService.searchOptions.pipe( + map((options: SearchOptions) => hasNoValue(this.scope) ? options : Object.assign({}, options, { + scope: this.scope, + })), + ); this.subs.push( this.searchOptions$.subscribe(() => this.updateFilterValueList()), this.refreshFilters.asObservable().pipe( diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-filter.component.html index a6fb0021b7f..0eb826130d4 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.html @@ -18,6 +18,7 @@
(@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{ 'closed' : closed, 'notab': notab }"> 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 d1d3bd729d4..67e8906bb5d 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 @@ -6,7 +6,7 @@ import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; import { SearchFilterConfig } from '../../models/search-filter-config.model'; import { SearchFilterService } from '../../../../core/shared/search/search-filter.service'; import { slide } from '../../../animations/slide'; -import { isNotEmpty } from '../../../empty.util'; +import { isNotEmpty, hasValue } from '../../../empty.util'; import { SearchService } from '../../../../core/shared/search/search.service'; import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component'; @@ -38,6 +38,11 @@ export class SearchFilterComponent implements OnInit { */ @Input() refreshFilters: BehaviorSubject; + /** + * The current scope + */ + @Input() scope: string; + /** * True when the filter is 100% collapsed in the UI */ @@ -171,6 +176,9 @@ export class SearchFilterComponent implements OnInit { } else { return this.searchConfigService.searchOptions.pipe( switchMap((options) => { + if (hasValue(this.scope)) { + options.scope = this.scope; + } return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe( filter((RD) => !RD.isLoading), map((valuesRD) => { diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts index e6c74d80478..4469a124ce6 100644 --- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts @@ -14,6 +14,7 @@ import { CommonModule } from '@angular/common'; import { SearchService } from '../../../../../core/shared/search/search.service'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, SearchFilterService, REFRESH_FILTER @@ -75,7 +76,8 @@ describe('SearchHierarchyFilterComponent', () => { { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: IN_PLACE_SEARCH, useValue: false }, { provide: FILTER_CONFIG, useValue: Object.assign(new SearchFilterConfig(), { name: testSearchFilter }) }, - { provide: REFRESH_FILTER, useValue: new BehaviorSubject(false)} + { provide: REFRESH_FILTER, useValue: new BehaviorSubject(false)}, + { provide: SCOPE, useValue: undefined }, ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts index f9b3f2bff94..d53fa37cf4b 100644 --- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts @@ -9,6 +9,7 @@ import { import { SearchService } from '../../../../../core/shared/search/search.service'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, SearchFilterService, REFRESH_FILTER } from '../../../../../core/shared/search/search-filter.service'; @@ -49,9 +50,10 @@ export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent i @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService, @Inject(IN_PLACE_SEARCH) public inPlaceSearch: boolean, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, - @Inject(REFRESH_FILTER) public refreshFilters: BehaviorSubject + @Inject(REFRESH_FILTER) public refreshFilters: BehaviorSubject, + @Inject(SCOPE) public scope: string, ) { - super(searchService, filterService, rdbs, router, searchConfigService, inPlaceSearch, filterConfig, refreshFilters); + super(searchService, filterService, rdbs, router, searchConfigService, inPlaceSearch, filterConfig, refreshFilters, scope); } vocabularyExists$: Observable; diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts index 3a146f50590..03f47a75698 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts @@ -4,6 +4,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, REFRESH_FILTER, SearchFilterService @@ -105,6 +106,7 @@ describe('SearchRangeFilterComponent', () => { { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: IN_PLACE_SEARCH, useValue: false }, { provide: REFRESH_FILTER, useValue: new BehaviorSubject(false) }, + { provide: SCOPE, useValue: undefined }, { provide: SearchFilterService, useValue: { getSelectedValuesForFilter: () => selectedValues, diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 938f67412e4..cdbf384fe98 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -9,6 +9,7 @@ import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/se import { SearchFilterConfig } from '../../../models/search-filter-config.model'; import { FILTER_CONFIG, + SCOPE, IN_PLACE_SEARCH, REFRESH_FILTER, SearchFilterService @@ -83,8 +84,9 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, @Inject(PLATFORM_ID) private platformId: any, @Inject(REFRESH_FILTER) public refreshFilters: BehaviorSubject, + @Inject(SCOPE) public scope: string, private route: RouteService) { - super(searchService, filterService, rdbs, router, searchConfigService, inPlaceSearch, filterConfig, refreshFilters); + super(searchService, filterService, rdbs, router, searchConfigService, inPlaceSearch, filterConfig, refreshFilters, scope); } 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 e392cd2663e..c006d80c44f 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,7 @@

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

- +
{{"search.filters.reset" | translate}} diff --git a/src/app/shared/search/search.component.spec.ts b/src/app/shared/search/search.component.spec.ts index d0d9bdda86a..9d069636a94 100644 --- a/src/app/shared/search/search.component.spec.ts +++ b/src/app/shared/search/search.component.spec.ts @@ -36,8 +36,6 @@ import { getCollectionPageRoute } from '../../collection-page/collection-page-ro let comp: SearchComponent; let fixture: ComponentFixture; -let searchServiceObject: SearchService; -let searchConfigurationServiceObject: SearchConfigurationService; const store: Store = jasmine.createSpyObj('store', { /* eslint-disable no-empty,@typescript-eslint/no-empty-function */ dispatch: {}, @@ -93,7 +91,6 @@ const mockDso2 = Object.assign(new Item(), { } } }); -const sort: SortOptions = new SortOptions('score', SortDirection.DESC); const mockSearchResults: SearchObjects = Object.assign(new SearchObjects(), { page: [mockDso, mockDso2] }); @@ -106,23 +103,13 @@ const searchServiceStub = jasmine.createSpyObj('SearchService', { getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig), trackSearch: {}, }) as SearchService; -const configurationParam = 'default'; const queryParam = 'test query'; const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; -const fixedFilter = 'fixed filter'; const defaultSearchOptions = new PaginatedSearchOptions({ pagination }); const paginatedSearchOptions$ = new BehaviorSubject(defaultSearchOptions); -const paginatedSearchOptions = new PaginatedSearchOptions({ - configuration: configurationParam, - query: queryParam, - scope: scopeParam, - fixedFilter: fixedFilter, - pagination, - sort -}); const activatedRouteStub = { snapshot: { queryParamMap: new Map([ @@ -155,14 +142,11 @@ const filtersConfigRD = createSuccessfulRemoteDataObject([mockFilterConfig, mock const filtersConfigRD$ = observableOf(filtersConfigRD); const routeServiceStub = { - getRouteParameterValue: () => { - return observableOf(''); - }, getQueryParameterValue: () => { - return observableOf(''); + return observableOf(null); }, getQueryParamsWithPrefix: () => { - return observableOf(''); + return observableOf(null); }, setParameter: () => { return; @@ -252,16 +236,10 @@ describe('SearchComponent', () => { comp.paginationId = paginationId; spyOn((comp as any), 'getSearchOptions').and.returnValue(paginatedSearchOptions$.asObservable()); - - searchServiceObject = TestBed.inject(SearchService); - searchConfigurationServiceObject = TestBed.inject(SEARCH_CONFIG_SERVICE); - }); afterEach(() => { comp = null; - searchServiceObject = null; - searchConfigurationServiceObject = null; }); it('should init search parameters properly and call retrieveSearchResults', fakeAsync(() => { diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 61f3a119c87..8e120940ecc 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnInit, Output, OnDestroy } from '@angular/core'; import { NavigationStart, Router } from '@angular/router'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; @@ -11,7 +11,7 @@ import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { pushInOut } from '../animations/push'; import { HostWindowService } from '../host-window.service'; import { SidebarService } from '../sidebar/sidebar.service'; -import { hasValue, hasValueOperator, isNotEmpty } from '../empty.util'; +import { hasValue, hasValueOperator, isEmpty, isNotEmpty } from '../empty.util'; import { RouteService } from '../../core/services/route.service'; import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; import { PaginatedSearchOptions } from './models/paginated-search-options.model'; @@ -34,7 +34,7 @@ import { CollectionElementLinkType } from '../object-collection/collection-eleme import { environment } from 'src/environments/environment'; import { SubmissionObject } from '../../core/submission/models/submission-object.model'; import { SearchFilterConfig } from './models/search-filter-config.model'; -import { WorkspaceItem } from '../..//core/submission/models/workspaceitem.model'; +import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model'; 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'; @@ -50,7 +50,7 @@ import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routi /** * This component renders a sidebar, a search input bar and the search results. */ -export class SearchComponent implements OnInit { +export class SearchComponent implements OnDestroy, OnInit { /** * The list of available configuration options @@ -166,6 +166,11 @@ export class SearchComponent implements OnInit { */ @Input() query: string; + /** + * The fallback scope when no scope is defined in the url, if this is also undefined no scope will be set + */ + @Input() scope: string; + /** * The current configuration used during the search */ @@ -179,7 +184,7 @@ export class SearchComponent implements OnInit { /** * The current sort options used */ - currentScope$: BehaviorSubject = new BehaviorSubject(''); + currentScope$: Observable; /** * The current sort options used @@ -299,6 +304,10 @@ export class SearchComponent implements OnInit { this.routeService.setParameter('fixedFilterQuery', this.fixedFilterQuery); } + this.currentScope$ = this.routeService.getQueryParameterValue('scope').pipe( + map((routeValue: string) => hasValue(routeValue) ? routeValue : this.scope), + ); + this.isSidebarCollapsed$ = this.isSidebarCollapsed(); this.searchLink = this.getSearchLink(); this.currentContext$.next(this.context); @@ -321,13 +330,13 @@ export class SearchComponent implements OnInit { ); const searchOptions$: Observable = this.getSearchOptions().pipe(distinctUntilChanged()); - this.subs.push(combineLatest([configuration$, searchSortOptions$, searchOptions$, sortOption$]).pipe( - filter(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => { + this.subs.push(combineLatest([configuration$, searchSortOptions$, searchOptions$, sortOption$, this.currentScope$]).pipe( + filter(([configuration, searchSortOptions, searchOptions, sortOption, scope]: [string, SortOptions[], PaginatedSearchOptions, SortOptions, string]) => { // filter for search options related to instanced paginated id return searchOptions.pagination.id === this.paginationId; }), debounceTime(100) - ).subscribe(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => { + ).subscribe(([configuration, searchSortOptions, searchOptions, sortOption, scope]: [string, SortOptions[], PaginatedSearchOptions, SortOptions, string]) => { // Build the PaginatedSearchOptions object const combinedOptions = Object.assign({}, searchOptions, { @@ -337,6 +346,9 @@ export class SearchComponent implements OnInit { if (combinedOptions.query === '') { combinedOptions.query = this.query; } + if (isEmpty(combinedOptions.scope)) { + combinedOptions.scope = scope; + } const newSearchOptions = new PaginatedSearchOptions(combinedOptions); // check if search options are changed // if so retrieve new related results otherwise skip it @@ -344,13 +356,12 @@ export class SearchComponent implements OnInit { // Initialize variables this.currentConfiguration$.next(configuration); this.currentSortOptions$.next(newSearchOptions.sort); - this.currentScope$.next(newSearchOptions.scope); this.sortOptionsList$.next(searchSortOptions); this.searchOptions$.next(newSearchOptions); this.initialized$.next(true); // retrieve results this.retrieveSearchResults(newSearchOptions); - this.retrieveFilters(searchOptions); + this.retrieveFilters(newSearchOptions); } })); diff --git a/src/app/shared/search/themed-search.component.ts b/src/app/shared/search/themed-search.component.ts index fe531e4f0f5..38df90dd8a7 100644 --- a/src/app/shared/search/themed-search.component.ts +++ b/src/app/shared/search/themed-search.component.ts @@ -15,11 +15,37 @@ import { ListableObject } from '../object-collection/shared/listable-object.mode */ @Component({ selector: 'ds-themed-search', - styleUrls: [], templateUrl: '../theme-support/themed.component.html', }) export class ThemedSearchComponent extends ThemedComponent { - protected inAndOutputNames: (keyof SearchComponent & keyof this)[] = ['configurationList', 'context', 'configuration', 'fixedFilterQuery', 'useCachedVersionIfAvailable', 'inPlaceSearch', 'linkType', 'paginationId', 'searchEnabled', 'sideBarWidth', 'searchFormPlaceholder', 'selectable', 'selectionConfig', 'showCsvExport', 'showSidebar', 'showThumbnails', 'showViewModes', 'useUniquePageId', 'viewModeList', 'showScopeSelector', 'resultFound', 'deselectObject', 'selectObject', 'trackStatistics', 'query']; + protected inAndOutputNames: (keyof SearchComponent & keyof this)[] = [ + 'configurationList', + 'context', + 'configuration', + 'fixedFilterQuery', + 'useCachedVersionIfAvailable', + 'inPlaceSearch', + 'linkType', + 'paginationId', + 'searchEnabled', + 'sideBarWidth', + 'searchFormPlaceholder', + 'selectable', + 'selectionConfig', + 'showCsvExport', + 'showSidebar', + 'showThumbnails', + 'showViewModes', + 'useUniquePageId', + 'viewModeList', + 'showScopeSelector', + 'trackStatistics', + 'query', + 'scope', + 'resultFound', + 'deselectObject', + 'selectObject', + ]; @Input() configurationList: SearchConfigurationOption[]; @@ -51,7 +77,7 @@ export class ThemedSearchComponent extends ThemedComponent { @Input() showSidebar: boolean; - @Input() showThumbnails; + @Input() showThumbnails: boolean; @Input() showViewModes: boolean; @@ -65,6 +91,8 @@ export class ThemedSearchComponent extends ThemedComponent { @Input() query: string; + @Input() scope: string; + @Output() resultFound: EventEmitter> = new EventEmitter(); @Output() deselectObject: EventEmitter = new EventEmitter(); From 93b22cba1f1b541d86f12b3bce79c8db6fd83bb9 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Sat, 3 Feb 2024 13:39:31 +0100 Subject: [PATCH 2/2] 111639: Fixed search settings not using the scope --- .../search-settings.component.spec.ts | 41 ++----------------- .../search-settings.component.ts | 11 ++--- src/app/shared/search/search.component.ts | 5 +-- src/assets/i18n/en.json5 | 12 ++++++ 4 files changed, 21 insertions(+), 48 deletions(-) diff --git a/src/app/shared/search/search-settings/search-settings.component.spec.ts b/src/app/shared/search/search-settings/search-settings.component.spec.ts index d0b51f04b1f..bdcdb6f171f 100644 --- a/src/app/shared/search/search-settings/search-settings.component.spec.ts +++ b/src/app/shared/search/search-settings/search-settings.component.spec.ts @@ -1,4 +1,3 @@ -import { SearchService } from '../../../core/shared/search/search.service'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { SearchSettingsComponent } from './search-settings.component'; import { of as observableOf } from 'rxjs'; @@ -6,15 +5,11 @@ import { PaginationComponentOptions } from '../../pagination/pagination-componen import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { TranslateModule } from '@ngx-translate/core'; import { RouterTestingModule } from '@angular/router/testing'; -import { ActivatedRoute } from '@angular/router'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { EnumKeysPipe } from '../../utils/enum-keys-pipe'; import { By } from '@angular/platform-browser'; -import { SearchFilterService } from '../../../core/shared/search/search-filter.service'; import { VarDirective } from '../../utils/var.directive'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; -import { SidebarService } from '../../sidebar/sidebar.service'; -import { SidebarServiceStub } from '../../testing/sidebar-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../testing/pagination-service.stub'; @@ -22,32 +17,23 @@ describe('SearchSettingsComponent', () => { let comp: SearchSettingsComponent; let fixture: ComponentFixture; - let searchServiceObject: SearchService; let pagination: PaginationComponentOptions; let sort: SortOptions; - let mockResults; - let searchServiceStub; let queryParam; let scopeParam; let paginatedSearchOptions; - let paginationService; + let paginationService: PaginationServiceStub; - let activatedRouteStub; - beforeEach(waitForAsync(() => { + beforeEach(waitForAsync(async () => { pagination = new PaginationComponentOptions(); pagination.id = 'search-results-pagination'; pagination.currentPage = 1; pagination.pageSize = 10; sort = new SortOptions('score', SortDirection.DESC); - mockResults = ['test', 'data']; - searchServiceStub = { - searchOptions: { pagination: pagination, sort: sort }, - search: () => mockResults, - }; queryParam = 'test query'; scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; @@ -58,30 +44,12 @@ describe('SearchSettingsComponent', () => { sort, }; - activatedRouteStub = { - queryParams: observableOf({ - query: queryParam, - scope: scopeParam, - }), - }; - paginationService = new PaginationServiceStub(pagination, sort); - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], declarations: [SearchSettingsComponent, EnumKeysPipe, VarDirective], providers: [ - { provide: SearchService, useValue: searchServiceStub }, - - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { - provide: SidebarService, - useValue: SidebarServiceStub, - }, - { - provide: SearchFilterService, - useValue: {}, - }, { provide: PaginationService, useValue: paginationService, @@ -111,10 +79,7 @@ describe('SearchSettingsComponent', () => { // SearchPageComponent test instance fixture.detectChanges(); - searchServiceObject = (comp as any).service; spyOn(comp, 'reloadOrder'); - spyOn(searchServiceObject, 'search').and.callThrough(); - }); it('it should show the order settings with the respective selectable options', () => { diff --git a/src/app/shared/search/search-settings/search-settings.component.ts b/src/app/shared/search/search-settings/search-settings.component.ts index 0efd38b5b28..23c9e78c3a8 100644 --- a/src/app/shared/search/search-settings/search-settings.component.ts +++ b/src/app/shared/search/search-settings/search-settings.component.ts @@ -1,7 +1,5 @@ import { Component, Inject, Input } from '@angular/core'; -import { SearchService } from '../../../core/shared/search/search.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; -import { ActivatedRoute, Router } from '@angular/router'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { PaginationService } from '../../../core/pagination/pagination.service'; @@ -26,11 +24,10 @@ export class SearchSettingsComponent { */ @Input() sortOptionsList: SortOptions[]; - constructor(private service: SearchService, - private route: ActivatedRoute, - private router: Router, - private paginationService: PaginationService, - @Inject(SEARCH_CONFIG_SERVICE) public searchConfigurationService: SearchConfigurationService) { + constructor( + protected paginationService: PaginationService, + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigurationService: SearchConfigurationService, + ) { } /** diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 8e120940ecc..fc07893d721 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -315,9 +315,8 @@ export class SearchComponent implements OnDestroy, OnInit { // Determinate PaginatedSearchOptions and listen to any update on it const configuration$: Observable = this.searchConfigService .getCurrentConfiguration(this.configuration).pipe(distinctUntilChanged()); - const searchSortOptions$: Observable = configuration$.pipe( - switchMap((configuration: string) => this.searchConfigService - .getConfigurationSearchConfig(configuration)), + const searchSortOptions$: Observable = combineLatest([configuration$, this.currentScope$]).pipe( + switchMap(([configuration, scope]: [string, string]) => this.searchConfigService.getConfigurationSearchConfig(configuration, scope)), map((searchConfig: SearchConfig) => this.searchConfigService.getConfigurationSortOptions(searchConfig)), distinctUntilChanged() ); diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..19c297acd36 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3888,6 +3888,18 @@ "sorting.lastModified.DESC": "Last modified Descending", + "sorting.person.familyName.ASC": "Surname Ascending", + + "sorting.person.familyName.DESC": "Surname Descending", + + "sorting.person.givenName.ASC": "Name Ascending", + + "sorting.person.givenName.DESC": "Name Descending", + + "sorting.person.birthDate.ASC": "Birth Date Ascending", + + "sorting.person.birthDate.DESC": "Birth Date Descending", + "statistics.title": "Statistics", "statistics.header": "Statistics for {{ scope }}",