From 49cb77659aa632de7c6491f755c24729c2631e60 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Tue, 7 May 2024 10:32:55 +0200 Subject: [PATCH] 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) --- .../search-facet-filter.component.ts | 9 +++ .../search-filter.component.spec.ts | 75 ++++++++++++++++++- .../search-filter/search-filter.component.ts | 7 +- .../search-configuration-service.stub.ts | 6 +- 4 files changed, 89 insertions(+), 8 deletions(-) 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 e085d3e6678..b4fad80493b 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 @@ -20,6 +20,15 @@ import { currentPath } from '../../../../utils/route.utils'; import { FacetValues } from '../../../models/facet-values.model'; import { AppliedFilter } from '../../../models/applied-filter.model'; +/** + * The operators the {@link AppliedFilter} should have in order to be shown in the facets + */ +export const FACET_OPERATORS: string[] = [ + 'equals', + 'authority', + 'range', +]; + @Component({ selector: 'ds-search-facet-filter', template: ``, diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts index 3404d3def81..964f0de4474 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed, waitForAsync, fakeAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; @@ -16,10 +16,22 @@ import { SequenceService } from '../../../../core/shared/sequence.service'; import { BrowserOnlyMockPipe } from '../../../testing/browser-only-mock.pipe'; import { SearchServiceStub } from '../../../testing/search-service.stub'; import { SearchFilterServiceStub } from '../../../testing/search-filter-service.stub'; +import { cold } from 'jasmine-marbles'; +import { AppliedFilter } from '../../models/applied-filter.model'; +import { FacetValues } from '../../models/facet-values.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils'; describe('SearchFilterComponent', () => { let comp: SearchFilterComponent; let fixture: ComponentFixture; + + const appliedFilter1: AppliedFilter = Object.assign(new AppliedFilter(), { + operator: 'equals', + }); + const appliedFilter2: AppliedFilter = Object.assign(new AppliedFilter(), { + operator: 'notauthority', + }); + const filterName1 = 'test name'; const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { @@ -30,12 +42,13 @@ describe('SearchFilterComponent', () => { }); let searchFilterService: SearchFilterServiceStub; let sequenceService; - const mockResults = observableOf(['test', 'data']); let searchService: SearchServiceStub; + let searchConfigurationService: SearchConfigurationServiceStub; beforeEach(waitForAsync(() => { searchFilterService = new SearchFilterServiceStub(); searchService = new SearchServiceStub(); + searchConfigurationService = new SearchConfigurationServiceStub(); sequenceService = jasmine.createSpyObj('sequenceService', { next: 17 }); TestBed.configureTestingModule({ @@ -47,7 +60,7 @@ describe('SearchFilterComponent', () => { providers: [ { provide: SearchService, useValue: searchService }, { provide: SearchFilterService, useValue: searchFilterService }, - { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, + { provide: SEARCH_CONFIG_SERVICE, useValue: searchConfigurationService }, { provide: SequenceService, useValue: sequenceService }, ], schemas: [CUSTOM_ELEMENTS_SCHEMA], @@ -57,7 +70,6 @@ describe('SearchFilterComponent', () => { })); beforeEach(() => { - spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockResults); fixture = TestBed.createComponent(SearchFilterComponent); comp = fixture.componentInstance; // SearchPageComponent test instance comp.filter = mockFilterConfig; @@ -121,4 +133,59 @@ describe('SearchFilterComponent', () => { sub.unsubscribe(); }); }); + + describe('isActive', () => { + it('should return true when there are facet value suggestions & no valid applied values', fakeAsync(() => { + spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), { + pageInfo: { + totalElements: 5, + }, + } as FacetValues))); + comp.appliedFilters$ = observableOf([appliedFilter2]); + + expect(comp.isActive()).toBeObservable(cold('(tt)', { + t: true, + })); + })); + + it('should return false when there are no facet value suggestions & no valid applied values', () => { + spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), { + pageInfo: { + totalElements: 0, + }, + } as FacetValues))); + comp.appliedFilters$ = observableOf([appliedFilter2]); + + expect(comp.isActive()).toBeObservable(cold('(tf)', { + t: true, + f: false, + })); + }); + + it('should return true when there are no facet value suggestions & but there are valid applied values', (() => { + spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), { + pageInfo: { + totalElements: 0, + }, + } as FacetValues))); + comp.appliedFilters$ = observableOf([appliedFilter1, appliedFilter2]); + + expect(comp.isActive()).toBeObservable(cold('(tt)', { + t: true, + })); + })); + + it('should return true when there are facet value suggestions & there are valid applied values', (() => { + spyOn(searchService, 'getFacetValuesFor').and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new FacetValues(), { + pageInfo: { + totalElements: 5, + }, + } as FacetValues))); + comp.appliedFilters$ = observableOf([appliedFilter1, appliedFilter2]); + + expect(comp.isActive()).toBeObservable(cold('(tt)', { + t: true, + })); + })); + }); }); 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 e595187dc1d..1edc2d9d8e5 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 @@ -15,6 +15,7 @@ import { FacetValues } from '../../models/facet-values.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { AppliedFilter } from '../../models/applied-filter.model'; import { SearchOptions } from '../../models/search-options.model'; +import { FACET_OPERATORS } from './search-facet-filter/search-facet-filter.component'; @Component({ selector: 'ds-search-filter', @@ -166,15 +167,17 @@ export class SearchFilterComponent implements OnInit, OnDestroy { * Check if a given filter is supposed to be shown or not * @returns {Observable} Emits true whenever a given filter config should be shown */ - private isActive(): Observable { + isActive(): Observable { return combineLatest([ this.appliedFilters$, this.searchConfigService.searchOptions, ]).pipe( switchMap(([selectedValues, options]: [AppliedFilter[], SearchOptions]) => { - if (isNotEmpty(selectedValues)) { + console.log('switchmap', selectedValues, isNotEmpty(selectedValues.filter((appliedFilter: AppliedFilter) => FACET_OPERATORS.includes(appliedFilter.operator)))); + if (isNotEmpty(selectedValues.filter((appliedFilter: AppliedFilter) => FACET_OPERATORS.includes(appliedFilter.operator)))) { return observableOf(true); } else { + console.log(this.searchService.getFacetValuesFor(this.filter, 1, options)); return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe( filter((RD: RemoteData) => !RD.isLoading), map((valuesRD: RemoteData) => { diff --git a/src/app/shared/testing/search-configuration-service.stub.ts b/src/app/shared/testing/search-configuration-service.stub.ts index cc874a0e4fb..f1985b5c826 100644 --- a/src/app/shared/testing/search-configuration-service.stub.ts +++ b/src/app/shared/testing/search-configuration-service.stub.ts @@ -4,6 +4,8 @@ import { FilterConfig, SearchConfig, } from '../../core/shared/search/search-filters/search-config.model'; +import { SearchOptions } from '../search/models/search-options.model'; +import { PaginatedSearchOptions } from '../search/models/paginated-search-options.model'; /** * Stub class of {@link SearchConfigurationService} @@ -12,8 +14,8 @@ export class SearchConfigurationServiceStub { public paginationID = 'test-id'; - private searchOptions: BehaviorSubject = new BehaviorSubject({}); - private paginatedSearchOptions: BehaviorSubject = new BehaviorSubject({}); + public searchOptions: BehaviorSubject = new BehaviorSubject(new SearchOptions({})); + public paginatedSearchOptions: BehaviorSubject = new BehaviorSubject(new PaginatedSearchOptions({})); getCurrentFrontendFilters() { return observableOf([]);