[ACS-4125] Add support for the tags search facet (#8390)

* ACS-4125 Added changes needed to display facets for tags

* ACS-4125 Removed logs

* Add reordering of buckets and facets through configuration + unit tests

---------

Co-authored-by: Aleksander Sklorz <Aleksander.Sklorz@hyland.com>
This commit is contained in:
Thomas Hunter 2023-03-17 09:17:17 +00:00 committed by GitHub
parent 4180d9f69a
commit 1b2575b2db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 3 deletions

View File

@ -444,7 +444,10 @@ Note: `settings` property used to control UI actions and interaction. i.e
],
"settings" : {
"allowUpdateOnChange": false,
"hideDefaultAction": true
"hideDefaultAction": true,
"facetOrder": 100,
"bucketSortBy": "LABEL",
"bucketSortDirection": "ASCENDING"
}
}
}

View File

@ -23,5 +23,4 @@ export interface FacetFieldBucket {
checked?: boolean;
field?: string;
}

View File

@ -40,4 +40,22 @@ export interface FacetFieldSettings {
allowUpdateOnChange?: boolean;
/* allow the user show/hide default search actions */
hideDefaultAction?: boolean;
/* a number to compare to other facets to determine the order in which they will appear */
facetOrder?: number;
/* the field used to sort the buckets */
bucketSortBy?: FacetBucketSortBy;
/* the direction in which the buckets are ordered */
bucketSortDirection?: FacetBucketSortDirection;
}
// eslint-disable-next-line no-shadow
export enum FacetBucketSortBy {
LABEL = 'LABEL',
COUNT = 'COUNT'
}
// eslint-disable-next-line no-shadow
export enum FacetBucketSortDirection {
ASCENDING = 'ASCENDING',
DESCENDING = 'DESCENDING'
}

View File

@ -20,6 +20,7 @@ import { TestBed } from '@angular/core/testing';
import { SearchFacetFiltersService } from './search-facet-filters.service';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { SearchQueryBuilderService } from './search-query-builder.service';
import { FacetBucketSortBy, FacetBucketSortDirection } from '@alfresco/adf-content-services';
describe('SearchFacetFiltersService', () => {
let searchFacetFiltersService: SearchFacetFiltersService;
@ -416,4 +417,103 @@ describe('SearchFacetFiltersService', () => {
expect(searchFacetFiltersService.responseFacets[0].buckets.length).toEqual(1);
});
it('should sort the facets based on the order set in the settings', () => {
searchFacetFiltersService.responseFacets = null;
queryBuilder.config = {
categories: [],
facetQueries: {
label: 'Query 1',
queries: [
{ label: 'q1', query: 'query1' },
{ label: 'q2', query: 'query2' }
],
settings: {
facetOrder: 300
}
},
facetFields: {
fields: [
{ field: 'field1', label: 'Field 1', settings: { facetOrder: 200 }},
{ field: 'field2', label: 'Field 2', settings: { facetOrder: 400 }},
{ field: 'field3', label: 'Field 3', settings: { facetOrder: 500 }},
{ field: 'field4', label: 'Field 4', settings: { facetOrder: 100 }}
]
}
};
const queryBucketsMock = [{ label: 'q1', filterQuery: 'query1', metrics: [{value: {count: 1} }] }];
const fieldBucketsMock = [{ label: 'b1', metrics: [{ value: { count: 10 } }] }];
const data = {
list: {
context: {
facets: [
{ type: 'query', label: 'Query 1', buckets: queryBucketsMock },
{ type: 'field', label: 'Field 1', buckets: fieldBucketsMock },
{ type: 'field', label: 'Field 2', buckets: fieldBucketsMock },
{ type: 'field', label: 'Field 3', buckets: fieldBucketsMock },
{ type: 'field', label: 'Field 4', buckets: fieldBucketsMock }
]
}
}
};
searchFacetFiltersService.onDataLoaded(data);
expect(searchFacetFiltersService.responseFacets.map(f => f.field)).toEqual(['field4', 'field1', 'Query 1', 'field2', 'field3']);
});
describe('Bucket sorting', () => {
let data;
beforeEach(() => {
searchFacetFiltersService.responseFacets = null;
data = {
list: {
context: {
facets: [
{
type: 'field',
label: 'Field',
buckets: [
{ label: 'foo', metrics: [{ value: { count: 8 } }] },
{ label: 'bar', metrics: [{ value: { count: 30 } }] },
{ label: 'xyzzy', metrics: [{ value: { count: 14 } }] },
{ label: 'qux', metrics: [{ value: { count: 28 } }] },
{ label: 'baz', metrics: [{ value: { count: 1 } }] }
]
}
]
}
}
};
});
it('should sort the buckets by label', () => {
queryBuilder.config = {
categories: [],
facetQueries: { queries: [] },
facetFields: {
fields: [
{ field: 'field', label: 'Field', settings: { bucketSortBy: FacetBucketSortBy.LABEL, bucketSortDirection: FacetBucketSortDirection.DESCENDING }}
]
}
};
searchFacetFiltersService.onDataLoaded(data);
expect(searchFacetFiltersService.responseFacets[0].buckets.items.map(b => b.label)).toEqual(['xyzzy', 'qux', 'foo', 'baz', 'bar']);
});
it('should sort the buckets by count', () => {
queryBuilder.config = {
categories: [],
facetQueries: { queries: [] },
facetFields: {
fields: [
{ field: 'field', label: 'Field', settings: { bucketSortBy: FacetBucketSortBy.COUNT, bucketSortDirection: FacetBucketSortDirection.ASCENDING }}
]
}
};
searchFacetFiltersService.onDataLoaded(data);
expect(searchFacetFiltersService.responseFacets[0].buckets.items.map(b => b.label)).toEqual(['baz', 'foo', 'xyzzy', 'qux', 'bar']);
});
});
});

View File

@ -16,7 +16,7 @@
*/
import { Inject, Injectable, OnDestroy } from '@angular/core';
import { FacetField } from '../models/facet-field.interface';
import { FacetBucketSortBy, FacetBucketSortDirection, FacetField } from '../models/facet-field.interface';
import { Subject } from 'rxjs';
import { SEARCH_QUERY_SERVICE_TOKEN } from '../search-query-service.token';
import { SearchQueryBuilderService } from './search-query-builder.service';
@ -91,6 +91,7 @@ export class SearchFacetFiltersService implements OnDestroy {
this.parseFacetFields(context);
this.parseFacetIntervals(context);
this.parseFacetQueries(context);
this.sortFacets();
}
private parseFacetItems(context: ResultSetContext, configFacetFields: FacetField[], itemType: string) {
@ -98,6 +99,7 @@ export class SearchFacetFiltersService implements OnDestroy {
const responseField = this.findFacet(context, itemType, field.label);
const responseBuckets = this.getResponseBuckets(responseField, field)
.filter(this.getFilterByMinCount(field.mincount));
this.sortFacetBuckets(responseBuckets, field.settings?.bucketSortBy, field.settings?.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING);
const alreadyExistingField = this.findResponseFacet(itemType, field.label);
if (alreadyExistingField) {
@ -155,6 +157,7 @@ export class SearchFacetFiltersService implements OnDestroy {
const responseField = this.findFacet(context, 'query', group);
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group])
.filter(mincountFilter);
this.sortFacetBuckets(responseBuckets, facetQuerySetting?.bucketSortBy, facetQuerySetting.bucketSortDirection ?? FacetBucketSortDirection.ASCENDING);
const alreadyExistingField = this.findResponseFacet('query', group);
if (alreadyExistingField) {
@ -184,6 +187,10 @@ export class SearchFacetFiltersService implements OnDestroy {
}
private sortFacets() {
this.responseFacets?.sort((facet1, facet2) => (facet1.settings?.facetOrder ?? 0) - (facet2.settings?.facetOrder ?? 0));
}
private getResponseBuckets(responseField: GenericFacetResponse, configField: FacetField): FacetFieldBucket[] {
return ((responseField && responseField.buckets) || []).map((respBucket) => {
@ -213,6 +220,23 @@ export class SearchFacetFiltersService implements OnDestroy {
});
}
private sortFacetBuckets(buckets: FacetFieldBucket[], sortBy: FacetBucketSortBy, sortDirection: FacetBucketSortDirection) {
switch (sortBy) {
case FacetBucketSortBy.LABEL:
buckets.sort((bucket1, bucket2) =>
sortDirection === FacetBucketSortDirection.ASCENDING ? bucket1.label.localeCompare(bucket2.label) : bucket2.label.localeCompare(bucket1.label)
);
break;
case FacetBucketSortBy.COUNT:
buckets.sort((bucket1, bucket2) =>
sortDirection === FacetBucketSortDirection.ASCENDING ? bucket1.count - bucket2.count : bucket2.count - bucket1.count
);
break;
default:
return;
}
}
private getCountValue(bucket: GenericBucket): number {
return (!!bucket && !!bucket.metrics && bucket.metrics[0]?.value?.count) || 0;
}