mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
74606: Ensure the correct operators are used for filter queries
This commit is contained in:
@@ -1,9 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { FilterType } from '../../../filter-type.model';
|
import { FilterType } from '../../../filter-type.model';
|
||||||
import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component';
|
import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component';
|
||||||
import { renderFacetFor } from '../search-filter-type-decorator';
|
import { renderFacetFor } from '../search-filter-type-decorator';
|
||||||
import { FacetValue } from '../../../facet-value.model';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-authority-filter',
|
selector: 'ds-search-authority-filter',
|
||||||
@@ -17,20 +15,4 @@ import { FacetValue } from '../../../facet-value.model';
|
|||||||
*/
|
*/
|
||||||
@renderFacetFor(FilterType.authority)
|
@renderFacetFor(FilterType.authority)
|
||||||
export class SearchAuthorityFilterComponent extends SearchFacetFilterComponent implements OnInit {
|
export class SearchAuthorityFilterComponent extends SearchFacetFilterComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved
|
|
||||||
* Retrieve facet value from search link
|
|
||||||
*/
|
|
||||||
protected getFacetValue(facet: FacetValue): string {
|
|
||||||
const search = facet._links.search.href;
|
|
||||||
const hashes = search.slice(search.indexOf('?') + 1).split('&');
|
|
||||||
const params = {};
|
|
||||||
hashes.map((hash) => {
|
|
||||||
const [key, val] = hash.split('=');
|
|
||||||
params[key] = decodeURIComponent(val)
|
|
||||||
});
|
|
||||||
|
|
||||||
return params[this.filterConfig.paramName];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@ import { SearchConfigurationService } from '../../../../../../core/shared/search
|
|||||||
import { hasValue } from '../../../../../empty.util';
|
import { hasValue } from '../../../../../empty.util';
|
||||||
import { FilterType } from '../../../../filter-type.model';
|
import { FilterType } from '../../../../filter-type.model';
|
||||||
import { currentPath } from '../../../../../utils/route.utils';
|
import { currentPath } from '../../../../../utils/route.utils';
|
||||||
|
import { getFacetValueForType } from '../../../../search.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-facet-option',
|
selector: 'ds-search-facet-option',
|
||||||
@@ -102,7 +103,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
private updateAddParams(selectedValues: FacetValue[]): void {
|
private updateAddParams(selectedValues: FacetValue[]): void {
|
||||||
this.addQueryParams = {
|
this.addQueryParams = {
|
||||||
[this.filterConfig.paramName]: [...selectedValues.map((facetValue: FacetValue) => facetValue.label), this.getFacetValue()],
|
[this.filterConfig.paramName]: [...selectedValues.map((facetValue: FacetValue) => getFacetValueForType(facetValue, this.filterConfig)), this.getFacetValue()],
|
||||||
page: 1
|
page: 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -112,19 +113,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
|
|||||||
* Retrieve facet value related to facet type
|
* Retrieve facet value related to facet type
|
||||||
*/
|
*/
|
||||||
private getFacetValue(): string {
|
private getFacetValue(): string {
|
||||||
if (this.filterConfig.type === FilterType.authority) {
|
return getFacetValueForType(this.filterValue, this.filterConfig);
|
||||||
const search = this.filterValue._links.search.href;
|
|
||||||
const hashes = search.slice(search.indexOf('?') + 1).split('&');
|
|
||||||
const params = {};
|
|
||||||
hashes.map((hash) => {
|
|
||||||
const [key, val] = hash.split('=');
|
|
||||||
params[key] = decodeURIComponent(val)
|
|
||||||
});
|
|
||||||
|
|
||||||
return params[this.filterConfig.paramName];
|
|
||||||
} else {
|
|
||||||
return this.filterValue.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -3,6 +3,6 @@
|
|||||||
[queryParams]="removeQueryParams" queryParamsHandling="merge">
|
[queryParams]="removeQueryParams" queryParamsHandling="merge">
|
||||||
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
|
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
|
||||||
<span class="filter-value pl-1 text-capitalize">
|
<span class="filter-value pl-1 text-capitalize">
|
||||||
{{ 'search.filters.' + filterConfig.name + '.' + selectedValue.value | translate: {default: selectedValue.value} }}
|
{{ 'search.filters.' + filterConfig.name + '.' + selectedValue.value | translate: {default: selectedValue.label} }}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@@ -9,6 +9,7 @@ import { SearchConfigurationService } from '../../../../../../core/shared/search
|
|||||||
import { FacetValue } from '../../../../facet-value.model';
|
import { FacetValue } from '../../../../facet-value.model';
|
||||||
import { FilterType } from '../../../../filter-type.model';
|
import { FilterType } from '../../../../filter-type.model';
|
||||||
import { currentPath } from '../../../../../utils/route.utils';
|
import { currentPath } from '../../../../../utils/route.utils';
|
||||||
|
import { getFacetValueForType } from '../../../../search.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-facet-selected-option',
|
selector: 'ds-search-facet-selected-option',
|
||||||
@@ -101,19 +102,7 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy {
|
|||||||
* Retrieve facet value related to facet type
|
* Retrieve facet value related to facet type
|
||||||
*/
|
*/
|
||||||
private getFacetValue(facetValue: FacetValue): string {
|
private getFacetValue(facetValue: FacetValue): string {
|
||||||
if (this.filterConfig.type === FilterType.authority) {
|
return getFacetValueForType(facetValue, this.filterConfig);
|
||||||
const search = facetValue._links.search.href;
|
|
||||||
const hashes = search.slice(search.indexOf('?') + 1).split('&');
|
|
||||||
const params = {};
|
|
||||||
hashes.map((hash) => {
|
|
||||||
const [key, val] = hash.split('=');
|
|
||||||
params[key] = decodeURIComponent(val)
|
|
||||||
});
|
|
||||||
|
|
||||||
return params[this.filterConfig.paramName];
|
|
||||||
} else {
|
|
||||||
return facetValue.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -25,6 +25,7 @@ import { InputSuggestion } from '../../../../input-suggestions/input-suggestions
|
|||||||
import { SearchOptions } from '../../../search-options.model';
|
import { SearchOptions } from '../../../search-options.model';
|
||||||
import { SEARCH_CONFIG_SERVICE } from '../../../../../+my-dspace-page/my-dspace-page.component';
|
import { SEARCH_CONFIG_SERVICE } from '../../../../../+my-dspace-page/my-dspace-page.component';
|
||||||
import { currentPath } from '../../../../utils/route.utils';
|
import { currentPath } from '../../../../utils/route.utils';
|
||||||
|
import { getFacetValueForType, stripOperatorFromFilterValue } from '../../../search.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-facet-filter',
|
selector: 'ds-search-facet-filter',
|
||||||
@@ -148,7 +149,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
|||||||
if (hasValue(fValue)) {
|
if (hasValue(fValue)) {
|
||||||
return fValue;
|
return fValue;
|
||||||
}
|
}
|
||||||
return Object.assign(new FacetValue(), { label: value, value: value });
|
return Object.assign(new FacetValue(), { label: stripOperatorFromFilterValue(value), value: value });
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -303,7 +304,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
|||||||
* Retrieve facet value
|
* Retrieve facet value
|
||||||
*/
|
*/
|
||||||
protected getFacetValue(facet: FacetValue): string {
|
protected getFacetValue(facet: FacetValue): string {
|
||||||
return facet.value;
|
return getFacetValueForType(facet, this.filterConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -5,6 +5,10 @@ import {
|
|||||||
SearchFacetFilterComponent
|
SearchFacetFilterComponent
|
||||||
} from '../search-facet-filter/search-facet-filter.component';
|
} from '../search-facet-filter/search-facet-filter.component';
|
||||||
import { renderFacetFor } from '../search-filter-type-decorator';
|
import { renderFacetFor } from '../search-filter-type-decorator';
|
||||||
|
import {
|
||||||
|
addOperatorToFilterValue,
|
||||||
|
stripOperatorFromFilterValue
|
||||||
|
} from '../../../search.utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
@@ -24,4 +28,21 @@ import { renderFacetFor } from '../search-filter-type-decorator';
|
|||||||
*/
|
*/
|
||||||
@renderFacetFor(FilterType.text)
|
@renderFacetFor(FilterType.text)
|
||||||
export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit {
|
export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* Submits a new active custom value to the filter from the input field
|
||||||
|
* Overwritten method from parent component, adds the "query" operator to the received data before passing it on
|
||||||
|
* @param data The string from the input field
|
||||||
|
*/
|
||||||
|
onSubmit(data: any) {
|
||||||
|
super.onSubmit(addOperatorToFilterValue(data, 'query'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On click, set the input's value to the clicked data
|
||||||
|
* Overwritten method from parent component, strips any operator from the received data before passing it on
|
||||||
|
* @param data The value of the option that was clicked
|
||||||
|
*/
|
||||||
|
onClick(data: any) {
|
||||||
|
super.onClick(stripOperatorFromFilterValue(data));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,8 @@ import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.c
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Params, Router } from '@angular/router';
|
import { Params, Router } from '@angular/router';
|
||||||
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
|
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
import { stripOperatorFromFilterValue } from '../search.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-labels',
|
selector: 'ds-search-labels',
|
||||||
@@ -30,6 +32,15 @@ export class SearchLabelsComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
|
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
|
||||||
this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters();
|
this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters().pipe(
|
||||||
|
map((params) => {
|
||||||
|
const labels = {};
|
||||||
|
Object.keys(params)
|
||||||
|
.forEach((key) => {
|
||||||
|
labels[key] = [...params[key].map((value) => stripOperatorFromFilterValue(value))];
|
||||||
|
});
|
||||||
|
return labels;
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
src/app/shared/search/search.utils.ts
Normal file
44
src/app/shared/search/search.utils.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { FacetValue } from './facet-value.model';
|
||||||
|
import { SearchFilterConfig } from './search-filter-config.model';
|
||||||
|
import { isNotEmpty } from '../empty.util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a facet's value by matching its parameter in the search href, this will include the operator of the facet value
|
||||||
|
* If the {@link FacetValue} doesn't contain a search link, its raw value will be returned as a fallback
|
||||||
|
* @param facetValue
|
||||||
|
* @param searchFilterConfig
|
||||||
|
*/
|
||||||
|
export function getFacetValueForType(facetValue: FacetValue, searchFilterConfig: SearchFilterConfig): string {
|
||||||
|
const regex = new RegExp(`[?|&]${searchFilterConfig.paramName}=(${facetValue.value}[^&]*)`, 'g');
|
||||||
|
if (isNotEmpty(facetValue._links)) {
|
||||||
|
const values = regex.exec(facetValue._links.search.href);
|
||||||
|
if (isNotEmpty(values)) {
|
||||||
|
return values[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addOperatorToFilterValue(facetValue.value, 'equals');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip the operator from a filter value
|
||||||
|
* Warning: This expects the value to end with an operator, otherwise it might strip unwanted content
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
export function stripOperatorFromFilterValue(value: string) {
|
||||||
|
if (value.lastIndexOf(',') > -1) {
|
||||||
|
return value.substring(0, value.lastIndexOf(','));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an operator to a string
|
||||||
|
* @param value
|
||||||
|
* @param operator
|
||||||
|
*/
|
||||||
|
export function addOperatorToFilterValue(value: string, operator: string) {
|
||||||
|
if (!value.endsWith(`,${operator}`)) {
|
||||||
|
return `${value},${operator}`;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
Reference in New Issue
Block a user