Skip to content

Commit 1f42f92

Browse files
111731: Hide the search facets when there are no facet suggestions & the applied filters of that facet don't have the operator equals, authority or range (because those should be displayed in the facets)
1 parent 28088bc commit 1f42f92

5 files changed

Lines changed: 152 additions & 29 deletions

File tree

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

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils
2424
import { AppliedFilter } from '../../../models/applied-filter.model';
2525
import { FacetValues } from '../../../models/facet-values.model';
2626
import { SearchFilterServiceStub } from '../../../../testing/search-filter-service.stub';
27+
import { cold } from 'jasmine-marbles';
28+
import { PageInfo } from '../../../../../core/shared/page-info.model';
2729

2830
describe('SearchFacetFilterComponent', () => {
2931
let comp: SearchFacetFilterComponent;
@@ -32,34 +34,47 @@ describe('SearchFacetFilterComponent', () => {
3234
const value1 = 'testvalue1';
3335
const value2 = 'test2';
3436
const value3 = 'another value3';
37+
const value4 = '52d629dc-7d2f-47b9-aa2d-258b92e45ae1';
3538
const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
3639
name: filterName1,
3740
filterType: FilterType.text,
3841
hasFacets: false,
3942
isOpenByDefault: false,
4043
pageSize: 2
4144
});
45+
const appliedFilter1: AppliedFilter = Object.assign(new AppliedFilter(), {
46+
filter: filterName1,
47+
operator: 'equals',
48+
label: value1,
49+
value: value1,
50+
});
51+
const appliedFilter2: AppliedFilter = Object.assign(new AppliedFilter(), {
52+
filter: filterName1,
53+
operator: 'equals',
54+
label: value2,
55+
value: value2,
56+
});
57+
const appliedFilter3: AppliedFilter = Object.assign(new AppliedFilter(), {
58+
filter: filterName1,
59+
operator: 'equals',
60+
label: value3,
61+
value: value3,
62+
});
63+
const appliedFilter4: AppliedFilter = Object.assign(new AppliedFilter(), {
64+
filter: filterName1,
65+
operator: 'notauthority',
66+
label: value4,
67+
value: value4,
68+
});
4269
const values: Partial<FacetValues> = {
4370
appliedFilters: [
44-
{
45-
filter: filterName1,
46-
operator: 'equals',
47-
label: value1,
48-
value: value1,
49-
},
50-
{
51-
filter: filterName1,
52-
operator: 'equals',
53-
label: value2,
54-
value: value2,
55-
},
56-
{
57-
filter: filterName1,
58-
operator: 'equals',
59-
label: value3,
60-
value: value3,
61-
}
62-
]
71+
appliedFilter1,
72+
appliedFilter2,
73+
appliedFilter3,
74+
],
75+
pageInfo: Object.assign(new PageInfo(), {
76+
currentPage: 0,
77+
}),
6378
};
6479

6580
const searchLink = '/search';
@@ -205,4 +220,26 @@ describe('SearchFacetFilterComponent', () => {
205220
expect(comp.filter).toEqual('');
206221
});
207222
});
223+
224+
describe('when new values are detected for a filter', () => {
225+
let selectedValues$: BehaviorSubject<AppliedFilter[]>;
226+
227+
beforeEach(() => {
228+
selectedValues$ = new BehaviorSubject([appliedFilter1, appliedFilter2, appliedFilter3]);
229+
spyOn(searchService, 'getSelectedValuesForFilter').and.returnValue(selectedValues$);
230+
comp.ngOnInit();
231+
});
232+
233+
it('should updated the selectedAppliedFilters$ when they are AppliedFilters that should be displayed in the search facets', () => {
234+
expect(comp.selectedAppliedFilters$).toBeObservable(cold('a', {
235+
a: [appliedFilter1, appliedFilter2, appliedFilter3],
236+
}));
237+
238+
selectedValues$.next([appliedFilter1, appliedFilter2, appliedFilter3, appliedFilter4]);
239+
240+
expect(comp.selectedAppliedFilters$).toBeObservable(cold('a', {
241+
a: [appliedFilter1, appliedFilter2, appliedFilter3],
242+
}));
243+
});
244+
});
208245
});

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ import { currentPath } from '../../../../utils/route.utils';
2020
import { FacetValues } from '../../../models/facet-values.model';
2121
import { AppliedFilter } from '../../../models/applied-filter.model';
2222

23+
/**
24+
* The operators the {@link AppliedFilter} should have in order to be shown in the facets
25+
*/
26+
export const FACET_OPERATORS: string[] = [
27+
'equals',
28+
'authority',
29+
'range',
30+
];
31+
2332
@Component({
2433
selector: 'ds-search-facet-filter',
2534
template: ``,
@@ -104,7 +113,10 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
104113
this.searchOptions$.subscribe(() => this.updateFilterValueList()),
105114
this.retrieveFilterValues().subscribe(),
106115
);
107-
this.selectedAppliedFilters$ = this.searchService.getSelectedValuesForFilter(this.filterConfig.name);
116+
this.selectedAppliedFilters$ = this.searchService.getSelectedValuesForFilter(this.filterConfig.name).pipe(
117+
map((allAppliedFilters: AppliedFilter[]) => allAppliedFilters.filter((appliedFilter: AppliedFilter) => FACET_OPERATORS.includes(appliedFilter.operator))),
118+
distinctUntilChanged((previous: AppliedFilter[], next: AppliedFilter[]) => JSON.stringify(previous) === JSON.stringify(next)),
119+
);
108120
}
109121

110122
/**

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

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2+
import { RouterModule } from '@angular/router';
23

34
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
4-
import { RouterTestingModule } from '@angular/router/testing';
55
import { TranslateModule } from '@ngx-translate/core';
66
import { Observable, of as observableOf } from 'rxjs';
77
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -16,10 +16,22 @@ import { SequenceService } from '../../../../core/shared/sequence.service';
1616
import { BrowserOnlyMockPipe } from '../../../testing/browser-only-mock.pipe';
1717
import { SearchServiceStub } from '../../../testing/search-service.stub';
1818
import { SearchFilterServiceStub } from '../../../testing/search-filter-service.stub';
19+
import { cold } from 'jasmine-marbles';
20+
import { AppliedFilter } from '../../models/applied-filter.model';
21+
import { FacetValues } from '../../models/facet-values.model';
22+
import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
1923

2024
describe('SearchFilterComponent', () => {
2125
let comp: SearchFilterComponent;
2226
let fixture: ComponentFixture<SearchFilterComponent>;
27+
28+
const appliedFilter1: AppliedFilter = Object.assign(new AppliedFilter(), {
29+
operator: 'equals',
30+
});
31+
const appliedFilter2: AppliedFilter = Object.assign(new AppliedFilter(), {
32+
operator: 'notauthority',
33+
});
34+
2335
const filterName1 = 'test name';
2436

2537
const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), {
@@ -30,24 +42,29 @@ describe('SearchFilterComponent', () => {
3042
});
3143
let searchFilterService: SearchFilterServiceStub;
3244
let sequenceService;
33-
const mockResults = observableOf(['test', 'data']);
3445
let searchService: SearchServiceStub;
46+
let searchConfigurationService: SearchConfigurationServiceStub;
3547

3648
beforeEach(waitForAsync(() => {
3749
searchFilterService = new SearchFilterServiceStub();
3850
searchService = new SearchServiceStub();
51+
searchConfigurationService = new SearchConfigurationServiceStub();
3952
sequenceService = jasmine.createSpyObj('sequenceService', { next: 17 });
4053

4154
TestBed.configureTestingModule({
42-
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule],
55+
imports: [
56+
NoopAnimationsModule,
57+
RouterModule.forRoot([]),
58+
TranslateModule.forRoot(),
59+
],
4360
declarations: [
4461
SearchFilterComponent,
4562
BrowserOnlyMockPipe,
4663
],
4764
providers: [
4865
{ provide: SearchService, useValue: searchService },
4966
{ provide: SearchFilterService, useValue: searchFilterService },
50-
{ provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() },
67+
{ provide: SEARCH_CONFIG_SERVICE, useValue: searchConfigurationService },
5168
{ provide: SequenceService, useValue: sequenceService },
5269
],
5370
schemas: [CUSTOM_ELEMENTS_SCHEMA],
@@ -57,7 +74,6 @@ describe('SearchFilterComponent', () => {
5774
}));
5875

5976
beforeEach(() => {
60-
spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockResults);
6177
fixture = TestBed.createComponent(SearchFilterComponent);
6278
comp = fixture.componentInstance; // SearchPageComponent test instance
6379
comp.filter = mockFilterConfig;
@@ -121,4 +137,59 @@ describe('SearchFilterComponent', () => {
121137
sub.unsubscribe();
122138
});
123139
});
140+
141+
describe('isActive', () => {
142+
it('should return true when there are facet value suggestions & no valid applied values', () => {
143+
spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), {
144+
pageInfo: {
145+
totalElements: 5,
146+
},
147+
} as FacetValues)));
148+
comp.appliedFilters$ = observableOf([appliedFilter2]);
149+
150+
expect(comp.isActive()).toBeObservable(cold('(tt)', {
151+
t: true,
152+
}));
153+
});
154+
155+
it('should return false when there are no facet value suggestions & no valid applied values', () => {
156+
spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), {
157+
pageInfo: {
158+
totalElements: 0,
159+
},
160+
} as FacetValues)));
161+
comp.appliedFilters$ = observableOf([appliedFilter2]);
162+
163+
expect(comp.isActive()).toBeObservable(cold('(tf)', {
164+
t: true,
165+
f: false,
166+
}));
167+
});
168+
169+
it('should return true when there are no facet value suggestions & but there are valid applied values', () => {
170+
spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), {
171+
pageInfo: {
172+
totalElements: 0,
173+
},
174+
} as FacetValues)));
175+
comp.appliedFilters$ = observableOf([appliedFilter1, appliedFilter2]);
176+
177+
expect(comp.isActive()).toBeObservable(cold('(tt)', {
178+
t: true,
179+
}));
180+
});
181+
182+
it('should return true when there are facet value suggestions & there are valid applied values', () => {
183+
spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), {
184+
pageInfo: {
185+
totalElements: 5,
186+
},
187+
} as FacetValues)));
188+
comp.appliedFilters$ = observableOf([appliedFilter1, appliedFilter2]);
189+
190+
expect(comp.isActive()).toBeObservable(cold('(tt)', {
191+
t: true,
192+
}));
193+
});
194+
});
124195
});

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { FacetValues } from '../../models/facet-values.model';
1515
import { RemoteData } from '../../../../core/data/remote-data';
1616
import { AppliedFilter } from '../../models/applied-filter.model';
1717
import { SearchOptions } from '../../models/search-options.model';
18+
import { FACET_OPERATORS } from './search-facet-filter/search-facet-filter.component';
1819

1920
@Component({
2021
selector: 'ds-search-filter',
@@ -166,13 +167,13 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
166167
* Check if a given filter is supposed to be shown or not
167168
* @returns {Observable<boolean>} Emits true whenever a given filter config should be shown
168169
*/
169-
private isActive(): Observable<boolean> {
170+
isActive(): Observable<boolean> {
170171
return combineLatest([
171172
this.appliedFilters$,
172173
this.searchConfigService.searchOptions,
173174
]).pipe(
174175
switchMap(([selectedValues, options]: [AppliedFilter[], SearchOptions]) => {
175-
if (isNotEmpty(selectedValues)) {
176+
if (isNotEmpty(selectedValues.filter((appliedFilter: AppliedFilter) => FACET_OPERATORS.includes(appliedFilter.operator)))) {
176177
return observableOf(true);
177178
} else {
178179
return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe(

src/app/shared/testing/search-configuration-service.stub.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {
44
FilterConfig,
55
SearchConfig,
66
} from '../../core/shared/search/search-filters/search-config.model';
7+
import { SearchOptions } from '../search/models/search-options.model';
8+
import { PaginatedSearchOptions } from '../search/models/paginated-search-options.model';
79

810
/**
911
* Stub class of {@link SearchConfigurationService}
@@ -12,8 +14,8 @@ export class SearchConfigurationServiceStub {
1214

1315
public paginationID = 'test-id';
1416

15-
private searchOptions: BehaviorSubject<any> = new BehaviorSubject<any>({});
16-
private paginatedSearchOptions: BehaviorSubject<any> = new BehaviorSubject<any>({});
17+
public searchOptions: BehaviorSubject<SearchOptions> = new BehaviorSubject(new SearchOptions({}));
18+
public paginatedSearchOptions: BehaviorSubject<PaginatedSearchOptions> = new BehaviorSubject(new PaginatedSearchOptions({}));
1719

1820
getCurrentFrontendFilters() {
1921
return observableOf([]);

0 commit comments

Comments
 (0)