diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html index 9ec082db73..c7e1f77264 100644 --- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html +++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts index e76a9cf3d0..711e1b9d3d 100644 --- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts +++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts @@ -47,9 +47,9 @@ describe('RelatedEntitiesSearchComponent', () => { expect(comp.fixedFilter).toEqual(mockFilter); }); - it('should create a fixedFilter$', () => { - comp.fixedFilter$.subscribe((fixedFilter) => { - expect(fixedFilter).toEqual(mockRelationEntityType); + it('should create a configuration$', () => { + comp.configuration$.subscribe((configuration) => { + expect(configuration).toEqual(mockRelationEntityType); }) }); diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts index 672655a8b8..4c0b127925 100644 --- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts +++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts @@ -47,7 +47,7 @@ export class RelatedEntitiesSearchComponent implements OnInit { @Input() sideBarWidth = 4; fixedFilter: string; - fixedFilter$: Observable; + configuration$: Observable; constructor(private fixedFilterService: SearchFixedFilterService) { } @@ -57,7 +57,7 @@ export class RelatedEntitiesSearchComponent implements OnInit { this.fixedFilter = this.fixedFilterService.getFilterByRelation(this.relationType, this.item.id); } if (isNotEmpty(this.relationEntityType)) { - this.fixedFilter$ = of(this.relationEntityType); + this.configuration$ = of(this.relationEntityType); } } diff --git a/src/app/+search-page/configuration-search-page.component.spec.ts b/src/app/+search-page/configuration-search-page.component.spec.ts new file mode 100644 index 0000000000..a18dd38f78 --- /dev/null +++ b/src/app/+search-page/configuration-search-page.component.spec.ts @@ -0,0 +1,21 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { configureSearchComponentTestingModule } from './search-page.component.spec'; +import { SearchConfigurationService } from './search-service/search-configuration.service'; +import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; + +describe('ConfigurationSearchPageComponent', () => { + let comp: ConfigurationSearchPageComponent; + let fixture: ComponentFixture; + let searchConfigService: SearchConfigurationService; + + beforeEach(async(() => { + configureSearchComponentTestingModule(ConfigurationSearchPageComponent); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfigurationSearchPageComponent); + comp = fixture.componentInstance; + searchConfigService = (comp as any).searchConfigService; + fixture.detectChanges(); + }); +}); diff --git a/src/app/+search-page/configuration-search-page.component.ts b/src/app/+search-page/configuration-search-page.component.ts new file mode 100644 index 0000000000..85619e8f04 --- /dev/null +++ b/src/app/+search-page/configuration-search-page.component.ts @@ -0,0 +1,71 @@ +import { HostWindowService } from '../shared/host-window.service'; +import { SearchService } from './search-service/search.service'; +import { SearchSidebarService } from './search-sidebar/search-sidebar.service'; +import { SearchPageComponent } from './search-page.component'; +import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core'; +import { pushInOut } from '../shared/animations/push'; +import { RouteService } from '../shared/services/route.service'; +import { SearchConfigurationService } from './search-service/search-configuration.service'; +import { Observable } from 'rxjs'; +import { PaginatedSearchOptions } from './paginated-search-options.model'; +import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component'; +import { map } from 'rxjs/operators'; + +/** + * This component renders a search page using a configuration as input. + */ +@Component({ + selector: 'ds-configuration-search-page', + styleUrls: ['./search-page.component.scss'], + templateUrl: './search-page.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + animations: [pushInOut], + providers: [ + { + provide: SEARCH_CONFIG_SERVICE, + useClass: SearchConfigurationService + } + ] +}) + +export class ConfigurationSearchPageComponent extends SearchPageComponent implements OnInit { + /** + * The configuration to use for the search options + * If empty, the configuration will be determined by the route parameter called 'configuration' + */ + @Input() configuration: string; + + constructor(protected service: SearchService, + protected sidebarService: SearchSidebarService, + protected windowService: HostWindowService, + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService, + protected routeService: RouteService) { + super(service, sidebarService, windowService, searchConfigService, routeService); + } + + /** + * Listening to changes in the paginated search options + * If something changes, update the search results + * + * Listen to changes in the scope + * If something changes, update the list of scopes for the dropdown + */ + ngOnInit(): void { + super.ngOnInit(); + } + + /** + * Get the current paginated search options after updating the configuration using the configuration input + * This is to make sure the configuration is included in the paginated search options, as it is not part of any + * query or route parameters + * @returns {Observable} + */ + protected getSearchOptions(): Observable { + return this.searchConfigService.paginatedSearchOptions.pipe( + map((options: PaginatedSearchOptions) => { + const config = this.configuration || options.configuration; + return Object.assign(options, { configuration: config }); + }) + ); + } +} diff --git a/src/app/+search-page/configuration-search-page.guard.ts b/src/app/+search-page/configuration-search-page.guard.ts new file mode 100644 index 0000000000..c52a0a6d8e --- /dev/null +++ b/src/app/+search-page/configuration-search-page.guard.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; + +@Injectable() +/** + * Assemble the correct i18n key for the configuration search page's title depending on the current route's configuration parameter. + * The format of the key will be "{configuration}.search.title" with: + * - configuration: The current configuration stored in route.params + */ +export class ConfigurationSearchPageGuard implements CanActivate { + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean { + const configuration = route.params.configuration; + + const newTitle = configuration + '.search.title'; + + route.data = { title: newTitle }; + return true; + } +} diff --git a/src/app/+search-page/filtered-search-page.guard.ts b/src/app/+search-page/filtered-search-page.guard.ts deleted file mode 100644 index 6d41d4965d..0000000000 --- a/src/app/+search-page/filtered-search-page.guard.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Injectable } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { Observable } from 'rxjs'; - -@Injectable() -/** - * Assemble the correct i18n key for the filtered search page's title depending on the current route's filter parameter. - * The format of the key will be "{filter}.search.title" with: - * - filter: The current filter stored in route.params - */ -export class FilteredSearchPageGuard implements CanActivate { - canActivate( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot): Observable | Promise | boolean { - const filter = route.params.filter; - - const newTitle = filter + '.search.title'; - - route.data = { title: newTitle }; - return true; - } -} diff --git a/src/app/+search-page/search-page-routing.module.ts b/src/app/+search-page/search-page-routing.module.ts index c3cf4e1343..d1ab02945e 100644 --- a/src/app/+search-page/search-page-routing.module.ts +++ b/src/app/+search-page/search-page-routing.module.ts @@ -2,14 +2,14 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { SearchPageComponent } from './search-page.component'; -import { FilteredSearchPageComponent } from './filtered-search-page.component'; -import { FilteredSearchPageGuard } from './filtered-search-page.guard'; +import { ConfigurationSearchPageGuard } from './configuration-search-page.guard'; +import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; @NgModule({ imports: [ RouterModule.forChild([ { path: '', component: SearchPageComponent, data: { title: 'search.title' } }, - { path: ':filter', component: FilteredSearchPageComponent, canActivate: [FilteredSearchPageGuard]} + { path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard]} ]) ] }) diff --git a/src/app/+search-page/search-page.component.html b/src/app/+search-page/search-page.component.html index b4d8c70f11..ea04a2b04e 100644 --- a/src/app/+search-page/search-page.component.html +++ b/src/app/+search-page/search-page.component.html @@ -33,7 +33,7 @@ diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index f23bff96f3..03433d1da1 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -86,10 +86,10 @@ export class SearchPageComponent implements OnInit { sideBarWidth = 3; /** - * The currently applied filter (determines title of search) + * The currently applied configuration (determines title of search) */ @Input() - fixedFilter$: Observable; + configuration$: Observable; constructor(protected service: SearchService, protected sidebarService: SearchSidebarService, @@ -116,8 +116,8 @@ export class SearchPageComponent implements OnInit { this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( switchMap((scopeId) => this.service.getScopes(scopeId)) ); - if (!isNotEmpty(this.fixedFilter$)) { - this.fixedFilter$ = this.routeService.getRouteParameterValue('filter'); + if (!isNotEmpty(this.configuration$)) { + this.configuration$ = this.routeService.getRouteParameterValue('configuration'); } } diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 65558eae17..d7d66d854c 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -17,9 +17,7 @@ import { SearchFiltersComponent } from './search-filters/search-filters.componen import { SearchFilterComponent } from './search-filters/search-filter/search-filter.component'; import { SearchFacetFilterComponent } from './search-filters/search-filter/search-facet-filter/search-facet-filter.component'; import { SearchFilterService } from './search-filters/search-filter/search-filter.service'; -import { FilteredSearchPageComponent } from './filtered-search-page.component'; import { SearchFixedFilterService } from './search-filters/search-filter/search-fixed-filter.service'; -import { FilteredSearchPageGuard } from './filtered-search-page.guard'; import { SearchLabelsComponent } from './search-labels/search-labels.component'; import { SearchRangeFilterComponent } from './search-filters/search-filter/search-range-filter/search-range-filter.component'; import { SearchTextFilterComponent } from './search-filters/search-filter/search-text-filter/search-text-filter.component'; @@ -32,6 +30,9 @@ import { SearchFacetSelectedOptionComponent } from './search-filters/search-filt import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component'; import { SearchSwitchConfigurationComponent } from './search-switch-configuration/search-switch-configuration.component'; import { SearchAuthorityFilterComponent } from './search-filters/search-filter/search-authority-filter/search-authority-filter.component'; +import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; +import { ConfigurationSearchPageGuard } from './configuration-search-page.guard'; +import { FilteredSearchPageComponent } from './filtered-search-page.component'; const effects = [ SearchSidebarEffects @@ -60,7 +61,8 @@ const components = [ SearchFacetRangeOptionComponent, SearchSwitchConfigurationComponent, SearchAuthorityFilterComponent, - FilteredSearchPageComponent + FilteredSearchPageComponent, + ConfigurationSearchPageComponent ]; @NgModule({ @@ -76,7 +78,7 @@ const components = [ SearchSidebarService, SearchFilterService, SearchFixedFilterService, - FilteredSearchPageGuard, + ConfigurationSearchPageGuard, SearchFilterService, SearchConfigurationService ], diff --git a/src/app/+search-page/search-results/search-results.component.html b/src/app/+search-page/search-results/search-results.component.html index 824d531155..5a1e89858b 100644 --- a/src/app/+search-page/search-results/search-results.component.html +++ b/src/app/+search-page/search-results/search-results.component.html @@ -1,4 +1,4 @@ -

{{ getTitleKey() | translate }}

+

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

} Emits the current configuration string */ getCurrentConfiguration(defaultConfiguration: string) { - return this.routeService.getQueryParameterValue('configuration').pipe(map((configuration) => { - return configuration || defaultConfiguration; - })); + return observableCombineLatest( + this.routeService.getQueryParameterValue('configuration').pipe(startWith(undefined)), + this.routeService.getRouteParameterValue('configuration').pipe(startWith(undefined)) + ).pipe( + map(([queryConfig, routeConfig]) => { + return queryConfig || routeConfig || defaultConfiguration; + }) + ); } /** diff --git a/src/app/+search-page/search-service/search-result-element-decorator.ts b/src/app/+search-page/search-service/search-result-element-decorator.ts index 59446480a3..e804a5d8ee 100644 --- a/src/app/+search-page/search-service/search-result-element-decorator.ts +++ b/src/app/+search-page/search-service/search-result-element-decorator.ts @@ -1,6 +1,6 @@ import { GenericConstructor } from '../../core/shared/generic-constructor'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; -import { isNull } from '../../shared/empty.util'; +import { hasNoValue, isNull } from '../../shared/empty.util'; /** * Contains the mapping between a search result component and a DSpaceObject @@ -34,7 +34,7 @@ export function searchResultFor(domainConstructor: GenericConstructor, configuration: string = null) { - if (isNull(configuration) || configuration === 'default') { + if (isNull(configuration) || configuration === 'default' || hasNoValue(searchResultMap.get(configuration))) { return searchResultMap.get(domainConstructor); } else { return searchResultMap.get(configuration).get(domainConstructor);