mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-15 22:13:02 +00:00
optimizations links in facets
This commit is contained in:
@@ -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",
|
||||
|
@@ -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">
|
||||
|
@@ -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>
|
@@ -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
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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>
|
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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>
|
@@ -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
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
<ng-container *ngComponentOutlet="getSearchFilter(); injector: objectInjector;"></ng-container>
|
||||
<ng-container *ngComponentOutlet="searchFilter injector: objectInjector;"></ng-container>
|
@@ -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);
|
||||
}
|
||||
|
@@ -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()], {
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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>
|
@@ -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>;
|
||||
|
||||
constructor(private filterService: SearchFilterService) {
|
||||
selectedValues$: Observable<string[]>;
|
||||
active$: Observable<boolean>;
|
||||
|
||||
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
|
||||
* Sets the initial state of the filter
|
||||
*/
|
||||
initialCollapse() {
|
||||
this.filterService.initialCollapse(this.filter.name);
|
||||
this.collapsed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the initial state to expanded
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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(() => {
|
||||
|
@@ -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 prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').pipe(
|
||||
map((params: Params) => [].concat(...Object.values(params)))
|
||||
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))),
|
||||
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
|
||||
* Dispatches an initialize action to the store for a given filter
|
||||
* @param {SearchFilterConfig} filter 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
|
||||
*/
|
||||
public initialExpand(filterName: string): void {
|
||||
this.store.dispatch(new SearchFilterInitialExpandAction(filterName));
|
||||
public initializeFilter(filter: SearchFilterConfig): void {
|
||||
this.store.dispatch(new SearchFilterInitializeAction(filter));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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">
|
||||
|
@@ -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>
|
||||
|
@@ -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'
|
||||
});
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
@@ -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
|
||||
*/
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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
|
||||
]
|
||||
})
|
||||
|
||||
|
@@ -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'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import { BrowserAppModule } from './modules/app/browser-app.module';
|
||||
|
||||
import { ENV_CONFIG } from './config';
|
||||
|
||||
|
||||
if (ENV_CONFIG.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
43
yarn.lock
43
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"
|
||||
|
Reference in New Issue
Block a user