From fc73fc1d3ea8b497390aafe7a7e55a61e5c6eef0 Mon Sep 17 00:00:00 2001 From: lotte <lotte_hofstede@hotmail.com> Date: Wed, 20 Mar 2019 16:57:55 +0100 Subject: [PATCH] optimizations links in facets --- package.json | 1 + .../search-boolean-filter.component.html | 20 +---- .../search-facet-option.component.html | 9 ++ .../search-facet-option.component.ts | 78 ++++++++++++++++ .../search-facet-range-option.component.html | 8 ++ .../search-facet-range-option.component.ts | 88 +++++++++++++++++++ ...earch-facet-selected-option.component.html | 6 ++ .../search-facet-selected-option.component.ts | 67 ++++++++++++++ ...search-facet-filter-wrapper.component.html | 2 +- .../search-facet-filter-wrapper.component.ts | 6 +- .../search-facet-filter.component.ts | 4 + .../search-filter/search-filter.actions.ts | 20 ++--- .../search-filter.component.html | 6 +- .../search-filter/search-filter.component.ts | 75 ++++++++++------ .../search-filter/search-filter.reducer.ts | 37 +++----- .../search-filter.service.spec.ts | 20 ++--- .../search-filter/search-filter.service.ts | 40 ++++----- .../search-hierarchy-filter.component.html | 13 +-- .../search-range-filter.component.html | 9 +- .../search-range-filter.component.ts | 30 ++----- .../search-text-filter.component.html | 14 +-- .../search-filters.component.html | 2 +- .../search-filters.component.ts | 32 +------ src/app/+search-page/search-page.component.ts | 1 - src/app/+search-page/search-page.module.ts | 9 ++ src/app/shared/services/route.service.ts | 9 +- src/main.browser.ts | 1 + yarn.lock | 43 +++++++++ 28 files changed, 445 insertions(+), 205 deletions(-) create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts diff --git a/package.json b/package.json index fd037de3f7..7f319d9716 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "pem": "1.12.3", "reflect-metadata": "0.1.12", "rxjs": "6.2.2", + "rxjs-spy": "^7.5.1", "sortablejs": "1.7.0", "text-mask-core": "5.0.1", "ts-loader": "^5.2.1", diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html index 216683c122..06154916b2 100644 --- a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html @@ -1,24 +1,10 @@ <div> <div class="filters py-2"> - <a *ngFor="let value of (selectedValues | async)" class="d-flex flex-row" - [routerLink]="[getSearchLink()]" - [queryParams]="getRemoveParams(value) | async" queryParamsHandling="merge"> - <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/> - <span class="filter-value pl-1">{{value}}</span> - </a> + <ds-search-facet-selected-option *ngFor="let value of (selectedValues | async)" [selectedValue]="value" [filterConfig]="filterConfig"></ds-search-facet-selected-option> <ng-container *ngFor="let page of (filterValues$ | async)?.payload"> <div [@facetLoad]="animationState"> - <ng-container *ngFor="let value of page.page; trackBy: trackUpdate"> - <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row" - [routerLink]="[getSearchLink()]" - [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge"> - <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> - <span class="filter-value px-1">{{value.value}}</span> - <span class="float-right filter-value-count ml-auto"> - <span class="badge badge-secondary badge-pill">{{value.count}}</span> - </span> - </a> - </ng-container> + <ds-search-facet-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value"> + </ds-search-facet-option> </div> </ng-container> <div class="clearfix toggle-more-filters"> diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html new file mode 100644 index 0000000000..881fb98dcb --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html @@ -0,0 +1,9 @@ +<a *ngIf="isVisible" class="d-flex flex-row" + [routerLink]="[getSearchLink()]" + [queryParams]="addQueryParams | async" queryParamsHandling="merge"> + <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> + <span class="filter-value px-1">{{filterValue.value}}</span> + <span class="float-right filter-value-count ml-auto"> + <span class="badge badge-secondary badge-pill">{{filterValue.count}}</span> + </span> +</a> \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts new file mode 100644 index 0000000000..c5896f92b6 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -0,0 +1,78 @@ +import { Observable, of as observableOf } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Component, Input, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { FacetValue } from '../../../../search-service/facet-value.model'; +import { SearchFilterConfig } from '../../../../search-service/search-filter-config.model'; +import { SearchService } from '../../../../search-service/search.service'; +import { SearchFilterService } from '../../search-filter.service'; + +@Component({ + selector: 'ds-search-facet-option', + templateUrl: './search-facet-option.component.html', +}) + +/** + * Represents a single option in a filter facet + */ +export class SearchFacetOptionComponent implements OnInit { + /** + * A single value for this component + */ + @Input() filterValue: FacetValue; + @Input() filterConfig: SearchFilterConfig; + + /** + * Emits the active values for this filter + */ + selectedValues$: Observable<string[]>; + + isVisible: Observable<boolean>; + + addQueryParams; + + constructor(protected searchService: SearchService, + protected filterService: SearchFilterService, + protected router: Router + ) { + } + + /** + * Initializes all observable instance variables and starts listening to them + */ + ngOnInit(): void { + this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig); + this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked)); + this.addQueryParams = this.getAddParams(); + } + + /** + * Checks if a value for this filter is currently active + */ + private isChecked(): Observable<boolean> { + return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.filterValue.value); + } + + /** + * @returns {string} The base path to the search page + */ + getSearchLink() { + return this.searchService.getSearchLink(); + } + + /** + * Calculates the parameters that should change if a given value for this filter would be added to the active filters + * @param {string} value The value that is added for this filter + * @returns {Observable<any>} The changed filter parameters + */ + private getAddParams(): Observable<any> { + return this.selectedValues$.pipe(map((selectedValues) => { + return { + [this.filterConfig.paramName]: [...selectedValues, this.filterValue.value], + page: 1 + }; + })); + } + +} + diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html new file mode 100644 index 0000000000..92e90a00cc --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html @@ -0,0 +1,8 @@ +<a *ngIf="isVisible" class="d-flex flex-row" + [routerLink]="[getSearchLink()]" + [queryParams]="changeQueryParams | async" queryParamsHandling="merge"> + <span class="filter-value px-1">{{filterValue.value}}</span> + <span class="float-right filter-value-count ml-auto"> + <span class="badge badge-secondary badge-pill">{{filterValue.count}}</span> + </span> +</a> \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts new file mode 100644 index 0000000000..0b38ca1845 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts @@ -0,0 +1,88 @@ +import { Observable, of as observableOf } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Component, Input, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { FacetValue } from '../../../../search-service/facet-value.model'; +import { SearchFilterConfig } from '../../../../search-service/search-filter-config.model'; +import { SearchService } from '../../../../search-service/search.service'; +import { SearchFilterService } from '../../search-filter.service'; +import { + RANGE_FILTER_MAX_SUFFIX, + RANGE_FILTER_MIN_SUFFIX +} from '../../search-range-filter/search-range-filter.component'; + +const rangeDelimiter = '-'; + +@Component({ + selector: 'ds-search-facet-range-option', + templateUrl: './search-facet-range-option.component.html', +}) + +/** + * Represents a single option in a filter facet + */ +export class SearchFacetRangeOptionComponent implements OnInit { + /** + * A single value for this component + */ + @Input() filterValue: FacetValue; + @Input() filterConfig: SearchFilterConfig; + + /** + * Emits the active values for this filter + */ + selectedValues$: Observable<string[]>; + + isVisible: Observable<boolean>; + + changeQueryParams; + + constructor(protected searchService: SearchService, + protected filterService: SearchFilterService, + protected router: Router + ) { + } + + /** + * Initializes all observable instance variables and starts listening to them + */ + ngOnInit(): void { + this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig); + this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked)); + this.changeQueryParams = this.getChangeParams(); + } + + /** + * Checks if a value for this filter is currently active + */ + private isChecked(): Observable<boolean> { + return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.filterValue.value); + } + + /** + * @returns {string} The base path to the search page + */ + getSearchLink() { + return this.searchService.getSearchLink(); + } + + + /** + * Calculates the parameters that should change if a given values for this range filter would be changed + * @param {string} value The values that are changed for this filter + * @returns {Observable<any>} The changed filter parameters + */ + getChangeParams() { + const parts = this.filterValue.value.split(rangeDelimiter); + const min = parts.length > 1 ? parts[0].trim() : this.filterValue.value; + const max = parts.length > 1 ? parts[1].trim() : this.filterValue.value; + return observableOf( + { + [this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX]: [min], + [this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX]: [max], + page: 1 + }); + } + +} + diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html new file mode 100644 index 0000000000..7bed620770 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html @@ -0,0 +1,6 @@ +<a class="d-flex flex-row" + [routerLink]="[getSearchLink()]" + [queryParams]="removeQueryParams | async" queryParamsHandling="merge"> + <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/> + <span class="filter-value pl-1">{{selectedValue}}</span> +</a> \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts new file mode 100644 index 0000000000..2fdc490d68 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts @@ -0,0 +1,67 @@ +import { Observable, of as observableOf } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Component, Input, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { FacetValue } from '../../../../search-service/facet-value.model'; +import { SearchFilterConfig } from '../../../../search-service/search-filter-config.model'; +import { SearchService } from '../../../../search-service/search.service'; +import { SearchFilterService } from '../../search-filter.service'; + +@Component({ + selector: 'ds-search-facet-selected-option', + templateUrl: './search-facet-selected-option.component.html', +}) + +/** + * Represents a single option in a filter facet + */ +export class SearchFacetSelectedOptionComponent implements OnInit { + /** + * A single value for this component + */ + @Input() selectedValue: string; + @Input() filterConfig: SearchFilterConfig; + + /** + * Emits the active values for this filter + */ + selectedValues$: Observable<string[]>; + + removeQueryParams; + + constructor(protected searchService: SearchService, + protected filterService: SearchFilterService, + protected router: Router + ) { + } + + /** + * Initializes all observable instance variables and starts listening to them + */ + ngOnInit(): void { + this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig); + this.removeQueryParams = this.getRemoveParams(); + } + + /** + * @returns {string} The base path to the search page + */ + getSearchLink() { + return this.searchService.getSearchLink(); + } + + /** + * Calculates the parameters that should change if a given value for this filter would be removed from the active filters + * @param {string} value The value that is removed for this filter + * @returns {Observable<any>} The changed filter parameters + */ + private getRemoveParams(): Observable<any> { + return this.selectedValues$.pipe(map((selectedValues) => { + return { + [this.filterConfig.paramName]: selectedValues.filter((v) => v !== this.selectedValue), + page: 1 + }; + })); + } +} + diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html index b7e03af473..4a325d9b3c 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html @@ -1 +1 @@ -<ng-container *ngComponentOutlet="getSearchFilter(); injector: objectInjector;"></ng-container> +<ng-container *ngComponentOutlet="searchFilter injector: objectInjector;"></ng-container> \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts index bc088777fa..5b733b52cb 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -3,6 +3,8 @@ import { renderFilterType } from '../search-filter-type-decorator'; import { FilterType } from '../../../search-service/filter-type.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { FILTER_CONFIG } from '../search-filter.service'; +import { GenericConstructor } from '../../../../core/shared/generic-constructor'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; @Component({ selector: 'ds-search-facet-filter-wrapper', @@ -18,6 +20,7 @@ export class SearchFacetFilterWrapperComponent implements OnInit { */ @Input() filterConfig: SearchFilterConfig; + searchFilter: GenericConstructor<SearchFacetFilterComponent>; /** * Injector to inject a child component with the @Input parameters */ @@ -30,6 +33,7 @@ export class SearchFacetFilterWrapperComponent implements OnInit { * Initialize and add the filter config to the injector */ ngOnInit(): void { + this.searchFilter = this.getSearchFilter(); this.objectInjector = Injector.create({ providers: [ { provide: FILTER_CONFIG, useFactory: () => (this.filterConfig), deps: [] } @@ -41,7 +45,7 @@ export class SearchFacetFilterWrapperComponent implements OnInit { /** * Find the correct component based on the filter config's type */ - getSearchFilter() { + private getSearchFilter() { const type: FilterType = this.filterConfig.type; return renderFilterType(type); } diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index f4f835c152..74c2794313 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -85,8 +85,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { * Initializes all observable instance variables and starts listening to them */ ngOnInit(): void { + console.log('renderSearchFacetFilterComponent') + this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined)); this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged()); + this.selectedValues = this.filterService.getSelectedValuesForFilter(this.filterConfig); const searchOptions = this.searchConfigService.searchOptions; this.subs.push(this.searchConfigService.searchOptions.subscribe(() => this.updateFilterValueList())); @@ -190,6 +193,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { * @param data The string from the input field */ onSubmit(data: any) { + console.log('onsubmit'); this.selectedValues.pipe(take(1)).subscribe((selectedValues) => { if (isNotEmpty(data)) { this.router.navigate([this.getSearchLink()], { diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts b/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts index 2e556b32d6..838597e03d 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts @@ -1,6 +1,7 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; +import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; /** * For each action type in an action group, make a simple @@ -12,9 +13,8 @@ import { type } from '../../../shared/ngrx/type'; */ export const SearchFilterActionTypes = { COLLAPSE: type('dspace/search-filter/COLLAPSE'), - INITIAL_COLLAPSE: type('dspace/search-filter/INITIAL_COLLAPSE'), + INITIALIZE: type('dspace/search-filter/INITIALIZE'), EXPAND: type('dspace/search-filter/EXPAND'), - INITIAL_EXPAND: type('dspace/search-filter/INITIAL_EXPAND'), TOGGLE: type('dspace/search-filter/TOGGLE'), DECREMENT_PAGE: type('dspace/search-filter/DECREMENT_PAGE'), INCREMENT_PAGE: type('dspace/search-filter/INCREMENT_PAGE'), @@ -66,15 +66,13 @@ export class SearchFilterToggleAction extends SearchFilterAction { /** * Used to set the initial state of a filter to collapsed */ -export class SearchFilterInitialCollapseAction extends SearchFilterAction { - type = SearchFilterActionTypes.INITIAL_COLLAPSE; -} - -/** - * Used to set the initial state of a filter to expanded - */ -export class SearchFilterInitialExpandAction extends SearchFilterAction { - type = SearchFilterActionTypes.INITIAL_EXPAND; +export class SearchFilterInitializeAction extends SearchFilterAction { + type = SearchFilterActionTypes.INITIALIZE; + initiallyExpanded; + constructor(filter: SearchFilterConfig) { + super(filter.name); + this.initiallyExpanded = filter.isOpenByDefault; + } } /** diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html index 1013bf7e28..e2c128593f 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html @@ -1,7 +1,7 @@ -<div> +<div *ngIf="active$ | async"> <div (click)="toggle()" class="filter-name"><h5 class="d-inline-block mb-0">{{'search.filters.filter.' + filter.name + '.head'| translate}}</h5> <span class="filter-toggle fas float-right" - [ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div> - <div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : collapsed}"> + [ngClass]="(collapsed$ | async) ? 'fa-plus' : 'fa-minus'"></span></div> + <div [@slide]="(collapsed$ | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : closed}"> <ds-search-facet-filter-wrapper [filterConfig]="filter"></ds-search-facet-filter-wrapper> </div> </div> \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts index dcc01f2b46..eaf318655f 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts @@ -1,11 +1,12 @@ - -import { take } from 'rxjs/operators'; +import { filter, first, map, startWith, switchMap, take } from 'rxjs/operators'; import { Component, Input, OnInit } from '@angular/core'; import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { SearchFilterService } from './search-filter.service'; -import { Observable } from 'rxjs'; +import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { slide } from '../../../shared/animations/slide'; import { isNotEmpty } from '../../../shared/empty.util'; +import { SearchService } from '../../search-service/search.service'; +import { SearchConfigurationService } from '../../search-service/search-configuration.service'; @Component({ selector: 'ds-search-filter', @@ -26,9 +27,13 @@ export class SearchFilterComponent implements OnInit { /** * True when the filter is 100% collapsed in the UI */ - collapsed; + closed = true; + collapsed$: Observable<boolean>; + + selectedValues$: Observable<string[]>; + active$: Observable<boolean>; - constructor(private filterService: SearchFilterService) { + constructor(private filterService: SearchFilterService, private searchService: SearchService, private searchConfigService: SearchConfigurationService) { } /** @@ -37,11 +42,13 @@ export class SearchFilterComponent implements OnInit { * Else, the filter should initially be collapsed */ ngOnInit() { - this.getSelectedValues().pipe(take(1)).subscribe((isActive) => { - if (this.filter.isOpenByDefault || isNotEmpty(isActive)) { - this.initialExpand(); - } else { - this.initialCollapse(); + this.selectedValues$ = this.getSelectedValues(); + this.active$ = this.isActive(); + this.collapsed$ = this.isCollapsed(); + this.initializeFilter(); + this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { + if (isNotEmpty(selectedValues)) { + this.filterService.expand(this.filter.name); } }); } @@ -57,30 +64,21 @@ export class SearchFilterComponent implements OnInit { * Checks if the filter is currently collapsed * @returns {Observable<boolean>} Emits true when the current state of the filter is collapsed, false when it's expanded */ - isCollapsed(): Observable<boolean> { + private isCollapsed(): Observable<boolean> { return this.filterService.isCollapsed(this.filter.name); } /** - * Changes the initial state to collapsed - */ - initialCollapse() { - this.filterService.initialCollapse(this.filter.name); - this.collapsed = true; - } - - /** - * Changes the initial state to expanded + * Sets the initial state of the filter */ - initialExpand() { - this.filterService.initialExpand(this.filter.name); - this.collapsed = false; + initializeFilter() { + this.filterService.initializeFilter(this.filter); } /** * @returns {Observable<string[]>} Emits a list of all values that are currently active for this filter */ - getSelectedValues(): Observable<string[]> { + private getSelectedValues(): Observable<string[]> { return this.filterService.getSelectedValuesForFilter(this.filter); } @@ -90,7 +88,7 @@ export class SearchFilterComponent implements OnInit { */ finishSlide(event: any): void { if (event.fromState === 'collapsed') { - this.collapsed = false; + this.closed = false; } } @@ -100,7 +98,32 @@ export class SearchFilterComponent implements OnInit { */ startSlide(event: any): void { if (event.toState === 'collapsed') { - this.collapsed = true; + this.closed = true; } } + + /** + * Check if a given filter is supposed to be shown or not + * @returns {Observable<boolean>} Emits true whenever a given filter config should be shown + */ + private isActive(): Observable<boolean> { + return this.selectedValues$.pipe( + switchMap((isActive) => { + if (isNotEmpty(isActive)) { + return observableOf(true); + } else { + return this.searchConfigService.searchOptions.pipe( + first(), + switchMap((options) => { + return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe( + filter((RD) => !RD.isLoading), + map((valuesRD) => { + return valuesRD.payload.totalElements > 0 + }),) + } + )) + } + }), + startWith(true)); + } } diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts b/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts index f7e064fcc7..187bcd50d0 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts @@ -1,5 +1,9 @@ -import { SearchFilterAction, SearchFilterActionTypes } from './search-filter.actions'; -import { isEmpty } from '../../../shared/empty.util'; +import { + SearchFilterAction, + SearchFilterActionTypes, + SearchFilterInitializeAction +} from './search-filter.actions'; +import { isEmpty, isNotUndefined } from '../../../shared/empty.util'; /** * Interface that represents the state for a single filters @@ -28,27 +32,14 @@ export function filterReducer(state = initialState, action: SearchFilterAction): switch (action.type) { - case SearchFilterActionTypes.INITIAL_COLLAPSE: { - if (isEmpty(state) || isEmpty(state[action.filterName])) { - return Object.assign({}, state, { - [action.filterName]: { - filterCollapsed: true, - page: 1 - } - }); - } - return state; - } - - case SearchFilterActionTypes.INITIAL_EXPAND: { - if (isEmpty(state) || isEmpty(state[action.filterName])) { - return Object.assign({}, state, { - [action.filterName]: { - filterCollapsed: false, - page: 1 - } - }); - } + case SearchFilterActionTypes.INITIALIZE: { + const initAction = (action as SearchFilterInitializeAction); + return Object.assign({}, state, { + [action.filterName]: { + filterCollapsed: !initAction.initiallyExpanded, + page: 1 + } + }); return state; } diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts index 156e8d47ea..306f8cdb96 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts @@ -5,8 +5,7 @@ import { SearchFilterDecrementPageAction, SearchFilterExpandAction, SearchFilterIncrementPageAction, - SearchFilterInitialCollapseAction, - SearchFilterInitialExpandAction, + SearchFilterInitializeAction, SearchFilterResetPageAction, SearchFilterToggleAction } from './search-filter.actions'; @@ -62,25 +61,16 @@ describe('SearchFilterService', () => { service = new SearchFilterService(store, routeServiceStub); }); - describe('when the initialCollapse method is triggered', () => { + describe('when the initializeFilter method is triggered', () => { beforeEach(() => { - service.initialCollapse(mockFilterConfig.name); + service.initializeFilter(mockFilterConfig); }); - it('SearchFilterInitialCollapseAction should be dispatched to the store', () => { - expect(store.dispatch).toHaveBeenCalledWith(new SearchFilterInitialCollapseAction(mockFilterConfig.name)); + it('SearchFilterInitializeAction should be dispatched to the store', () => { + expect(store.dispatch).toHaveBeenCalledWith(new SearchFilterInitializeAction(mockFilterConfig)); }); }); - describe('when the initialExpand method is triggered', () => { - beforeEach(() => { - service.initialExpand(mockFilterConfig.name); - }); - - it('SearchFilterInitialExpandAction should be dispatched to the store', () => { - expect(store.dispatch).toHaveBeenCalledWith(new SearchFilterInitialExpandAction(mockFilterConfig.name)); - }); - }); describe('when the collapse method is triggered', () => { beforeEach(() => { diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts index 34c34ee4cc..5ce1e8e647 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts @@ -1,6 +1,6 @@ import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { Injectable, InjectionToken } from '@angular/core'; -import { distinctUntilChanged, map } from 'rxjs/operators'; +import { distinctUntilChanged, map, tap } from 'rxjs/operators'; import { SearchFiltersState, SearchFilterState } from './search-filter.reducer'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { @@ -8,8 +8,7 @@ import { SearchFilterDecrementPageAction, SearchFilterExpandAction, SearchFilterIncrementPageAction, - SearchFilterInitialCollapseAction, - SearchFilterInitialExpandAction, + SearchFilterInitializeAction, SearchFilterResetPageAction, SearchFilterToggleAction } from './search-filter.actions'; @@ -17,7 +16,9 @@ import { hasValue, isNotEmpty, } from '../../../shared/empty.util'; import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { RouteService } from '../../../shared/services/route.service'; import { Params } from '@angular/router'; - +import { tag } from 'rxjs-spy/operators'; +import { create, detect } from "rxjs-spy"; +const spy = create(); const filterStateSelector = (state: SearchFiltersState) => state.searchFilter; export const FILTER_CONFIG: InjectionToken<SearchFilterConfig> = new InjectionToken<SearchFilterConfig>('filterConfig'); @@ -58,16 +59,21 @@ export class SearchFilterService { * @returns {Observable<string[]>} Emits the active filters for the given filter configuration */ getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable<string[]> { - const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName); + const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName).pipe( + tag("parameter") + ); const prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').pipe( - map((params: Params) => [].concat(...Object.values(params))) + map((params: Params) => [].concat(...Object.values(params))), + tag("prefix-tag") + + ); + spy.log(); + detect('prefix-tag'); return observableCombineLatest(values$, prefixValues$).pipe( map(([values, prefixValues]) => { - console.log('getSelectedValuesForFilter ', values, prefixValues); - - if (isNotEmpty(values)) { + if (isNotEmpty(values)) { return values; } return prefixValues; @@ -138,19 +144,11 @@ export class SearchFilterService { } /** - * Dispatches an initial collapse action to the store for a given filter - * @param {string} filterName The filter for which the action is dispatched - */ - public initialCollapse(filterName: string): void { - this.store.dispatch(new SearchFilterInitialCollapseAction(filterName)); - } - - /** - * Dispatches an initial expand action to the store for a given filter - * @param {string} filterName The filter for which the action is dispatched + * Dispatches an initialize action to the store for a given filter + * @param {SearchFilterConfig} filter The filter for which the action is dispatched */ - public initialExpand(filterName: string): void { - this.store.dispatch(new SearchFilterInitialExpandAction(filterName)); + public initializeFilter(filter: SearchFilterConfig): void { + this.store.dispatch(new SearchFilterInitializeAction(filter)); } /** diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html index 5434f0e0f4..3acc868a17 100644 --- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html @@ -8,17 +8,8 @@ </a> <ng-container *ngFor="let page of (filterValues$ | async)?.payload"> <div [@facetLoad]="animationState"> - <ng-container *ngFor="let value of page.page; trackBy: trackUpdate"> - <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row" - [routerLink]="[getSearchLink()]" - [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge" > - <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> - <span class="filter-value px-1">{{value.value}}</span> - <span class="float-right filter-value-count ml-auto"> - <span class="badge badge-secondary badge-pill">{{value.count}}</span> - </span> - </a> - </ng-container> + <ds-search-facet-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value"> + </ds-search-facet-option> </div> </ng-container> <div class="clearfix toggle-more-filters"> diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index 1cc0556ed5..a30233ece3 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -25,14 +25,7 @@ <ng-container *ngFor="let page of (filterValues$ | async)?.payload"> <div [@facetLoad]="animationState"> <ng-container *ngFor="let value of page.page; trackBy: trackUpdate"> - <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row" - [routerLink]="[getSearchLink()]" - [queryParams]="getChangeParams(value.value) | async" queryParamsHandling="merge"> - <span class="filter-value px-1">{{value.value}}</span> - <span class="float-right filter-value-count ml-auto"> - <span class="badge badge-secondary badge-pill">{{value.count}}</span> - </span> - </a> + </ng-container> </div> </ng-container> diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 6cb04c6c1f..2b6797f5a1 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -28,10 +28,9 @@ import { SearchConfigurationService } from '../../../search-service/search-confi * The route parameter 'id' is used to request the item it represents. * All fields of the item that should be displayed, are defined in its template. */ -const minSuffix = '.min'; -const maxSuffix = '.max'; +export const RANGE_FILTER_MIN_SUFFIX = '.min'; +export const RANGE_FILTER_MAX_SUFFIX = '.max'; const dateFormats = ['YYYY', 'YYYY-MM', 'YYYY-MM-DD']; -const rangeDelimiter = '-'; @Component({ selector: 'ds-search-range-filter', @@ -85,8 +84,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple super.ngOnInit(); this.min = moment(this.filterConfig.minValue, dateFormats).year() || this.min; this.max = moment(this.filterConfig.maxValue, dateFormats).year() || this.max; - const iniMin = this.route.getQueryParameterValue(this.filterConfig.paramName + minSuffix).pipe(startWith(undefined)); - const iniMax = this.route.getQueryParameterValue(this.filterConfig.paramName + maxSuffix).pipe(startWith(undefined)); + const iniMin = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX).pipe(startWith(undefined)); + const iniMax = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX).pipe(startWith(undefined)); this.sub = observableCombineLatest(iniMin, iniMax).pipe( map(([min, max]) => { const minimum = hasValue(min) ? min : this.min; @@ -96,22 +95,7 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple ).subscribe((minmax) => this.range = minmax); } - /** - * Calculates the parameters that should change if a given values for this range filter would be changed - * @param {string} value The values that are changed for this filter - * @returns {Observable<any>} The changed filter parameters - */ - getChangeParams(value: string) { - const parts = value.split(rangeDelimiter); - const min = parts.length > 1 ? parts[0].trim() : value; - const max = parts.length > 1 ? parts[1].trim() : value; - return observableOf( - { - [this.filterConfig.paramName + minSuffix]: [min], - [this.filterConfig.paramName + maxSuffix]: [max], - page: 1 - }); - } + /** * Submits new custom range values to the range filter from the widget @@ -122,8 +106,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple this.router.navigate([this.getSearchLink()], { queryParams: { - [this.filterConfig.paramName + minSuffix]: newMin, - [this.filterConfig.paramName + maxSuffix]: newMax + [this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX]: newMin, + [this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX]: newMax }, queryParamsHandling: 'merge' }); diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html index 32f6fe2153..45034507a2 100644 --- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html @@ -10,15 +10,8 @@ <div [@facetLoad]="animationState"> <ng-container *ngFor="let page of filterValuesRD?.payload"> <ng-container *ngFor="let value of page.page; trackBy: trackUpdate"> - <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row" - [routerLink]="[getSearchLink()]" - [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge" > - <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> - <span class="filter-value px-1">{{value.value}}</span> - <span class="float-right filter-value-count ml-auto"> - <span class="badge badge-secondary badge-pill">{{value.count}}</span> - </span> - </a> + <ds-search-facet-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value"> + </ds-search-facet-option> </ng-container> </ng-container> </div> @@ -40,6 +33,5 @@ (submitSuggestion)="onSubmit($event)" (clickSuggestion)="onClick($event)" (findSuggestions)="findSuggestions($event)" - ngDefaultControl - ></ds-input-suggestions> + ngDefaultControl></ds-input-suggestions> </div> diff --git a/src/app/+search-page/search-filters/search-filters.component.html b/src/app/+search-page/search-filters/search-filters.component.html index de725f0958..ab2a96d752 100644 --- a/src/app/+search-page/search-filters/search-filters.component.html +++ b/src/app/+search-page/search-filters/search-filters.component.html @@ -1,7 +1,7 @@ <h3>{{"search.filters.head" | translate}}</h3> <div *ngIf="(filters | async)?.hasSucceeded"> <div *ngFor="let filter of (filters | async)?.payload; trackBy: trackUpdate"> - <ds-search-filter *ngIf="isActive(filter) | async" class="d-block mb-3 p-3" [filter]="filter"></ds-search-filter> + <ds-search-filter class="d-block mb-3 p-3" [filter]="filter"></ds-search-filter> </div> </div> <a class="btn btn-primary" [routerLink]="[getSearchLink()]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button">{{"search.filters.reset" | translate}}</a> \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index 0d32df4867..1dd747e908 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -1,15 +1,13 @@ -import { Observable, of as observableOf } from 'rxjs'; +import { Observable } from 'rxjs'; -import { filter, first, map, mergeMap, startWith, switchMap, tap } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Component } from '@angular/core'; import { SearchService } from '../search-service/search.service'; import { RemoteData } from '../../core/data/remote-data'; import { SearchFilterConfig } from '../search-service/search-filter-config.model'; import { SearchConfigurationService } from '../search-service/search-configuration.service'; -import { isNotEmpty } from '../../shared/empty.util'; import { SearchFilterService } from './search-filter/search-filter.service'; import { getSucceededRemoteData } from '../../core/shared/operators'; -import { FieldUpdate } from '../../core/data/object-updates/object-updates.reducer'; @Component({ selector: 'ds-search-filters', @@ -53,32 +51,6 @@ export class SearchFiltersComponent { return this.searchService.getSearchLink(); } - /** - * Check if a given filter is supposed to be shown or not - * @param {SearchFilterConfig} filter The filter to check for - * @returns {Observable<boolean>} Emits true whenever a given filter config should be shown - */ - isActive(filterConfig: SearchFilterConfig): Observable<boolean> { - return this.filterService.getSelectedValuesForFilter(filterConfig).pipe( - switchMap((isActive) => { - console.log('selected fires'); - if (isNotEmpty(isActive)) { - return observableOf(true); - } else { - return this.searchConfigService.searchOptions.pipe( - first(), - switchMap((options) => { - return this.searchService.getFacetValuesFor(filterConfig, 1, options).pipe( - filter((RD) => !RD.isLoading), - map((valuesRD) => { - return valuesRD.payload.totalElements > 0 - }),) - } - )) - } - }), tap(t => console.log(t)), startWith(true)); - } - /** * Prevent unnecessary rerendering */ diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index 816e3d67bf..0c572a3a84 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -62,7 +62,6 @@ export class SearchPageComponent implements OnInit { constructor(private service: SearchService, private sidebarService: SearchSidebarService, private windowService: HostWindowService, - private filterService: SearchFilterService, private searchConfigService: SearchConfigurationService) { this.isXsOrSm$ = this.windowService.isXsOrSm(); } diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 0c8a4ee306..b441367f1b 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -28,6 +28,9 @@ import { SearchFacetFilterWrapperComponent } from './search-filters/search-filte import { SearchBooleanFilterComponent } from './search-filters/search-filter/search-boolean-filter/search-boolean-filter.component'; import { SearchHierarchyFilterComponent } from './search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component'; import { SearchConfigurationService } from './search-service/search-configuration.service'; +import { SearchFacetOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component'; +import { SearchFacetSelectedOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component'; +import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component'; const effects = [ SearchSidebarEffects @@ -63,6 +66,9 @@ const effects = [ SearchTextFilterComponent, SearchHierarchyFilterComponent, SearchBooleanFilterComponent, + SearchFacetOptionComponent, + SearchFacetSelectedOptionComponent, + SearchFacetRangeOptionComponent ], providers: [ SearchService, @@ -82,6 +88,9 @@ const effects = [ SearchTextFilterComponent, SearchHierarchyFilterComponent, SearchBooleanFilterComponent, + SearchFacetOptionComponent, + SearchFacetSelectedOptionComponent, + SearchFacetRangeOptionComponent ] }) diff --git a/src/app/shared/services/route.service.ts b/src/app/shared/services/route.service.ts index 478d92c21e..b6c7747cfb 100644 --- a/src/app/shared/services/route.service.ts +++ b/src/app/shared/services/route.service.ts @@ -1,4 +1,4 @@ -import { distinctUntilChanged, map } from 'rxjs/operators'; +import { distinctUntilChanged, map, tap } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { @@ -6,6 +6,7 @@ import { Router, } from '@angular/router'; import { isNotEmpty } from '../empty.util'; +import { detect } from 'rxjs-spy'; @Injectable() export class RouteService { @@ -14,6 +15,7 @@ export class RouteService { } getQueryParameterValues(paramName: string): Observable<string[]> { + console.log('called'); return this.route.queryParamMap.pipe( map((params) => [...params.getAll(paramName)]), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)) @@ -44,6 +46,7 @@ export class RouteService { getQueryParamsWithPrefix(prefix: string): Observable<Params> { return this.route.queryParamMap.pipe( map((qparams) => { + console.log('map'); const params = {}; qparams.keys .filter((key) => key.startsWith(prefix)) @@ -52,6 +55,8 @@ export class RouteService { }); return params; }), - distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))); + distinctUntilChanged((a, b) => { console.log('changed?', a, b, JSON.stringify(a) === JSON.stringify(b)); return JSON.stringify(a) === JSON.stringify(b)}), + tap((t) => console.log('changed')) + ); } } diff --git a/src/main.browser.ts b/src/main.browser.ts index 8409a96485..7b0fbf9d65 100644 --- a/src/main.browser.ts +++ b/src/main.browser.ts @@ -12,6 +12,7 @@ import { BrowserAppModule } from './modules/app/browser-app.module'; import { ENV_CONFIG } from './config'; + if (ENV_CONFIG.production) { enableProdMode(); } diff --git a/yarn.lock b/yarn.lock index d71d9b9186..208ed60c2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -243,6 +243,10 @@ "@types/connect" "*" "@types/node" "*" +"@types/circular-json@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@types/circular-json/-/circular-json-0.4.0.tgz#7401f7e218cfe87ad4c43690da5658b9acaf51be" + "@types/connect@*": version "3.4.32" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" @@ -370,6 +374,10 @@ dependencies: "@types/node" "*" +"@types/stacktrace-js@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/stacktrace-js/-/stacktrace-js-0.0.32.tgz#d23e4a36a5073d39487fbea8234cc6186862d389" + "@types/strip-bom@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" @@ -1600,6 +1608,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +circular-json@^0.5.0: + version "0.5.9" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" + circular-json@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.5.tgz#64182ef359042d37cd8e767fc9de878b1e9447d3" @@ -2605,6 +2617,12 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.2.tgz#4ae8dbaa2bf90a8b450707b9149dcabca135520d" + dependencies: + stackframe "^1.0.4" + es-abstract@^1.4.3, es-abstract@^1.5.1: version "1.12.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" @@ -7237,6 +7255,16 @@ rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" +rxjs-spy@^7.5.1: + version "7.5.1" + resolved "https://registry.yarnpkg.com/rxjs-spy/-/rxjs-spy-7.5.1.tgz#1a9ef50bc8d7dd00d9ecf3c54c00929231eaf319" + dependencies: + "@types/circular-json" "^0.4.0" + "@types/stacktrace-js" "^0.0.32" + circular-json "^0.5.0" + error-stack-parser "^2.0.1" + stacktrace-gps "^3.0.2" + rxjs@6.2.2, rxjs@^6.0.0, rxjs@^6.1.0: version "6.2.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9" @@ -7681,6 +7709,10 @@ source-map@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86" +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + source-map@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" @@ -7801,6 +7833,17 @@ ssri@^5.2.4: dependencies: safe-buffer "^5.1.1" +stackframe@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.0.4.tgz#357b24a992f9427cba6b545d96a14ed2cbca187b" + +stacktrace-gps@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.2.tgz#33f8baa4467323ab2bd1816efa279942ba431ccc" + dependencies: + source-map "0.5.6" + stackframe "^1.0.4" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" -- GitLab