[ADF-4083] search facetFields - empty spaced labels support (#4322)

* [ADF-4083] ignore wrapping quotes for facet labels

- bucket selection needs fixing

* [ADF-4083] fix bucket selection

- generate missing filterQuery values

* [ADF-4083] fix label display

* [ADF-4083] renaming

* [ADF-4083] support also single quotes label wrappings

- update documentation
- tests

* [ADF-4083] automatically escape facet field labels having spaces - better fix

* [ADF-4083] remove unneeded mentions from documentation

* [ADF-4083] clean-up code

* [ADF-4083] better naming param

* [ADF-4083] small refactoring
This commit is contained in:
Suzana Dirla
2019-02-21 14:49:47 +02:00
committed by Eugenio Romano
parent 877c57b356
commit bfec78aec9
5 changed files with 76 additions and 12 deletions

View File

@@ -66,7 +66,7 @@ A typical configuration is shown below:
"expanded": true,
"fields": [
{ "field": "content.mimetype", "mincount": 1, "label": "Type" },
{ "field": "content.size", "mincount": 1, "label": "Size" },
{ "field": "content.size", "mincount": 1, "label": "File Size" },
{ "field": "creator", "mincount": 1, "label": "Creator" },
{ "field": "modifier", "mincount": 1, "label": "Modifier" }
]
@@ -254,13 +254,16 @@ export interface SearchWidgetSettings {
```json
{
"search": {
"facetFields": [
{ "field": "content.mimetype", "mincount": 1, "label": "Type" },
{ "field": "content.size", "mincount": 1, "label": "Size" },
{ "field": "creator", "mincount": 1, "label": "Creator" },
{ "field": "modifier", "mincount": 1, "label": "Modifier" },
{ "field": "created", "mincount": 1, "label": "Created" }
]
"facetFields": {
"expanded": true,
"fields": [
{ "field": "content.mimetype", "mincount": 1, "label": "Type" },
{ "field": "content.size", "mincount": 1, "label": "File Size" },
{ "field": "creator", "mincount": 1, "label": "Creator" },
{ "field": "modifier", "mincount": 1, "label": "Modifier" },
{ "field": "created", "mincount": 1, "label": "Created" }
]
}
}
}
```
@@ -268,7 +271,7 @@ export interface SearchWidgetSettings {
Every field declared within the `facetFields` group is presented by a separate collapsible category at runtime.
By default, users see only the top 5 entries.
If there are more than 5 entries, the "Show more" button is displayed to let the user move to
If there are more than 5 entries, a button to show more items is displayed to let the user move to
the next block of results.
![Facet Fields](../docassets/images/search-facet-fields.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -192,7 +192,7 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
private parseFacetItems(context: ResultSetContext, configFacetFields, itemType): FacetField[] {
return configFacetFields.map((field) => {
const responseField = (context.facets || []).find((response) => response.type === itemType && response.label === field.label) || {};
const responseBuckets = this.getResponseBuckets(responseField)
const responseBuckets = this.getResponseBuckets(responseField, field)
.filter(this.getFilterByMinCount(field.mincount));
const bucketList = new SearchFilterList<FacetFieldBucket>(responseBuckets, field.pageSize);
@@ -270,10 +270,11 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
return result;
}
private getResponseBuckets(responseField: GenericFacetResponse): FacetFieldBucket[] {
private getResponseBuckets(responseField: GenericFacetResponse, configField: FacetField): FacetFieldBucket[] {
return ((responseField && responseField.buckets) || []).map((respBucket) => {
respBucket['count'] = this.getCountValue(respBucket);
respBucket.filterQuery = respBucket.filterQuery || this.getCorrespondingFilterQuery(configField, respBucket.label);
return <FacetFieldBucket> {
...respBucket,
checked: false,
@@ -312,4 +313,11 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
return bucket.count >= mincount;
};
}
private getCorrespondingFilterQuery (configFacetItem: FacetField, bucketLabel: string): string {
if (!configFacetItem.field || !bucketLabel) {
return null;
}
return `${configFacetItem.field}:"${bucketLabel}"`;
}
}

View File

@@ -216,6 +216,20 @@ describe('SearchQueryBuilder', () => {
expect(field).toBeFalsy();
});
it('should fetch facets from the config by label with spaces and return field with request compatible label (escaped)', () => {
const config: SearchConfiguration = {
categories: [],
facetFields: { 'fields': [
{ 'field': 'content.size', 'mincount': 1, 'label': 'Label with spaces' }
]}
};
const builder = new SearchQueryBuilderService(buildConfig(config), null);
const field = builder.getFacetField('Label with spaces');
expect(field.label).toBe('"Label with spaces"');
expect(field.field).toBe('content.size');
});
xit('should build query and raise an event on update', async () => {
const builder = new SearchQueryBuilderService(buildConfig({}), null);
const query = {};
@@ -371,6 +385,35 @@ describe('SearchQueryBuilder', () => {
expect(compiled.facetFields.facets).toEqual(jasmine.objectContaining(config.facetFields.fields));
});
it('should build query with custom facet fields automatically getting their request compatible labels', () => {
const spacesLabel = {
configValue: 'label with spaces',
requestCompatibleValue: '"label with spaces"'
};
const noSpacesLabel = {
configValue: 'label',
requestCompatibleValue: 'label'
};
const config: SearchConfiguration = {
categories: [
<any> { id: 'cat1', enabled: true }
],
facetFields: { fields: [
{ field: 'field1', label: spacesLabel.configValue, mincount: 1, limit: null, offset: 0, prefix: null },
{ field: 'field2', label: noSpacesLabel.configValue, mincount: 1, limit: null, offset: 0, prefix: null }
]}
};
const builder = new SearchQueryBuilderService(buildConfig(config), null);
builder.queryFragments['cat1'] = 'cm:name:test';
const compiled = builder.buildQuery();
expect(compiled.facetFields.facets[0].label).toEqual(spacesLabel.requestCompatibleValue);
expect(compiled.facetFields.facets[0].label).not.toEqual(spacesLabel.configValue);
expect(compiled.facetFields.facets[1].label).toEqual(noSpacesLabel.requestCompatibleValue);
expect(compiled.facetFields.facets[1].label).toEqual(noSpacesLabel.configValue);
});
it('should build query with custom facet intervals', () => {
const config: SearchConfiguration = {
categories: [

View File

@@ -175,6 +175,7 @@ export class SearchQueryBuilderService {
const fields = this.config.facetFields.fields || [];
const result = fields.find((field) => field.label === label);
if (result) {
result.label = this.getSupportedLabel(result.label);
return { ...result };
}
}
@@ -352,6 +353,7 @@ export class SearchQueryBuilderService {
if (this.userFacetBuckets) {
Object.keys(this.userFacetBuckets).forEach((key) => {
const subQuery = (this.userFacetBuckets[key] || [])
.filter((bucket) => bucket.filterQuery)
.map((bucket) => bucket.filterQuery)
.join(' OR ');
if (subQuery) {
@@ -374,7 +376,7 @@ export class SearchQueryBuilderService {
facets: facetFields.map((facet) => <RequestFacetField> {
field: facet.field,
mincount: facet.mincount,
label: facet.label,
label: this.getSupportedLabel(facet.label),
limit: facet.limit,
offset: facet.offset,
prefix: facet.prefix
@@ -384,4 +386,12 @@ export class SearchQueryBuilderService {
return null;
}
getSupportedLabel(configLabel: string): string {
const spaceInsideLabelIndex = configLabel.search(/\s/g);
if (spaceInsideLabelIndex > -1) {
return `"${configLabel}"`;
}
return configLabel;
}
}