Skip to content

Commit 213f454

Browse files
committed
[CST-6876] Retrieve filter list in parent search.component
1 parent 380aadb commit 213f454

7 files changed

Lines changed: 92 additions & 51 deletions

File tree

src/app/shared/search/search-filters/search-filters.component.spec.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
77
import { SearchFilterService } from '../../../core/shared/search/search-filter.service';
88
import { SearchFiltersComponent } from './search-filters.component';
99
import { SearchService } from '../../../core/shared/search/search.service';
10-
import { of as observableOf, Subject } from 'rxjs';
10+
import { of as observableOf } from 'rxjs';
1111
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
1212
import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub';
1313

@@ -66,26 +66,4 @@ describe('SearchFiltersComponent', () => {
6666
});
6767
});
6868

69-
describe('when refreshSearch observable is present and emit events', () => {
70-
71-
let refreshFiltersEmitter: Subject<any>;
72-
73-
beforeEach(() => {
74-
spyOn(comp, 'initFilters').and.callFake(() => { /****/});
75-
76-
refreshFiltersEmitter = new Subject();
77-
comp.refreshFilters = refreshFiltersEmitter.asObservable();
78-
comp.ngOnInit();
79-
});
80-
81-
it('should reinitialize search filters', () => {
82-
83-
expect(comp.initFilters).toHaveBeenCalledTimes(1);
84-
85-
refreshFiltersEmitter.next();
86-
87-
expect(comp.initFilters).toHaveBeenCalledTimes(2);
88-
});
89-
});
90-
9169
});

src/app/shared/search/search-filters/search-filters.component.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { RemoteData } from '../../../core/data/remote-data';
99
import { SearchFilterConfig } from '../models/search-filter-config.model';
1010
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
1111
import { SearchFilterService } from '../../../core/shared/search/search-filter.service';
12-
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
1312
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
1413
import { currentPath } from '../../utils/route.utils';
1514
import { hasValue } from '../../empty.util';
@@ -28,7 +27,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy {
2827
/**
2928
* An observable containing configuration about which filters are shown and how they are shown
3029
*/
31-
filters: Observable<RemoteData<SearchFilterConfig[]>>;
30+
@Input() filters: Observable<RemoteData<SearchFilterConfig[]>>;
3231

3332
/**
3433
* List of all filters that are currently active with their value set to null.
@@ -61,11 +60,6 @@ export class SearchFiltersComponent implements OnInit, OnDestroy {
6160
*/
6261
searchLink: string;
6362

64-
/**
65-
* For chart regular expression
66-
*/
67-
chartReg = new RegExp(/^chart./, 'i');
68-
6963
subs = [];
7064

7165
/**
@@ -83,31 +77,13 @@ export class SearchFiltersComponent implements OnInit, OnDestroy {
8377
}
8478

8579
ngOnInit(): void {
86-
87-
this.initFilters();
88-
89-
if (this.refreshFilters) {
90-
this.subs.push(this.refreshFilters.subscribe(() => this.initFilters()));
91-
}
92-
9380
this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => {
9481
Object.keys(filters).forEach((f) => filters[f] = null);
9582
return filters;
9683
}));
9784
this.searchLink = this.getSearchLink();
9885
}
9986

100-
initFilters() {
101-
this.filters = this.searchService.getConfig(this.currentScope, this.currentConfiguration).pipe(
102-
getFirstSucceededRemoteData(),
103-
map((rd: RemoteData<SearchFilterConfig[]>) => Object.assign(rd, {
104-
payload: rd.payload.filter((filter: SearchFilterConfig) =>
105-
!this.chartReg.test(filter.filterType)
106-
)})
107-
)
108-
);
109-
}
110-
11187
/**
11288
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
11389
*/

src/app/shared/search/search-sidebar/search-sidebar.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
(changeConfiguration)="changeConfiguration.emit($event)"></ds-search-switch-configuration>
2121
<ds-search-filters [currentScope]="currentScope"
2222
[currentConfiguration]="configuration"
23+
[filters]="filters"
2324
[refreshFilters]="refreshFilters"
2425
[inPlaceSearch]="inPlaceSearch"></ds-search-filters>
2526
<ds-search-settings [currentSortOption]="currentSortOption" [sortOptionsList]="sortOptionsList"></ds-search-settings>

src/app/shared/search/search-sidebar/search-sidebar.component.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { Observable } from 'rxjs';
55
import { PaginatedSearchOptions } from '../models/paginated-search-options.model';
66
import { SortOptions } from '../../../core/cache/models/sort-options.model';
77
import { ViewMode } from '../../../core/shared/view-mode.model';
8+
import { RemoteData } from '../../../core/data/remote-data';
9+
import { SearchFilterConfig } from '../models/search-filter-config.model';
810

911
/**
1012
* This component renders a simple item page.
@@ -43,6 +45,11 @@ export class SearchSidebarComponent {
4345
*/
4446
@Input() currentSortOption: SortOptions;
4547

48+
/**
49+
* An observable containing configuration about which filters are shown and how they are shown
50+
*/
51+
@Input() filters: Observable<RemoteData<SearchFilterConfig[]>>;
52+
4653
/**
4754
* The total amount of results
4855
*/

src/app/shared/search/search.component.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
[configurationList]="configurationList"
5959
[configuration]="(currentConfiguration$ | async)"
6060
[currentScope]="(currentScope$ | async)"
61+
[filters]="filtersRD$.asObservable()"
6162
[resultCount]="(resultsRD$ | async)?.payload?.totalElements"
6263
[searchOptions]="(searchOptions$ | async)"
6364
[sortOptionsList]="(sortOptionsList$ | async)"
@@ -71,6 +72,7 @@
7172
[configurationList]="configurationList"
7273
[configuration]="(currentConfiguration$ | async)"
7374
[currentScope]="(currentScope$ | async)"
75+
[filters]="filtersRD$.asObservable()"
7476
[resultCount]="(resultsRD$ | async)?.payload.totalElements"
7577
[searchOptions]="(searchOptions$ | async)"
7678
[sortOptionsList]="(sortOptionsList$ | async)"

src/app/shared/search/search.component.spec.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing';
55
import { Store } from '@ngrx/store';
66
import { TranslateModule } from '@ngx-translate/core';
77
import { cold } from 'jasmine-marbles';
8-
import { Observable, BehaviorSubject, of as observableOf } from 'rxjs';
8+
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
99
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
1010
import { CommunityDataService } from '../../core/data/community-data.service';
1111
import { HostWindowService } from '../host-window.service';
@@ -30,6 +30,8 @@ import { RemoteData } from '../../core/data/remote-data';
3030
import { SearchObjects } from './models/search-objects.model';
3131
import { DSpaceObject } from '../../core/shared/dspace-object.model';
3232
import { SearchManager } from '../../core/browse/search-manager';
33+
import { SearchFilterConfig } from './models/search-filter-config.model';
34+
import { FilterType } from './models/filter-type.model';
3335

3436
let comp: SearchComponent;
3537
let fixture: ComponentFixture<SearchComponent>;
@@ -96,10 +98,38 @@ const mockSearchResults: SearchObjects<DSpaceObject> = Object.assign(new SearchO
9698
});
9799
const mockResultsRD: RemoteData<SearchObjects<DSpaceObject>> = createSuccessfulRemoteDataObject(mockSearchResults);
98100
const mockResultsRD$: Observable<RemoteData<SearchObjects<DSpaceObject>>> = observableOf(mockResultsRD);
101+
102+
const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
103+
name: 'test1',
104+
filterType: FilterType.text,
105+
hasFacets: false,
106+
isOpenByDefault: false,
107+
pageSize: 2
108+
});
109+
const mockFilterConfig2: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
110+
name: 'test2',
111+
filterType: FilterType.text,
112+
hasFacets: false,
113+
isOpenByDefault: false,
114+
pageSize: 1
115+
});
116+
const mockChartFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
117+
name: 'line',
118+
filterType: FilterType['chart.line'],
119+
hasFacets: false,
120+
isOpenByDefault: false,
121+
pageSize: 1
122+
});
123+
124+
const filtersConfigRD = createSuccessfulRemoteDataObject([mockFilterConfig, mockFilterConfig2, mockChartFilterConfig]);
125+
const resultFiltersConfigRD = createSuccessfulRemoteDataObject([mockFilterConfig, mockFilterConfig2]);
126+
const filtersConfigRD$ = observableOf(filtersConfigRD);
127+
99128
const searchServiceStub = jasmine.createSpyObj('SearchService', {
100129
getSearchLink: '/search',
101130
getScopes: observableOf(['test-scope']),
102-
getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig)
131+
getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig),
132+
getConfig: filtersConfigRD$,
103133
});
104134
const searchManagerStub = jasmine.createSpyObj('SearchManager', {
105135
search: mockResultsRD$,
@@ -152,6 +182,7 @@ const routeServiceStub = {
152182

153183
const searchConfigurationServiceStub = jasmine.createSpyObj('SearchConfigurationService', {
154184
getConfigurationSortOptions: jasmine.createSpy('getConfigurationSortOptions'),
185+
getConfig: filtersConfigRD$,
155186
getConfigurationSearchConfig: jasmine.createSpy('getConfigurationSearchConfig'),
156187
getCurrentConfiguration: jasmine.createSpy('getCurrentConfiguration'),
157188
getCurrentScope: jasmine.createSpy('getCurrentScope'),
@@ -273,6 +304,15 @@ describe('SearchComponent', () => {
273304
}));
274305
}));
275306

307+
it('should retrieve Search Filters', fakeAsync(() => {
308+
fixture.detectChanges();
309+
tick(100);
310+
const expectedResults = resultFiltersConfigRD;
311+
expect(comp.filtersRD$).toBeObservable(cold('b', {
312+
b: expectedResults
313+
}));
314+
}));
315+
276316
it('should emit resultFound event', fakeAsync(() => {
277317
spyOn(comp.resultFound, 'emit');
278318
const expectedResults = mockSearchResults;

src/app/shared/search/search.component.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { SelectionConfig } from './search-results/search-results.component';
4141
import { ListableObject } from '../object-collection/shared/listable-object.model';
4242
import { CollectionElementLinkType } from '../object-collection/collection-element-link.type';
4343
import { SearchManager } from '../../core/browse/search-manager';
44+
import { SearchFilterConfig } from './models/search-filter-config.model';
4445

4546
@Component({
4647
selector: 'ds-search',
@@ -192,7 +193,12 @@ export class SearchComponent implements OnInit, OnDestroy {
192193
/**
193194
* Defines whether to show the toggle button to Show/Hide chart
194195
*/
195-
@Input() showChartsToggle = false;
196+
@Input() showChartsToggle = false;
197+
198+
/**
199+
* For chart regular expression
200+
*/
201+
chartReg = new RegExp(/^chart./, 'i');
196202

197203
/**
198204
* The current configuration used during the search
@@ -214,6 +220,16 @@ export class SearchComponent implements OnInit, OnDestroy {
214220
*/
215221
currentSortOptions$: BehaviorSubject<SortOptions> = new BehaviorSubject<SortOptions>(null);
216222

223+
/**
224+
* An observable containing configuration about which filters are shown and how they are shown
225+
*/
226+
filtersRD$: BehaviorSubject<RemoteData<SearchFilterConfig[]>> = new BehaviorSubject<RemoteData<SearchFilterConfig[]>>(null);
227+
228+
/**
229+
* Maintains the last search options, so it can be used in refresh
230+
*/
231+
lastSearchOptions: PaginatedSearchOptions;
232+
217233
/**
218234
* The current search results
219235
*/
@@ -356,6 +372,7 @@ export class SearchComponent implements OnInit, OnDestroy {
356372
this.initialized$.next(true);
357373
// retrieve results
358374
this.retrieveSearchResults(newSearchOptions);
375+
this.retrieveFilters(searchOptions);
359376
}
360377
});
361378
}
@@ -406,13 +423,33 @@ export class SearchComponent implements OnInit, OnDestroy {
406423
return this.searchConfigService.paginatedSearchOptions;
407424
}
408425

426+
/**
427+
* Retrieve search filters by the given search options
428+
* @param searchOptions
429+
* @private
430+
*/
431+
private retrieveFilters(searchOptions: PaginatedSearchOptions) {
432+
this.filtersRD$.next(null);
433+
this.service.getConfig(searchOptions.scope, searchOptions.configuration).pipe(
434+
getFirstCompletedRemoteData(),
435+
map((rd: RemoteData<SearchFilterConfig[]>) => Object.assign(rd, {
436+
payload: rd.payload.filter((entry: SearchFilterConfig) =>
437+
!this.chartReg.test(entry.filterType)
438+
)})
439+
)
440+
).subscribe((filtersRD: RemoteData<SearchFilterConfig[]>) => {
441+
this.filtersRD$.next(filtersRD);
442+
});
443+
}
444+
409445
/**
410446
* Retrieve search result by the given search options
411447
* @param searchOptions
412448
* @private
413449
*/
414450
private retrieveSearchResults(searchOptions: PaginatedSearchOptions) {
415451
this.resultsRD$.next(null);
452+
this.lastSearchOptions = searchOptions;
416453

417454
if (this.projection) {
418455
searchOptions = Object.assign(new PaginatedSearchOptions({}), searchOptions, {

0 commit comments

Comments
 (0)