111731: Minimize the facet filters when updating applied filters

This commit is contained in:
Alexandre Vryghem
2024-04-24 23:37:40 +02:00
parent 63be2dae54
commit f5dc187a93
17 changed files with 79 additions and 30 deletions

View File

@@ -13,7 +13,8 @@ import {
SearchFilterIncrementPageAction,
SearchFilterInitializeAction,
SearchFilterResetPageAction,
SearchFilterToggleAction
SearchFilterToggleAction,
SearchFilterMinimizeAllPageAction,
} from '../../../shared/search/search-filters/search-filter/search-filter.actions';
import { hasValue, isNotEmpty, } from '../../../shared/empty.util';
import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model';
@@ -202,7 +203,7 @@ export class SearchFilterService {
select(filterByNameSelector(filterName)),
map((object: SearchFilterState) => {
if (object) {
return object.filterCollapsed;
return object.filterCollapsed || object.minimized;
} else {
return false;
}
@@ -284,6 +285,10 @@ export class SearchFilterService {
public resetPage(filterName: string): void {
this.store.dispatch(new SearchFilterResetPageAction(filterName));
}
public minimizeAll(): void {
this.store.dispatch(new SearchFilterMinimizeAllPageAction());
}
}
function filterByNameSelector(name: string): MemoizedSelector<SearchFiltersState, SearchFilterState> {

View File

@@ -1,7 +1,8 @@
<a *ngIf="isVisible | async" class="d-flex flex-row"
[tabIndex]="-1"
[routerLink]="[searchLink]"
[queryParams]="addQueryParams$ | async">
[queryParams]="addQueryParams$ | async"
(click)="filterService.minimizeAll()">
<label class="mb-0 d-flex w-100">
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch filter-checkbox"/>
<span class="w-100 pl-1 break-facet">

View File

@@ -1,4 +1,5 @@
<a *ngIf="isVisible | async" class="d-flex flex-row"
(click)="filterService.minimizeAll()"
[routerLink]="[searchLink]"
[queryParams]="changeQueryParams" queryParamsHandling="merge">
<span class="filter-value px-1">{{filterValue.label}}</span>

View File

@@ -1,7 +1,8 @@
<a class="d-flex flex-row"
[tabIndex]="-1"
[routerLink]="[searchLink]"
[queryParams]="removeQueryParams | async">
[queryParams]="removeQueryParams | async"
(click)="searchFilterService.minimizeAll()">
<label class="mb-0 d-flex w-100">
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch filter-checkbox"/>
<span class="filter-value pl-1 text-capitalize break-facet">

View File

@@ -7,6 +7,7 @@ import { SearchConfigurationService } from '../../../../../../core/shared/search
import { currentPath } from '../../../../../utils/route.utils';
import { AppliedFilter } from '../../../../models/applied-filter.model';
import { PaginationService } from '../../../../../../core/pagination/pagination.service';
import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service';
@Component({
selector: 'ds-search-facet-selected-option',
@@ -46,6 +47,7 @@ export class SearchFacetSelectedOptionComponent implements OnInit {
constructor(
protected paginationService: PaginationService,
protected router: Router,
protected searchFilterService: SearchFilterService,
protected searchService: SearchService,
protected searchConfigService: SearchConfigurationService,
) {

View File

@@ -19,7 +19,8 @@ export const SearchFilterActionTypes = {
TOGGLE: type('dspace/search-filter/TOGGLE'),
DECREMENT_PAGE: type('dspace/search-filter/DECREMENT_PAGE'),
INCREMENT_PAGE: type('dspace/search-filter/INCREMENT_PAGE'),
RESET_PAGE: type('dspace/search-filter/RESET_PAGE')
RESET_PAGE: type('dspace/search-filter/RESET_PAGE'),
MINIMIZE_ALL: type('dspace/search-filters/MINIMIZE_ALL'),
};
export class SearchFilterAction implements Action {
@@ -37,7 +38,7 @@ export class SearchFilterAction implements Action {
* Initialize with the filter's name
* @param {string} name of the filter
*/
constructor(name: string) {
constructor(name?: string) {
this.filterName = name;
}
}
@@ -95,3 +96,7 @@ export class SearchFilterIncrementPageAction extends SearchFilterAction {
export class SearchFilterResetPageAction extends SearchFilterAction {
type = SearchFilterActionTypes.RESET_PAGE;
}
export class SearchFilterMinimizeAllPageAction extends SearchFilterAction {
type = SearchFilterActionTypes.MINIMIZE_ALL;
}

View File

@@ -9,7 +9,10 @@ import {
SearchFilterResetPageAction,
SearchFilterToggleAction
} from './search-filter.actions';
import { filterReducer } from './search-filter.reducer';
import {
filterReducer,
SearchFiltersState,
} from './search-filter.reducer';
const filterName1 = 'author';
const filterName2 = 'scope';
@@ -25,7 +28,7 @@ class NullAction extends SearchFilterCollapseAction {
describe('filterReducer', () => {
it('should return the current state when no valid actions have been made', () => {
const state = { author: { filterCollapsed: true, page: 1 } };
const state: SearchFiltersState = { author: { filterCollapsed: true, minimized: false, page: 1 } };
const action = new NullAction();
const newState = filterReducer(state, action);
@@ -122,7 +125,7 @@ describe('filterReducer', () => {
it('should not change the state in response to the INITIALIZE action with isOpenByDefault to false when the state has already been set for this filter', () => {
const state = {};
state[filterName1] = { filterCollapsed: false, page: 1 };
state[filterName1] = { filterCollapsed: false, minimized: false, page: 1 };
const filterConfig = { isOpenByDefault: true, name: filterName1 } as any;
const action = new SearchFilterInitializeAction(filterConfig);
const newState = filterReducer(state, action);
@@ -131,7 +134,7 @@ describe('filterReducer', () => {
it('should not change the state in response to the INITIALIZE action with isOpenByDefault to true when the state has already been set for this filter', () => {
const state = {};
state[filterName1] = { filterCollapsed: true, page: 1 };
state[filterName1] = { filterCollapsed: true, minimized: false, page: 1 };
const filterConfig = { isOpenByDefault: false, name: filterName1 } as any;
const action = new SearchFilterInitializeAction(filterConfig);
const newState = filterReducer(state, action);

View File

@@ -5,6 +5,7 @@ import { SearchFilterAction, SearchFilterActionTypes, SearchFilterInitializeActi
*/
export interface SearchFilterState {
filterCollapsed: boolean;
minimized: boolean;
page: number;
}
@@ -23,7 +24,7 @@ const initialState: SearchFiltersState = Object.create(null);
* @param {SearchFilterAction} action The action that should be performed
* @returns {SearchFiltersState} The state after the action is performed
*/
export function filterReducer(state = initialState, action: SearchFilterAction): SearchFiltersState {
export function filterReducer(state: SearchFiltersState = initialState, action: SearchFilterAction): SearchFiltersState {
switch (action.type) {
@@ -32,18 +33,19 @@ export function filterReducer(state = initialState, action: SearchFilterAction):
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: !initAction.initiallyExpanded,
minimized: false,
page: 1
}
} as SearchFilterState,
});
return state;
}
case SearchFilterActionTypes.COLLAPSE: {
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: true,
minimized: state[action.filterName].minimized,
page: state[action.filterName].page
}
} as SearchFilterState,
});
}
@@ -51,10 +53,10 @@ export function filterReducer(state = initialState, action: SearchFilterAction):
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: false,
minimized: state[action.filterName].minimized,
page: state[action.filterName].page
}
} as SearchFilterState,
});
}
case SearchFilterActionTypes.DECREMENT_PAGE: {
@@ -62,8 +64,9 @@ export function filterReducer(state = initialState, action: SearchFilterAction):
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: state[action.filterName].filterCollapsed,
minimized: state[action.filterName].minimized,
page: (page >= 1 ? page : 1)
}
} as SearchFilterState,
});
}
@@ -71,29 +74,34 @@ export function filterReducer(state = initialState, action: SearchFilterAction):
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: state[action.filterName].filterCollapsed,
minimized: state[action.filterName].minimized,
page: state[action.filterName].page + 1
}
} as SearchFilterState,
});
}
case SearchFilterActionTypes.MINIMIZE_ALL: {
return Object.assign({}, ...Object.entries(state).map(([key, value]) => ({ [key]: { ...value, minimized: true } })));
}
case SearchFilterActionTypes.RESET_PAGE: {
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: state[action.filterName].filterCollapsed,
minimized: false,
page: 1
}
} as SearchFilterState,
});
}
case SearchFilterActionTypes.TOGGLE: {
return Object.assign({}, state, {
[action.filterName]: {
filterCollapsed: !state[action.filterName].filterCollapsed,
minimized: state[action.filterName].minimized,
page: state[action.filterName].page
}
} as SearchFilterState,
});
}
default: {

View File

@@ -9,7 +9,6 @@
</span>
<input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'"
class="form-control" (blur)="onSubmit()"
aria-label="Mininum value"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.min.placeholder' | translate"
/>
</label>
@@ -21,7 +20,6 @@
</span>
<input type="text" [(ngModel)]="range[1]" [name]="filterConfig.paramName + '.max'"
class="form-control" (blur)="onSubmit()"
aria-label="Maximum value"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.max.placeholder' | translate"
/>
</label>

View File

@@ -4,4 +4,4 @@
<ds-search-filter [filter]="filter" [inPlaceSearch]="inPlaceSearch" [refreshFilters]="refreshFilters"></ds-search-filter>
</div>
</div>
<a class="btn btn-primary" [routerLink]="[searchLink]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button"><i class="fas fa-undo"></i> {{"search.filters.reset" | translate}}</a>
<button class="btn btn-primary" [routerLink]="[searchLink]" [queryParams]="clearParams | async" (click)="minimizeFilters()" queryParamsHandling="merge" role="button"><i class="fas fa-undo"></i> {{"search.filters.reset" | translate}}</button>

View File

@@ -11,6 +11,7 @@ import { SearchConfigurationService } from '../../../core/shared/search/search-c
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { currentPath } from '../../utils/route.utils';
import { AppliedFilter } from '../models/applied-filter.model';
import { SearchFilterService } from '../../../core/shared/search/search-filter.service';
@Component({
selector: 'ds-search-filters',
@@ -69,9 +70,11 @@ export class SearchFiltersComponent implements OnInit {
* @param {SearchConfigurationService} searchConfigService
*/
constructor(
private searchService: SearchService,
private router: Router,
@Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) {
protected searchService: SearchService,
protected searchFilterService: SearchFilterService,
protected router: Router,
@Inject(SEARCH_CONFIG_SERVICE) protected searchConfigService: SearchConfigurationService,
) {
}
ngOnInit(): void {
@@ -99,4 +102,9 @@ export class SearchFiltersComponent implements OnInit {
return config ? config.name : undefined;
}
minimizeFilters(): void {
if (this.searchService.appliedFilters$.value.length > 0) {
this.searchFilterService.minimizeAll();
}
}
}

View File

@@ -1,6 +1,7 @@
<a *ngIf="min !== '*'"
[routerLink]="searchLink"
[queryParams]="(removeParametersMin$ | async)"
(click)="searchFilterService.minimizeAll()"
class="badge badge-primary mr-1 mb-1">
{{('search.filters.applied.f.' + appliedFilter.filter + '.min') | translate}}: {{ min }}
<span> ×</span>
@@ -8,6 +9,7 @@
<a *ngIf="max !== '*'"
[routerLink]="searchLink"
[queryParams]="(removeParametersMax$ | async)"
(click)="searchFilterService.minimizeAll()"
class="badge badge-primary mr-1 mb-1">
{{('search.filters.applied.f.' + appliedFilter.filter + '.max') | translate}}: {{ max }}
<span> ×</span>

View File

@@ -13,6 +13,8 @@ import { SearchConfigurationServiceStub } from '../../../testing/search-configur
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../testing/pagination-service.stub';
import { PaginationComponentOptions } from '../../../pagination/pagination-component-options.model';
import { SearchFilterService } from '../../../../core/shared/search/search-filter.service';
import { SearchFilterServiceStub } from '../../../testing/search-filter-service.stub';
describe('SearchLabelRangeComponent', () => {
let comp: SearchLabelRangeComponent;
@@ -20,6 +22,7 @@ describe('SearchLabelRangeComponent', () => {
let route: ActivatedRouteStub;
let searchConfigurationService: SearchConfigurationServiceStub;
let searchFilterService: SearchFilterServiceStub;
let paginationService: PaginationServiceStub;
const searchLink = '/search';
@@ -51,6 +54,7 @@ describe('SearchLabelRangeComponent', () => {
init();
route = new ActivatedRouteStub(initialRouteParams);
searchConfigurationService = new SearchConfigurationServiceStub();
searchFilterService = new SearchFilterServiceStub();
paginationService = new PaginationServiceStub(pagination);
await TestBed.configureTestingModule({
@@ -65,6 +69,7 @@ describe('SearchLabelRangeComponent', () => {
{ provide: PaginationService, useValue: paginationService },
{ provide: SearchConfigurationService, useValue: searchConfigurationService },
{ provide: SearchService, useValue: new SearchServiceStub(searchLink) },
{ provide: SearchFilterService, useValue: searchFilterService },
{ provide: ActivatedRoute, useValue: route },
],
}).compileComponents();

View File

@@ -7,6 +7,7 @@ import { AppliedFilter } from '../../models/applied-filter.model';
import { renderSearchLabelFor } from '../search-label-loader/search-label-loader.decorator';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { SearchFilterService } from '../../../../core/shared/search/search-filter.service';
/**
* Component that represents the label containing the currently active filters
@@ -37,6 +38,7 @@ export class SearchLabelRangeComponent implements OnInit {
protected router: Router,
protected searchConfigurationService: SearchConfigurationService,
protected searchService: SearchService,
protected searchFilterService: SearchFilterService,
) {
}

View File

@@ -1,6 +1,7 @@
<a class="badge badge-primary mr-1 mb-1"
[routerLink]="searchLink"
[queryParams]="(removeParameters$ | async)">
[queryParams]="(removeParameters$ | async)"
(click)="searchFilterService.minimizeAll()">
{{('search.filters.applied.f.' + appliedFilter.filter) | translate}}{{'search.filters.applied.operator.' + appliedFilter.operator | translate}}: {{'search.filters.' + appliedFilter.filter + '.' + appliedFilter.label | translate: {default: appliedFilter.label} }}
<span> ×</span>
</a>

View File

@@ -13,6 +13,8 @@ import { SearchConfigurationServiceStub } from '../../../testing/search-configur
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../testing/pagination-service.stub';
import { PaginationComponentOptions } from '../../../pagination/pagination-component-options.model';
import { SearchFilterServiceStub } from '../../../testing/search-filter-service.stub';
import { SearchFilterService } from '../../../../core/shared/search/search-filter.service';
describe('SearchLabelComponent', () => {
let comp: SearchLabelComponent;
@@ -20,6 +22,7 @@ describe('SearchLabelComponent', () => {
let route: ActivatedRouteStub;
let searchConfigurationService: SearchConfigurationServiceStub;
let searchFilterService: SearchFilterServiceStub;
let paginationService: PaginationServiceStub;
const searchLink = '/search';
@@ -51,6 +54,7 @@ describe('SearchLabelComponent', () => {
init();
route = new ActivatedRouteStub(initialRouteParams);
searchConfigurationService = new SearchConfigurationServiceStub();
searchFilterService = new SearchFilterServiceStub();
paginationService = new PaginationServiceStub(pagination);
await TestBed.configureTestingModule({
@@ -64,6 +68,7 @@ describe('SearchLabelComponent', () => {
providers: [
{ provide: PaginationService, useValue: paginationService },
{ provide: SearchConfigurationService, useValue: searchConfigurationService },
{ provide: SearchFilterService, useValue: searchFilterService },
{ provide: SearchService, useValue: new SearchServiceStub(searchLink) },
{ provide: ActivatedRoute, useValue: route },
],

View File

@@ -7,6 +7,7 @@ import { AppliedFilter } from '../../models/applied-filter.model';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { renderSearchLabelFor } from '../search-label-loader/search-label-loader.decorator';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { SearchFilterService } from '../../../../core/shared/search/search-filter.service';
/**
* Component that represents the label containing the currently active filters
@@ -30,6 +31,7 @@ export class SearchLabelComponent implements OnInit {
protected router: Router,
protected searchConfigurationService: SearchConfigurationService,
protected searchService: SearchService,
protected searchFilterService: SearchFilterService,
) {
}