1
0

[CST-4009] Discovery result sort options not reflecting what is configured

This commit is contained in:
Alessandro Martelli
2021-04-06 10:06:15 +02:00
parent 9586428b12
commit 9b8ada0326
13 changed files with 292 additions and 72 deletions

View File

@@ -6,6 +6,8 @@
[configurationList]="(configurationList$ | async)" [configurationList]="(configurationList$ | async)"
[resultCount]="(resultsRD$ | async)?.payload.totalElements" [resultCount]="(resultsRD$ | async)?.payload.totalElements"
[viewModeList]="viewModeList" [viewModeList]="viewModeList"
[searchOptions]="(searchOptions$ | async)"
[sortOptions]="(sortOptions$ | async)"
[refreshFilters]="refreshFilters.asObservable()" [refreshFilters]="refreshFilters.asObservable()"
[inPlaceSearch]="inPlaceSearch"></ds-search-sidebar> [inPlaceSearch]="inPlaceSearch"></ds-search-sidebar>
<div class="col-12 col-md-9"> <div class="col-12 col-md-9">
@@ -28,6 +30,8 @@
[resultCount]="(resultsRD$ | async)?.payload.totalElements" [resultCount]="(resultsRD$ | async)?.payload.totalElements"
(toggleSidebar)="closeSidebar()" (toggleSidebar)="closeSidebar()"
[ngClass]="{'active': !(isSidebarCollapsed() | async)}" [ngClass]="{'active': !(isSidebarCollapsed() | async)}"
[searchOptions]="(searchOptions$ | async)"
[sortOptions]="(sortOptions$ | async)"
[refreshFilters]="refreshFilters.asObservable()" [refreshFilters]="refreshFilters.asObservable()"
[inPlaceSearch]="inPlaceSearch"> [inPlaceSearch]="inPlaceSearch">
</ds-search-sidebar> </ds-search-sidebar>

View File

@@ -45,6 +45,7 @@ describe('MyDSpacePageComponent', () => {
pagination.id = 'mydspace-results-pagination'; pagination.id = 'mydspace-results-pagination';
pagination.currentPage = 1; pagination.currentPage = 1;
pagination.pageSize = 10; pagination.pageSize = 10;
const sortOption = { name: 'score', metadata: null };
const sort: SortOptions = new SortOptions('score', SortDirection.DESC); const sort: SortOptions = new SortOptions('score', SortDirection.DESC);
const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']); const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']);
const searchServiceStub = jasmine.createSpyObj('SearchService', { const searchServiceStub = jasmine.createSpyObj('SearchService', {
@@ -52,7 +53,8 @@ describe('MyDSpacePageComponent', () => {
getEndpoint: observableOf('discover/search/objects'), getEndpoint: observableOf('discover/search/objects'),
getSearchLink: '/mydspace', getSearchLink: '/mydspace',
getScopes: observableOf(['test-scope']), getScopes: observableOf(['test-scope']),
setServiceOptions: {} setServiceOptions: {},
getSearchConfigurationFor: createSuccessfulRemoteDataObject$({ sortOptions: [sortOption]})
}); });
const configurationParam = 'default'; const configurationParam = 'default';
const queryParam = 'test query'; const queryParam = 'test query';
@@ -188,4 +190,24 @@ describe('MyDSpacePageComponent', () => {
}); });
}); });
describe('when stable', () => {
beforeEach(() => {
fixture.detectChanges();
});
it('should have initialized the sortOptions$ observable', (done) => {
comp.sortOptions$.subscribe((sortOptions) => {
expect(sortOptions.length).toEqual(2);
expect(sortOptions[0]).toEqual(new SortOptions('score', SortDirection.ASC));
expect(sortOptions[1]).toEqual(new SortOptions('score', SortDirection.DESC));
done();
});
});
});
}); });

View File

@@ -7,8 +7,8 @@ import {
OnInit OnInit
} from '@angular/core'; } from '@angular/core';
import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs'; import { BehaviorSubject, combineLatest, Observable, Subject, Subscription } from 'rxjs';
import { map, switchMap, tap, } from 'rxjs/operators'; import { map, switchMap, take, tap } from 'rxjs/operators';
import { PaginatedList } from '../core/data/paginated-list.model'; import { PaginatedList } from '../core/data/paginated-list.model';
import { RemoteData } from '../core/data/remote-data'; import { RemoteData } from '../core/data/remote-data';
@@ -19,7 +19,7 @@ import { PaginatedSearchOptions } from '../shared/search/paginated-search-option
import { SearchService } from '../core/shared/search/search.service'; import { SearchService } from '../core/shared/search/search.service';
import { SidebarService } from '../shared/sidebar/sidebar.service'; import { SidebarService } from '../shared/sidebar/sidebar.service';
import { hasValue } from '../shared/empty.util'; import { hasValue } from '../shared/empty.util';
import { getFirstSucceededRemoteData } from '../core/shared/operators'; import { getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload } from '../core/shared/operators';
import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service'; import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service';
import { SearchConfigurationOption } from '../shared/search/search-switch-configuration/search-configuration-option.model'; import { SearchConfigurationOption } from '../shared/search/search-switch-configuration/search-configuration-option.model';
import { RoleType } from '../core/roles/role-types'; import { RoleType } from '../core/roles/role-types';
@@ -29,6 +29,8 @@ import { ViewMode } from '../core/shared/view-mode.model';
import { MyDSpaceRequest } from '../core/data/request.models'; import { MyDSpaceRequest } from '../core/data/request.models';
import { SearchResult } from '../shared/search/search-result.model'; import { SearchResult } from '../shared/search/search-result.model';
import { Context } from '../core/shared/context.model'; import { Context } from '../core/shared/context.model';
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
import { SearchConfig } from '../core/shared/search/search-filters/search-config.model';
export const MYDSPACE_ROUTE = '/mydspace'; export const MYDSPACE_ROUTE = '/mydspace';
export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> = new InjectionToken<SearchConfigurationService>('searchConfigurationService'); export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> = new InjectionToken<SearchConfigurationService>('searchConfigurationService');
@@ -71,6 +73,11 @@ export class MyDSpacePageComponent implements OnInit {
*/ */
searchOptions$: Observable<PaginatedSearchOptions>; searchOptions$: Observable<PaginatedSearchOptions>;
/**
* The current available sort options
*/
sortOptions$: Observable<SortOptions[]>;
/** /**
* The current relevant scopes * The current relevant scopes
*/ */
@@ -151,6 +158,27 @@ export class MyDSpacePageComponent implements OnInit {
}) })
); );
this.sortOptions$ = this.context$.pipe(
switchMap((context) => this.service.getSearchConfigurationFor(null, context)),
getFirstSucceededRemoteDataPayload(),
map((searchConfig: SearchConfig) => {
const sortOptions = [];
searchConfig.sortOptions.forEach(sortOption => {
sortOptions.push(new SortOptions(sortOption.name, SortDirection.ASC));
sortOptions.push(new SortOptions(sortOption.name, SortDirection.DESC));
});
return sortOptions;
}));
combineLatest([
this.sortOptions$,
this.searchConfigService.paginatedSearchOptions
]).pipe(take(1))
.subscribe(([sortOptions, searchOptions]) => {
const updateValue = Object.assign(new PaginatedSearchOptions({}), searchOptions, { sort: sortOptions[0]});
this.searchConfigService.paginatedSearchOptions.next(updateValue);
});
} }
/** /**

View File

@@ -162,6 +162,7 @@ import { ShortLivedToken } from './auth/models/short-lived-token.model';
import { UsageReport } from './statistics/models/usage-report.model'; import { UsageReport } from './statistics/models/usage-report.model';
import { RootDataService } from './data/root-data.service'; import { RootDataService } from './data/root-data.service';
import { Root } from './data/root.model'; import { Root } from './data/root.model';
import { SearchConfig } from './shared/search/search-filters/search-config.model';
/** /**
* When not in production, endpoint responses can be mocked for testing purposes * When not in production, endpoint responses can be mocked for testing purposes
@@ -342,6 +343,7 @@ export const models =
Registration, Registration,
UsageReport, UsageReport,
Root, Root,
SearchConfig
]; ];
@NgModule({ @NgModule({

View File

@@ -0,0 +1,75 @@
import { autoserialize, deserialize } from 'cerialize';
import { SEARCH_CONFIG } from './search-config.resource-type';
import { typedObject } from '../../../cache/builders/build-decorators';
import { CacheableObject } from '../../../cache/object-cache.reducer';
import { HALLink } from '../../hal-link.model';
import { ResourceType } from '../../resource-type';
/**
* The configuration for a search
*/
@typedObject
export class SearchConfig implements CacheableObject {
static type = SEARCH_CONFIG;
/**
* The id of this search configuration.
*/
@autoserialize
id: string;
/**
* The configured filters.
*/
@autoserialize
filters: FilterConfig[];
/**
* The configured sort options.
*/
@autoserialize
sortOptions: SortOption[];
/**
* The object type.
*/
@autoserialize
type: ResourceType;
/**
* The {@link HALLink}s for this Item
*/
@deserialize
_links: {
facets: HALLink;
objects: HALLink;
self: HALLink;
};
}
/**
* Interface to model filter's configuration.
*/
export interface FilterConfig {
filter: string;
hasFacets: boolean;
operators: OperatorConfig[];
openByDefault: boolean;
pageSize: number;
type: string;
}
/**
* Interface to model sort option's configuration.
*/
export interface SortOption {
name: string;
}
/**
* Interface to model operator's configuration.
*/
export interface OperatorConfig {
operator: string;
}

View File

@@ -0,0 +1,9 @@
import {ResourceType} from '../../resource-type';
/**
* The resource type for SearchConfig
*
* Needs to be in a separate file to prevent circular
* dependencies in webpack.
*/
export const SEARCH_CONFIG = new ResourceType('discover');

View File

@@ -230,5 +230,55 @@ describe('SearchService', () => {
expect((searchService as any).requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({ href: requestUrl }), true); expect((searchService as any).requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({ href: requestUrl }), true);
}); });
}); });
describe('when getSearchConfigurationFor is called without a scope', () => {
const endPoint = 'http://endpoint.com/test/config';
beforeEach(() => {
spyOn((searchService as any).halService, 'getEndpoint').and.returnValue(observableOf(endPoint));
spyOn((searchService as any).rdb, 'buildFromHref').and.callThrough();
/* tslint:disable:no-empty */
searchService.getSearchConfigurationFor(null).subscribe((t) => {
}); // subscribe to make sure all methods are called
/* tslint:enable:no-empty */
});
it('should call getEndpoint on the halService', () => {
expect((searchService as any).halService.getEndpoint).toHaveBeenCalled();
});
it('should send out the request on the request service', () => {
expect((searchService as any).requestService.send).toHaveBeenCalled();
});
it('should call send containing a request with the correct request url', () => {
expect((searchService as any).requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({ href: endPoint }), true);
});
});
describe('when getSearchConfigurationFor is called with a scope', () => {
const endPoint = 'http://endpoint.com/test/config';
const scope = 'test';
const requestUrl = endPoint + '?scope=' + scope;
beforeEach(() => {
spyOn((searchService as any).halService, 'getEndpoint').and.returnValue(observableOf(endPoint));
/* tslint:disable:no-empty */
searchService.getSearchConfigurationFor(scope).subscribe((t) => {
}); // subscribe to make sure all methods are called
/* tslint:enable:no-empty */
});
it('should call getEndpoint on the halService', () => {
expect((searchService as any).halService.getEndpoint).toHaveBeenCalled();
});
it('should send out the request on the request service', () => {
expect((searchService as any).requestService.send).toHaveBeenCalled();
});
it('should call send containing a request with the correct request url', () => {
expect((searchService as any).requestService.send).toHaveBeenCalledWith(jasmine.objectContaining({ href: requestUrl }), true);
});
});
}); });
}); });

View File

@@ -37,12 +37,19 @@ import { ListableObject } from '../../../shared/object-collection/shared/listabl
import { getSearchResultFor } from '../../../shared/search/search-result-element-decorator'; import { getSearchResultFor } from '../../../shared/search/search-result-element-decorator';
import { FacetConfigResponse } from '../../../shared/search/facet-config-response.model'; import { FacetConfigResponse } from '../../../shared/search/facet-config-response.model';
import { FacetValues } from '../../../shared/search/facet-values.model'; import { FacetValues } from '../../../shared/search/facet-values.model';
import { SearchConfig } from './search-filters/search-config.model';
/** /**
* Service that performs all general actions that have to do with the search page * Service that performs all general actions that have to do with the search page
*/ */
@Injectable() @Injectable()
export class SearchService implements OnDestroy { export class SearchService implements OnDestroy {
/**
* Endpoint link path for retrieving search configurations
*/
private configurationLinkPath = 'discover/search';
/** /**
* Endpoint link path for retrieving general search results * Endpoint link path for retrieving general search results
*/ */
@@ -224,6 +231,24 @@ export class SearchService implements OnDestroy {
); );
} }
private getConfigUrl(url: string, scope?: string, configurationName?: string) {
const args: string[] = [];
if (isNotEmpty(scope)) {
args.push(`scope=${scope}`);
}
if (isNotEmpty(configurationName)) {
args.push(`configuration=${configurationName}`);
}
if (isNotEmpty(args)) {
url = new URLCombiner(url, `?${args.join('&')}`).toString();
}
return url;
}
/** /**
* Request the filter configuration for a given scope or the whole repository * Request the filter configuration for a given scope or the whole repository
* @param {string} scope UUID of the object for which config the filter config is requested, when no scope is provided the configuration for the whole repository is loaded * @param {string} scope UUID of the object for which config the filter config is requested, when no scope is provided the configuration for the whole repository is loaded
@@ -232,33 +257,17 @@ export class SearchService implements OnDestroy {
*/ */
getConfig(scope?: string, configurationName?: string): Observable<RemoteData<SearchFilterConfig[]>> { getConfig(scope?: string, configurationName?: string): Observable<RemoteData<SearchFilterConfig[]>> {
const href$ = this.halService.getEndpoint(this.facetLinkPathPrefix).pipe( const href$ = this.halService.getEndpoint(this.facetLinkPathPrefix).pipe(
map((url: string) => { map((url: string) => this.getConfigUrl(url, scope, configurationName)),
const args: string[] = [];
if (isNotEmpty(scope)) {
args.push(`scope=${scope}`);
}
if (isNotEmpty(configurationName)) {
args.push(`configuration=${configurationName}`);
}
if (isNotEmpty(args)) {
url = new URLCombiner(url, `?${args.join('&')}`).toString();
}
return url;
}),
); );
href$.pipe(take(1)).subscribe((url: string) => { href$.pipe(take(1)).subscribe((url: string) => {
let request = new this.request(this.requestService.generateRequestId(), url); let request = new this.request(this.requestService.generateRequestId(), url);
request = Object.assign(request, { request = Object.assign(request, {
getResponseParser(): GenericConstructor<ResponseParsingService> { getResponseParser(): GenericConstructor<ResponseParsingService> {
return FacetConfigResponseParsingService; return FacetConfigResponseParsingService;
} }
}); });
this.requestService.send(request, true); this.requestService.send(request, true);
}); });
return this.rdb.buildFromHref(href$).pipe( return this.rdb.buildFromHref(href$).pipe(
@@ -397,6 +406,25 @@ export class SearchService implements OnDestroy {
}); });
} }
/**
* Request the search configuration for a given scope or the whole repository
* @param {string} scope UUID of the object for which config the filter config is requested, when no scope is provided the configuration for the whole repository is loaded
* @param {string} configurationName the name of the configuration
* @returns {Observable<RemoteData<SearchConfig[]>>} The found configuration
*/
getSearchConfigurationFor(scope?: string, configurationName?: string ): Observable<RemoteData<SearchConfig>> {
const href$ = this.halService.getEndpoint(this.configurationLinkPath).pipe(
map((url: string) => this.getConfigUrl(url, scope, configurationName)),
);
href$.pipe(take(1)).subscribe((url: string) => {
const request = new this.request(this.requestService.generateRequestId(), url);
this.requestService.send(request, true);
});
return this.rdb.buildFromHref(href$);
}
/** /**
* @returns {string} The base path to the search page * @returns {string} The base path to the search page
*/ */

View File

@@ -1,4 +1,4 @@
<ng-container *ngVar="(searchOptions$ | async) as config"> <ng-container *ngVar="searchOptions as config">
<h3>{{ 'search.sidebar.settings.title' | translate}}</h3> <h3>{{ 'search.sidebar.settings.title' | translate}}</h3>
<div class="result-order-settings"> <div class="result-order-settings">
<ds-sidebar-dropdown <ds-sidebar-dropdown
@@ -7,7 +7,7 @@
[label]="'search.sidebar.settings.sort-by'" [label]="'search.sidebar.settings.sort-by'"
(change)="reloadOrder($event)" (change)="reloadOrder($event)"
> >
<option *ngFor="let sortOption of searchOptionPossibilities" <option *ngFor="let sortOption of sortOptions"
[value]="sortOption.field + ',' + sortOption.direction.toString()" [value]="sortOption.field + ',' + sortOption.direction.toString()"
[selected]="sortOption.field === config?.sort.field && sortOption.direction === (config?.sort.direction)? 'selected': null"> [selected]="sortOption.field === config?.sort.field && sortOption.direction === (config?.sort.direction)? 'selected': null">
{{'sorting.' + sortOption.field + '.' + sortOption.direction | translate}} {{'sorting.' + sortOption.field + '.' + sortOption.direction | translate}}
@@ -15,4 +15,4 @@
</ds-sidebar-dropdown> </ds-sidebar-dropdown>
</div> </div>
<ds-page-size-selector></ds-page-size-selector> <ds-page-size-selector></ds-page-size-selector>
</ng-container> </ng-container>

View File

@@ -12,7 +12,6 @@ import { EnumKeysPipe } from '../../utils/enum-keys-pipe';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { SearchFilterService } from '../../../core/shared/search/search-filter.service'; import { SearchFilterService } from '../../../core/shared/search/search-filter.service';
import { VarDirective } from '../../utils/var.directive'; import { VarDirective } from '../../utils/var.directive';
import { take } from 'rxjs/operators';
import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component'; import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component';
import { SidebarService } from '../../sidebar/sidebar.service'; import { SidebarService } from '../../sidebar/sidebar.service';
import { SidebarServiceStub } from '../../testing/sidebar-service.stub'; import { SidebarServiceStub } from '../../testing/sidebar-service.stub';
@@ -81,7 +80,7 @@ describe('SearchSettingsComponent', () => {
provide: SEARCH_CONFIG_SERVICE, provide: SEARCH_CONFIG_SERVICE,
useValue: { useValue: {
paginatedSearchOptions: observableOf(paginatedSearchOptions), paginatedSearchOptions: observableOf(paginatedSearchOptions),
getCurrentScope: observableOf('test-id') getCurrentScope: observableOf('test-id'),
} }
}, },
], ],
@@ -93,6 +92,14 @@ describe('SearchSettingsComponent', () => {
fixture = TestBed.createComponent(SearchSettingsComponent); fixture = TestBed.createComponent(SearchSettingsComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.sortOptions = [
new SortOptions('score', SortDirection.DESC),
new SortOptions('dc.title', SortDirection.ASC),
new SortOptions('dc.title', SortDirection.DESC)
];
comp.searchOptions = paginatedSearchOptions;
// SearchPageComponent test instance // SearchPageComponent test instance
fixture.detectChanges(); fixture.detectChanges();
searchServiceObject = (comp as any).service; searchServiceObject = (comp as any).service;
@@ -101,34 +108,24 @@ describe('SearchSettingsComponent', () => {
}); });
it('it should show the order settings with the respective selectable options', (done) => { it('it should show the order settings with the respective selectable options', () => {
(comp as any).searchOptions$.pipe(take(1)).subscribe((options) => { fixture.detectChanges();
fixture.detectChanges(); const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings'));
const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings')); expect(orderSetting).toBeDefined();
expect(orderSetting).toBeDefined(); const childElements = orderSetting.queryAll(By.css('option'));
const childElements = orderSetting.queryAll(By.css('option')); expect(childElements.length).toEqual(comp.sortOptions.length);
expect(childElements.length).toEqual(comp.searchOptionPossibilities.length);
done();
});
}); });
it('it should show the size settings', (done) => { it('it should show the size settings', () => {
(comp as any).searchOptions$.pipe(take(1)).subscribe((options) => { fixture.detectChanges();
fixture.detectChanges(); const pageSizeSetting = fixture.debugElement.query(By.css('page-size-settings'));
const pageSizeSetting = fixture.debugElement.query(By.css('page-size-settings')); expect(pageSizeSetting).toBeDefined();
expect(pageSizeSetting).toBeDefined();
done();
}
);
}); });
it('should have the proper order value selected by default', (done) => { it('should have the proper order value selected by default', () => {
(comp as any).searchOptions$.pipe(take(1)).subscribe((options) => { fixture.detectChanges();
fixture.detectChanges(); const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings'));
const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings')); const childElementToBeSelected = orderSetting.query(By.css('option[value="score,DESC"][selected="selected"]'));
const childElementToBeSelected = orderSetting.query(By.css('option[value="0"][selected="selected"]')); expect(childElementToBeSelected).toBeDefined();
expect(childElementToBeSelected).toBeDefined();
done();
});
}); });
}); });

View File

@@ -1,9 +1,8 @@
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, Input } from '@angular/core';
import { SearchService } from '../../../core/shared/search/search.service'; import { SearchService } from '../../../core/shared/search/search.service';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { SortOptions } from '../../../core/cache/models/sort-options.model';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { PaginatedSearchOptions } from '../paginated-search-options.model'; import { PaginatedSearchOptions } from '../paginated-search-options.model';
import { Observable } from 'rxjs';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component'; import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component';
@@ -16,16 +15,17 @@ import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.c
/** /**
* This component represents the part of the search sidebar that contains the general search settings. * This component represents the part of the search sidebar that contains the general search settings.
*/ */
export class SearchSettingsComponent implements OnInit { export class SearchSettingsComponent {
/** /**
* The configuration for the current paginated search results * The configuration for the current paginated search results
*/ */
searchOptions$: Observable<PaginatedSearchOptions>; @Input() searchOptions: PaginatedSearchOptions;
/** /**
* All sort options that are shown in the settings * All sort options that are shown in the settings
*/ */
searchOptionPossibilities = [new SortOptions('score', SortDirection.DESC), new SortOptions('dc.title', SortDirection.ASC), new SortOptions('dc.title', SortDirection.DESC)]; @Input() sortOptions: SortOptions[];
constructor(private service: SearchService, constructor(private service: SearchService,
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -33,13 +33,6 @@ export class SearchSettingsComponent implements OnInit {
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigurationService: SearchConfigurationService) { @Inject(SEARCH_CONFIG_SERVICE) public searchConfigurationService: SearchConfigurationService) {
} }
/**
* Initialize paginated search options
*/
ngOnInit(): void {
this.searchOptions$ = this.searchConfigurationService.paginatedSearchOptions;
}
/** /**
* Method to change the current sort field and direction * Method to change the current sort field and direction
* @param {Event} event Change event containing the sort direction and sort field * @param {Event} event Change event containing the sort direction and sort field

View File

@@ -12,7 +12,7 @@
<div class="sidebar-content"> <div class="sidebar-content">
<ds-search-switch-configuration [inPlaceSearch]="inPlaceSearch" *ngIf="configurationList" [configurationList]="configurationList"></ds-search-switch-configuration> <ds-search-switch-configuration [inPlaceSearch]="inPlaceSearch" *ngIf="configurationList" [configurationList]="configurationList"></ds-search-switch-configuration>
<ds-search-filters [refreshFilters]="refreshFilters" [inPlaceSearch]="inPlaceSearch"></ds-search-filters> <ds-search-filters [refreshFilters]="refreshFilters" [inPlaceSearch]="inPlaceSearch"></ds-search-filters>
<ds-search-settings></ds-search-settings> <ds-search-settings [searchOptions]="searchOptions" [sortOptions]="sortOptions"></ds-search-settings>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,6 +2,8 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
import { SearchConfigurationOption } from '../search-switch-configuration/search-configuration-option.model'; import { SearchConfigurationOption } from '../search-switch-configuration/search-configuration-option.model';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { PaginatedSearchOptions } from '../paginated-search-options.model';
import { SortOptions } from '../../../core/cache/models/sort-options.model';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -45,6 +47,16 @@ export class SearchSidebarComponent {
*/ */
@Input() inPlaceSearch; @Input() inPlaceSearch;
/**
* The configuration for the current paginated search results
*/
@Input() searchOptions: PaginatedSearchOptions;
/**
* All sort options that are shown in the settings
*/
@Input() sortOptions: SortOptions[];
/** /**
* Emits when the search filters values may be stale, and so they must be refreshed. * Emits when the search filters values may be stale, and so they must be refreshed.
*/ */