Commits
Giuseppe Digilio authored ac36cc20dcf
1 + | import { animate, state, style, transition, trigger } from '@angular/animations'; |
2 + | import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
3 + | import { Router } from '@angular/router'; |
4 + | |
1 5 | import { |
2 6 | BehaviorSubject, |
3 7 | combineLatest as observableCombineLatest, |
4 8 | Observable, |
5 9 | of as observableOf, |
6 10 | Subject, |
7 11 | Subscription |
8 12 | } from 'rxjs'; |
9 - | import { distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators'; |
10 - | import { animate, state, style, transition, trigger } from '@angular/animations'; |
11 - | import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
12 - | import { Router } from '@angular/router'; |
13 + | import { distinctUntilChanged, filter, map, mergeMap, switchMap, take, tap } from 'rxjs/operators'; |
14 + | |
13 15 | import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; |
14 16 | import { PaginatedList } from '../../../../../core/data/paginated-list.model'; |
15 17 | import { RemoteData } from '../../../../../core/data/remote-data'; |
16 18 | import { hasNoValue, hasValue, isNotEmpty } from '../../../../empty.util'; |
17 19 | import { EmphasizePipe } from '../../../../utils/emphasize.pipe'; |
18 20 | import { FacetValue } from '../../../models/facet-value.model'; |
19 21 | import { SearchFilterConfig } from '../../../models/search-filter-config.model'; |
20 22 | import { SearchService } from '../../../../../core/shared/search/search.service'; |
21 23 | import { |
22 24 | FILTER_CONFIG, |
25 27 | SearchFilterService |
26 28 | } from '../../../../../core/shared/search/search-filter.service'; |
27 29 | import { SearchConfigurationService } from '../../../../../core/shared/search/search-configuration.service'; |
28 30 | import { getFirstSucceededRemoteData } from '../../../../../core/shared/operators'; |
29 31 | import { InputSuggestion } from '../../../../input-suggestions/input-suggestions.model'; |
30 32 | import { SearchOptions } from '../../../models/search-options.model'; |
31 33 | import { SEARCH_CONFIG_SERVICE } from '../../../../../my-dspace-page/my-dspace-page.component'; |
32 34 | import { currentPath } from '../../../../utils/route.utils'; |
33 35 | import { getFacetValueForType, stripOperatorFromFilterValue } from '../../../search.utils'; |
34 36 | import { createPendingRemoteDataObject } from '../../../../remote-data.utils'; |
37 + | import { FacetValues } from '../../../models/facet-values.model'; |
35 38 | |
36 39 | @Component({ |
37 40 | selector: 'ds-search-facet-filter', |
38 41 | template: ``, |
39 42 | }) |
40 43 | |
41 44 | /** |
42 45 | * Super class for all different representations of facets |
43 46 | */ |
44 47 | export class SearchFacetFilterComponent implements OnInit, OnDestroy { |
69 72 | |
70 73 | /** |
71 74 | * Emits the result values for this filter found by the current filter query |
72 75 | */ |
73 76 | filterSearchResults: Observable<InputSuggestion[]> = observableOf([]); |
74 77 | |
75 78 | /** |
76 79 | * Emits the active values for this filter |
77 80 | */ |
78 81 | selectedValues$: Observable<FacetValue[]>; |
82 + | |
79 83 | protected collapseNextUpdate = true; |
80 84 | |
81 85 | /** |
82 86 | * State of the requested facets used to time the animation |
83 87 | */ |
84 88 | animationState = 'loading'; |
85 89 | |
86 90 | /** |
87 91 | * Emits all current search options available in the search URL |
88 92 | */ |
277 281 | |
278 282 | protected retrieveFilterValues(useCachedVersionIfAvailable = true) { |
279 283 | const facetValues$ = observableCombineLatest([this.searchOptions$, this.currentPage]).pipe( |
280 284 | map(([options, page]) => { |
281 285 | return { options, page }; |
282 286 | }), |
283 287 | switchMap(({ options, page }) => { |
284 288 | return this.searchService.getFacetValuesFor(this.filterConfig, page, options, null, useCachedVersionIfAvailable) |
285 289 | .pipe( |
286 290 | getFirstSucceededRemoteData(), |
287 - | map((results) => { |
288 - | return { |
289 - | values: observableOf(results), |
290 - | page: page |
291 - | }; |
292 - | } |
291 + | tap((rd: RemoteData<FacetValues>) => { |
292 + | this.isLastPage$.next(hasNoValue(rd?.payload?.next)); |
293 + | }), |
294 + | map((rd: RemoteData<FacetValues>) => ({ |
295 + | values: observableOf(rd), |
296 + | page: page |
297 + | }) |
293 298 | ) |
294 299 | ); |
295 300 | }) |
296 301 | ); |
297 302 | |
298 303 | let filterValues = []; |
299 - | this.subs.push(facetValues$.subscribe((facetOutcome) => { |
300 - | const newValues$ = facetOutcome.values; |
301 - | |
302 - | if (this.collapseNextUpdate) { |
303 - | this.showFirstPageOnly(); |
304 - | facetOutcome.page = 1; |
305 - | this.collapseNextUpdate = false; |
306 - | } |
307 - | if (facetOutcome.page === 1) { |
308 - | filterValues = []; |
309 - | } |
310 - | |
311 - | filterValues = [filterValues, newValues$]; |
312 - | |
313 - | this.subs.push(this.rdbs.aggregate(filterValues).pipe( |
304 + | this.subs.push( |
305 + | facetValues$.pipe( |
306 + | mergeMap((facetOutcome) => { |
307 + | const newValues$ = facetOutcome.values; |
308 + | |
309 + | if (this.collapseNextUpdate) { |
310 + | this.showFirstPageOnly(); |
311 + | facetOutcome.page = 1; |
312 + | this.collapseNextUpdate = false; |
313 + | } |
314 + | if (facetOutcome.page === 1) { |
315 + | filterValues = []; |
316 + | } |
317 + | |
318 + | filterValues = [filterValues, newValues$]; |
319 + | |
320 + | return this.rdbs.aggregate(filterValues); |
321 + | }), |
314 322 | tap((rd: RemoteData<PaginatedList<FacetValue>[]>) => { |
315 323 | this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig).pipe( |
316 324 | map((selectedValues) => { |
317 325 | return selectedValues.map((value: string) => { |
318 - | const fValue = [].concat(rd.payload.map((page) => page.page)).find((facetValue: FacetValue) => this.getFacetValue(facetValue) === value); |
326 + | const fValue = [].concat(rd.payload.map((page) => page.page)) |
327 + | .find((facetValue: FacetValue) => this.getFacetValue(facetValue) === value); |
319 328 | if (hasValue(fValue)) { |
320 329 | return fValue; |
321 330 | } |
322 331 | const filterValue = stripOperatorFromFilterValue(value); |
323 332 | return Object.assign(new FacetValue(), { label: filterValue, value: filterValue }); |
324 333 | }); |
325 334 | }) |
326 335 | ); |
327 336 | }) |
328 337 | ).subscribe((rd: RemoteData<PaginatedList<FacetValue>[]>) => { |
329 338 | this.animationState = 'ready'; |
330 339 | this.filterValues$.next(rd); |
331 - | |
332 - | })); |
333 - | this.subs.push(newValues$.pipe(take(1)).subscribe((rd) => { |
334 - | this.isLastPage$.next(hasNoValue(rd.payload.next)); |
335 - | })); |
336 - | })); |
340 + | }) |
341 + | ); |
337 342 | } |
338 343 | |
339 344 | /** |
340 345 | * Transforms the facet value string, so if the query matches part of the value, it's emphasized in the value |
341 346 | * @param {FacetValue} facet The value of the facet as returned by the server |
342 347 | * @param {string} query The query that was used to search facet values |
343 348 | * @returns {string} The facet value with the query part emphasized |
344 349 | */ |
345 350 | getDisplayValue(facet: FacetValue, query: string): string { |
346 351 | return new EmphasizePipe().transform(facet.value, query) + ' (' + facet.count + ')'; |