mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-3497] Facet intervals on search filter (#4255)
* [ADF-3497] allow facetIntervals on search * [ADF-3497] update schema json * [ADF-3497] update json * [ADF-3497] documentation update * [ADF-3497] specify that sets are not supported * [ADF-3497] no spaces on labels - mention * [ADF-3497] documentation update * [ADF-3497] update examples & document label key * [ADF-3497] tests added * [ADF-3497] testRail id * [ADF-3497] allow config of custom pageSize values * [ADF-3497] support mincount filtering also for intervals * [ADF-3497] support expanded property also for facetIntervals * remove no longer needed info - bcs. of PR #4322 fix
This commit is contained in:
committed by
Eugenio Romano
parent
f20a71438c
commit
e34f80aff7
@@ -122,7 +122,7 @@
|
|||||||
"expanded": true,
|
"expanded": true,
|
||||||
"mincount": 1,
|
"mincount": 1,
|
||||||
"queries": [
|
"queries": [
|
||||||
{ "query": "created:2018", "label": "SEARCH.FACET_QUERIES.CREATED_THIS_YEAR" },
|
{ "query": "created:2019", "label": "SEARCH.FACET_QUERIES.CREATED_THIS_YEAR" },
|
||||||
{ "query": "content.mimetype:text/html", "label": "SEARCH.FACET_QUERIES.MIMETYPE", "group":"Type facet queries" },
|
{ "query": "content.mimetype:text/html", "label": "SEARCH.FACET_QUERIES.MIMETYPE", "group":"Type facet queries" },
|
||||||
{ "query": "content.size:[0 TO 10240]", "label": "SEARCH.FACET_QUERIES.XTRASMALL", "group":"Size facet queries"},
|
{ "query": "content.size:[0 TO 10240]", "label": "SEARCH.FACET_QUERIES.XTRASMALL", "group":"Size facet queries"},
|
||||||
{ "query": "content.size:[10240 TO 102400]", "label": "SEARCH.FACET_QUERIES.SMALL", "group":"Size facet queries"},
|
{ "query": "content.size:[10240 TO 102400]", "label": "SEARCH.FACET_QUERIES.SMALL", "group":"Size facet queries"},
|
||||||
@@ -132,6 +132,30 @@
|
|||||||
{ "query": "content.size:[134217728 TO MAX]", "label": "SEARCH.FACET_QUERIES.XXTRALARGE", "group":"Size facet queries" }
|
{ "query": "content.size:[134217728 TO MAX]", "label": "SEARCH.FACET_QUERIES.XXTRALARGE", "group":"Size facet queries" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"facetIntervals":{
|
||||||
|
"expanded": true,
|
||||||
|
"intervals":[
|
||||||
|
{
|
||||||
|
"label":"TheCreated",
|
||||||
|
"field":"cm:created",
|
||||||
|
"sets":[
|
||||||
|
{ "label":"lastYear", "start":"2018", "end":"2019", "endInclusive":false },
|
||||||
|
{ "label":"currentYear", "start":"NOW/YEAR", "end":"NOW/YEAR+1YEAR" },
|
||||||
|
{ "label":"earlier", "start":"*", "end":"2018", "endInclusive":false }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"TheModified",
|
||||||
|
"field":"cm:modified",
|
||||||
|
"sets":[
|
||||||
|
{ "label":"2017", "start":"2017", "end":"2018", "endInclusive":false },
|
||||||
|
{ "label":"2017-2018", "start":"2017", "end":"2018", "endInclusive":true },
|
||||||
|
{ "label":"currentYear", "start":"NOW/YEAR", "end":"NOW/YEAR+1YEAR" },
|
||||||
|
{ "label":"earlierThan2017", "start":"*", "end":"2017", "endInclusive":false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
{
|
{
|
||||||
"id": "queryName",
|
"id": "queryName",
|
||||||
|
@@ -352,6 +352,56 @@ The default page size of 5 will be used if you set the value to 0 or omit it ent
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
### Facet Intervals
|
||||||
|
|
||||||
|
These provide custom categories based on admin defined ranges inside `intervals`. What is wanted for every interval can be specified exactly in the config file, and having overlapping ranges could also be possible.
|
||||||
|
|
||||||
|
#### FacetIntervals Properties
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
|intervals|array|Specifies the fields to facet by interval.|
|
||||||
|
|expanded|boolean|Toggles expanded state of the facet intervals.|
|
||||||
|
Note: `sets` parameter from Search API (Sets the intervals for all fields) is not yet supported.
|
||||||
|
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"search": {
|
||||||
|
"facetIntervals":{
|
||||||
|
"expanded": true,
|
||||||
|
"intervals":[
|
||||||
|
{
|
||||||
|
"label":"TheCreated",
|
||||||
|
"field":"cm:created",
|
||||||
|
"sets":[
|
||||||
|
{ "label":"lastYear", "start":"2017", "end":"2018", "endInclusive":false },
|
||||||
|
{ "label":"currentYear", "start":"NOW/YEAR", "end":"NOW/YEAR+1YEAR" },
|
||||||
|
{ "label":"earlier", "start":"*", "end":"2017", "endInclusive":false }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"TheModified",
|
||||||
|
"field":"cm:modified",
|
||||||
|
"sets":[
|
||||||
|
{ "label":"2016", "start":"2017", "end":"2018", "endInclusive":false },
|
||||||
|
{ "label":"currentYear", "start":"NOW/YEAR", "end":"NOW/YEAR+1YEAR" },
|
||||||
|
{ "label":"earlierThan2017", "start":"*", "end":"2017", "endInclusive":false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can specify a value for the `mincount` property inside each `intervals` item to set the minimum count required for a facet interval to be displayed. By default, only the intervals that have 1 or more response entries are displayed at runtime.
|
||||||
|
Check the [schema.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/core/app-config/schema.json)
|
||||||
|
for more details about what is the structure and the properties of `intervals` that you can set inside the configuration file.
|
||||||
|
|
||||||
|
Each `intervals` item defined is collected into its collapsible category identified uniquely by its `label`. The top code snippet will result in the following display of the facet intervals:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [Search Query Builder service](search-query-builder.service.md)
|
- [Search Query Builder service](search-query-builder.service.md)
|
||||||
|
BIN
docs/docassets/images/search-facet-intervals.png
Normal file
BIN
docs/docassets/images/search-facet-intervals.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
@@ -37,6 +37,8 @@ export class SearchFiltersPage {
|
|||||||
'mat-expansion-panel[data-automation-id="expansion-panel-My facet queries"]'));
|
'mat-expansion-panel[data-automation-id="expansion-panel-My facet queries"]'));
|
||||||
facetQueriesTypeGroup = element(by.css('mat-expansion-panel[data-automation-id="expansion-panel-Type facet queries"]'));
|
facetQueriesTypeGroup = element(by.css('mat-expansion-panel[data-automation-id="expansion-panel-Type facet queries"]'));
|
||||||
facetQueriesSizeGroup = element(by.css('mat-expansion-panel[data-automation-id="expansion-panel-Size facet queries"]'));
|
facetQueriesSizeGroup = element(by.css('mat-expansion-panel[data-automation-id="expansion-panel-Size facet queries"]'));
|
||||||
|
facetIntervalsByCreated = element(by.css('mat-expansion-panel[data-automation-id="expansion-panel-TheCreated"]'));
|
||||||
|
facetIntervalsByModified = element(by.css('mat-expansion-panel[data-automation-id="expansion-panel-TheModified"]'));
|
||||||
|
|
||||||
checkSearchFiltersIsDisplayed() {
|
checkSearchFiltersIsDisplayed() {
|
||||||
Util.waitUntilElementIsVisible(this.searchFilters);
|
Util.waitUntilElementIsVisible(this.searchFilters);
|
||||||
@@ -110,6 +112,16 @@ export class SearchFiltersPage {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkFacetIntervalsByCreatedIsDisplayed() {
|
||||||
|
this.searchCategoriesPage.checkFilterIsDisplayed(this.facetIntervalsByCreated);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkFacetIntervalsByModifiedIsDisplayed() {
|
||||||
|
this.searchCategoriesPage.checkFilterIsDisplayed(this.facetIntervalsByModified);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
isTypeFacetQueryGroupPresent() {
|
isTypeFacetQueryGroupPresent() {
|
||||||
return this.facetQueriesTypeGroup.isPresent();
|
return this.facetQueriesTypeGroup.isPresent();
|
||||||
}
|
}
|
||||||
|
@@ -207,4 +207,12 @@ describe('Search Filters', () => {
|
|||||||
expect(searchFiltersPage.isTypeFacetQueryGroupPresent()).toBe(false);
|
expect(searchFiltersPage.isTypeFacetQueryGroupPresent()).toBe(false);
|
||||||
expect(searchFiltersPage.isSizeFacetQueryGroupPresent()).toBe(false);
|
expect(searchFiltersPage.isSizeFacetQueryGroupPresent()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('[C297509] Should display search intervals under specified labels from config', () => {
|
||||||
|
browser.get(TestConfig.adf.url + '/search;q=*');
|
||||||
|
|
||||||
|
searchFiltersPage.checkFacetIntervalsByCreatedIsDisplayed()
|
||||||
|
.checkFacetIntervalsByModifiedIsDisplayed();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -202,8 +202,8 @@ describe('SearchFilterComponent', () => {
|
|||||||
queryBuilder.config = {
|
queryBuilder.config = {
|
||||||
categories: [],
|
categories: [],
|
||||||
facetFields: { fields: [
|
facetFields: { fields: [
|
||||||
{ label: 'f1', field: 'f1' },
|
{ label: 'f1', field: 'f1', mincount: 0 },
|
||||||
{ label: 'f2', field: 'f2' }
|
{ label: 'f2', field: 'f2', mincount: 0 }
|
||||||
]},
|
]},
|
||||||
facetQueries: {
|
facetQueries: {
|
||||||
queries: []
|
queries: []
|
||||||
@@ -593,4 +593,92 @@ describe('SearchFilterComponent', () => {
|
|||||||
expect(entry.checked).toBeFalsy();
|
expect(entry.checked).toBeFalsy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fetch facet intervals from response payload', () => {
|
||||||
|
component.responseFacets = null;
|
||||||
|
queryBuilder.config = {
|
||||||
|
categories: [],
|
||||||
|
facetIntervals: {
|
||||||
|
intervals: [
|
||||||
|
{ label: 'test_intervals1', field: 'f1', sets: [
|
||||||
|
{ label: 'interval1', start: 's1', end: 'e1'},
|
||||||
|
{ label: 'interval2', start: 's2', end: 'e2'}
|
||||||
|
]},
|
||||||
|
{ label: 'test_intervals2', field: 'f2', sets: [
|
||||||
|
{ label: 'interval3', start: 's3', end: 'e3'},
|
||||||
|
{ label: 'interval4', start: 's4', end: 'e4'}
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response1 = [
|
||||||
|
{ label: 'interval1', filterQuery: 'query1', metrics: [{ value: { count: 1 }}]},
|
||||||
|
{ label: 'interval2', filterQuery: 'query2', metrics: [{ value: { count: 2 }}]}
|
||||||
|
];
|
||||||
|
const response2 = [
|
||||||
|
{ label: 'interval3', filterQuery: 'query3', metrics: [{ value: { count: 3 }}]},
|
||||||
|
{ label: 'interval4', filterQuery: 'query4', metrics: [{ value: { count: 4 }}]}
|
||||||
|
];
|
||||||
|
const data = {
|
||||||
|
list: {
|
||||||
|
context: {
|
||||||
|
facets: [
|
||||||
|
{ type: 'interval', label: 'test_intervals1', buckets: response1 },
|
||||||
|
{ type: 'interval', label: 'test_intervals2', buckets: response2 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
component.onDataLoaded(data);
|
||||||
|
|
||||||
|
expect(component.responseFacets.length).toBe(2);
|
||||||
|
expect(component.responseFacets[0].buckets.length).toEqual(2);
|
||||||
|
expect(component.responseFacets[1].buckets.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter out the fetched facet intervals that have bucket values less than their set mincount', () => {
|
||||||
|
component.responseFacets = null;
|
||||||
|
queryBuilder.config = {
|
||||||
|
categories: [],
|
||||||
|
facetIntervals: {
|
||||||
|
intervals: [
|
||||||
|
{ label: 'test_intervals1', field: 'f1', mincount: 2, sets: [
|
||||||
|
{ label: 'interval1', start: 's1', end: 'e1'},
|
||||||
|
{ label: 'interval2', start: 's2', end: 'e2'}
|
||||||
|
]},
|
||||||
|
{ label: 'test_intervals2', field: 'f2', mincount: 5, sets: [
|
||||||
|
{ label: 'interval3', start: 's3', end: 'e3'},
|
||||||
|
{ label: 'interval4', start: 's4', end: 'e4'}
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response1 = [
|
||||||
|
{ label: 'interval1', filterQuery: 'query1', metrics: [{ value: { count: 1 }}]},
|
||||||
|
{ label: 'interval2', filterQuery: 'query2', metrics: [{ value: { count: 2 }}]}
|
||||||
|
];
|
||||||
|
const response2 = [
|
||||||
|
{ label: 'interval3', filterQuery: 'query3', metrics: [{ value: { count: 3 }}]},
|
||||||
|
{ label: 'interval4', filterQuery: 'query4', metrics: [{ value: { count: 4 }}]}
|
||||||
|
];
|
||||||
|
const data = {
|
||||||
|
list: {
|
||||||
|
context: {
|
||||||
|
facets: [
|
||||||
|
{ type: 'interval', label: 'test_intervals1', buckets: response1 },
|
||||||
|
{ type: 'interval', label: 'test_intervals2', buckets: response2 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
component.onDataLoaded(data);
|
||||||
|
|
||||||
|
expect(component.responseFacets.length).toBe(2);
|
||||||
|
expect(component.responseFacets[0].buckets.length).toEqual(1);
|
||||||
|
expect(component.responseFacets[1].buckets.length).toEqual(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -41,8 +41,9 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private facetQueriesPageSize = this.DEFAULT_PAGE_SIZE;
|
private facetQueriesPageSize = this.DEFAULT_PAGE_SIZE;
|
||||||
facetQueriesLabel: string = 'Facet Queries';
|
facetQueriesLabel: string = 'Facet Queries';
|
||||||
facetQueriesExpanded = false;
|
facetExpanded = {
|
||||||
facetFieldsExpanded = false;
|
'default': false
|
||||||
|
};
|
||||||
|
|
||||||
selectedBuckets: Array<{ field: FacetField, bucket: FacetFieldBucket }> = [];
|
selectedBuckets: Array<{ field: FacetField, bucket: FacetFieldBucket }> = [];
|
||||||
|
|
||||||
@@ -52,10 +53,13 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
||||||
this.facetQueriesLabel = queryBuilder.config.facetQueries.label || 'Facet Queries';
|
this.facetQueriesLabel = queryBuilder.config.facetQueries.label || 'Facet Queries';
|
||||||
this.facetQueriesPageSize = queryBuilder.config.facetQueries.pageSize || this.DEFAULT_PAGE_SIZE;
|
this.facetQueriesPageSize = queryBuilder.config.facetQueries.pageSize || this.DEFAULT_PAGE_SIZE;
|
||||||
this.facetQueriesExpanded = queryBuilder.config.facetQueries.expanded;
|
this.facetExpanded['query'] = queryBuilder.config.facetQueries.expanded;
|
||||||
}
|
}
|
||||||
if (queryBuilder.config && queryBuilder.config.facetFields) {
|
if (queryBuilder.config && queryBuilder.config.facetFields) {
|
||||||
this.facetFieldsExpanded = queryBuilder.config.facetFields.expanded;
|
this.facetExpanded['field'] = queryBuilder.config.facetFields.expanded;
|
||||||
|
}
|
||||||
|
if (queryBuilder.config && queryBuilder.config.facetIntervals) {
|
||||||
|
this.facetExpanded['interval'] = queryBuilder.config.facetIntervals.expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.queryBuilder.updated.pipe(
|
this.queryBuilder.updated.pipe(
|
||||||
@@ -146,7 +150,7 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shouldExpand(field: FacetField): boolean {
|
shouldExpand(field: FacetField): boolean {
|
||||||
return field.type === 'query' ? this.facetQueriesExpanded : this.facetFieldsExpanded;
|
return this.facetExpanded[field.type] || this.facetExpanded['default'];
|
||||||
}
|
}
|
||||||
|
|
||||||
onDataLoaded(data: any) {
|
onDataLoaded(data: any) {
|
||||||
@@ -162,8 +166,9 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
private parseFacets(context: ResultSetContext) {
|
private parseFacets(context: ResultSetContext) {
|
||||||
if (!this.responseFacets) {
|
if (!this.responseFacets) {
|
||||||
const responseFacetFields = this.parseFacetFields(context);
|
const responseFacetFields = this.parseFacetFields(context);
|
||||||
|
const responseFacetIntervals = this.parseFacetIntervals(context);
|
||||||
const responseGroupedFacetQueries = this.parseFacetQueries(context);
|
const responseGroupedFacetQueries = this.parseFacetQueries(context);
|
||||||
this.responseFacets = responseFacetFields.concat(...responseGroupedFacetQueries);
|
this.responseFacets = responseFacetFields.concat(...responseGroupedFacetQueries, ...responseFacetIntervals);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.responseFacets = this.responseFacets
|
this.responseFacets = this.responseFacets
|
||||||
@@ -184,12 +189,11 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseFacetFields(context: ResultSetContext): FacetField[] {
|
private parseFacetItems(context: ResultSetContext, configFacetFields, itemType): FacetField[] {
|
||||||
const configFacetFields = this.queryBuilder.config.facetFields && this.queryBuilder.config.facetFields.fields || [];
|
|
||||||
|
|
||||||
return configFacetFields.map((field) => {
|
return configFacetFields.map((field) => {
|
||||||
const responseField = (context.facets || []).find((response) => response.type === 'field' && response.label === field.label) || {};
|
const responseField = (context.facets || []).find((response) => response.type === itemType && response.label === field.label) || {};
|
||||||
const responseBuckets = this.getResponseBuckets(responseField);
|
const responseBuckets = this.getResponseBuckets(responseField)
|
||||||
|
.filter(this.getFilterByMinCount(field.mincount));
|
||||||
|
|
||||||
const bucketList = new SearchFilterList<FacetFieldBucket>(responseBuckets, field.pageSize);
|
const bucketList = new SearchFilterList<FacetFieldBucket>(responseBuckets, field.pageSize);
|
||||||
bucketList.filter = (bucket: FacetFieldBucket): boolean => {
|
bucketList.filter = (bucket: FacetFieldBucket): boolean => {
|
||||||
@@ -212,6 +216,16 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private parseFacetFields(context: ResultSetContext): FacetField[] {
|
||||||
|
const configFacetFields = this.queryBuilder.config.facetFields && this.queryBuilder.config.facetFields.fields || [];
|
||||||
|
return this.parseFacetItems(context, configFacetFields, 'field');
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFacetIntervals(context: ResultSetContext): FacetField[] {
|
||||||
|
const configFacetIntervals = this.queryBuilder.config.facetIntervals && this.queryBuilder.config.facetIntervals.intervals || [];
|
||||||
|
return this.parseFacetItems(context, configFacetIntervals, 'interval');
|
||||||
|
}
|
||||||
|
|
||||||
private parseFacetQueries(context: ResultSetContext): FacetField[] {
|
private parseFacetQueries(context: ResultSetContext): FacetField[] {
|
||||||
const configFacetQueries = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.queries || [];
|
const configFacetQueries = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.queries || [];
|
||||||
const configGroups = configFacetQueries.reduce((acc, query) => {
|
const configGroups = configFacetQueries.reduce((acc, query) => {
|
||||||
@@ -225,10 +239,13 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
|
const mincount = this.queryBuilder.config.facetQueries && this.queryBuilder.config.facetQueries.mincount;
|
||||||
|
const mincountFilter = this.getFilterByMinCount(mincount);
|
||||||
|
|
||||||
Object.keys(configGroups).forEach((group) => {
|
Object.keys(configGroups).forEach((group) => {
|
||||||
const responseField = (context.facets || []).find((response) => response.type === 'query' && response.label === group) || {};
|
const responseField = (context.facets || []).find((response) => response.type === 'query' && response.label === group) || {};
|
||||||
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group]);
|
const responseBuckets = this.getResponseQueryBuckets(responseField, configGroups[group])
|
||||||
|
.filter(mincountFilter);
|
||||||
|
|
||||||
const bucketList = new SearchFilterList<FacetFieldBucket>(responseBuckets, this.facetQueriesPageSize);
|
const bucketList = new SearchFilterList<FacetFieldBucket>(responseBuckets, this.facetQueriesPageSize);
|
||||||
bucketList.filter = (bucket: FacetFieldBucket): boolean => {
|
bucketList.filter = (bucket: FacetFieldBucket): boolean => {
|
||||||
@@ -278,12 +295,6 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
display: respBucket.display,
|
display: respBucket.display,
|
||||||
label: respBucket.label
|
label: respBucket.label
|
||||||
};
|
};
|
||||||
}).filter((bucket) => {
|
|
||||||
let mincount = this.queryBuilder.config.facetQueries.mincount;
|
|
||||||
if (mincount === undefined) {
|
|
||||||
mincount = 1;
|
|
||||||
}
|
|
||||||
return bucket.count >= mincount;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,4 +302,14 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
|||||||
return (!!bucket && !!bucket.metrics && bucket.metrics[0] && bucket.metrics[0].value && bucket.metrics[0].value.count)
|
return (!!bucket && !!bucket.metrics && bucket.metrics[0] && bucket.metrics[0].value && bucket.metrics[0].value.count)
|
||||||
|| 0;
|
|| 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getFilterByMinCount(mincountInput: number) {
|
||||||
|
return (bucket) => {
|
||||||
|
let mincount = mincountInput;
|
||||||
|
if (mincount === undefined) {
|
||||||
|
mincount = 1;
|
||||||
|
}
|
||||||
|
return bucket.count >= mincount;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,10 @@ export interface SearchConfiguration {
|
|||||||
expanded?: boolean;
|
expanded?: boolean;
|
||||||
fields: Array<FacetField>;
|
fields: Array<FacetField>;
|
||||||
};
|
};
|
||||||
|
facetIntervals?: {
|
||||||
|
expanded?: boolean;
|
||||||
|
intervals: Array<any>;
|
||||||
|
};
|
||||||
sorting?: {
|
sorting?: {
|
||||||
options: Array<SearchSortingDefinition>;
|
options: Array<SearchSortingDefinition>;
|
||||||
defaults: Array<SearchSortingDefinition>;
|
defaults: Array<SearchSortingDefinition>;
|
||||||
|
@@ -371,6 +371,39 @@ describe('SearchQueryBuilder', () => {
|
|||||||
expect(compiled.facetFields.facets).toEqual(jasmine.objectContaining(config.facetFields.fields));
|
expect(compiled.facetFields.facets).toEqual(jasmine.objectContaining(config.facetFields.fields));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should build query with custom facet intervals', () => {
|
||||||
|
const config: SearchConfiguration = {
|
||||||
|
categories: [
|
||||||
|
<any> { id: 'cat1', enabled: true }
|
||||||
|
],
|
||||||
|
facetIntervals: {
|
||||||
|
intervals: [
|
||||||
|
{
|
||||||
|
label: 'test_intervals1',
|
||||||
|
field: 'f1',
|
||||||
|
sets: [
|
||||||
|
{ label: 'interval1', start: 's1', end: 'e1' },
|
||||||
|
{ label: 'interval2', start: 's2', end: 'e2' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'test_intervals2',
|
||||||
|
field: 'f2',
|
||||||
|
sets: [
|
||||||
|
{ label: 'interval3', start: 's3', end: 'e3' },
|
||||||
|
{ label: 'interval4', start: 's4', end: 'e4' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const builder = new SearchQueryBuilderService(buildConfig(config), null);
|
||||||
|
builder.queryFragments['cat1'] = 'cm:name:test';
|
||||||
|
|
||||||
|
const compiled = builder.buildQuery();
|
||||||
|
expect(compiled.facetIntervals).toEqual(jasmine.objectContaining(config.facetIntervals));
|
||||||
|
});
|
||||||
|
|
||||||
it('should build query with sorting', () => {
|
it('should build query with sorting', () => {
|
||||||
const config: SearchConfiguration = {
|
const config: SearchConfiguration = {
|
||||||
fields: [],
|
fields: [],
|
||||||
|
@@ -224,6 +224,7 @@ export class SearchQueryBuilderService {
|
|||||||
fields: this.config.fields,
|
fields: this.config.fields,
|
||||||
filterQueries: this.filterQueries,
|
filterQueries: this.filterQueries,
|
||||||
facetQueries: this.facetQueries,
|
facetQueries: this.facetQueries,
|
||||||
|
facetIntervals: this.facetIntervals,
|
||||||
facetFields: this.facetFields,
|
facetFields: this.facetFields,
|
||||||
sort: this.sort
|
sort: this.sort
|
||||||
};
|
};
|
||||||
@@ -280,6 +281,20 @@ export class SearchQueryBuilderService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if FacetIntervals has been defined
|
||||||
|
* @returns True if defined, false otherwise
|
||||||
|
*/
|
||||||
|
get hasFacetIntervals(): boolean {
|
||||||
|
if (this.config
|
||||||
|
&& this.config.facetIntervals
|
||||||
|
&& this.config.facetIntervals.intervals
|
||||||
|
&& this.config.facetIntervals.intervals.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected get sort(): RequestSortDefinitionInner[] {
|
protected get sort(): RequestSortDefinitionInner[] {
|
||||||
return this.sorting.map((def) => {
|
return this.sorting.map((def) => {
|
||||||
return new RequestSortDefinitionInner({
|
return new RequestSortDefinitionInner({
|
||||||
@@ -301,6 +316,22 @@ export class SearchQueryBuilderService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected get facetIntervals(): any {
|
||||||
|
if (this.hasFacetIntervals) {
|
||||||
|
const configIntervals = this.config.facetIntervals;
|
||||||
|
|
||||||
|
return {
|
||||||
|
intervals: configIntervals.intervals.map((interval) => <any> {
|
||||||
|
label: interval.label,
|
||||||
|
field: interval.field,
|
||||||
|
sets: interval.sets
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected getFinalQuery(): string {
|
protected getFinalQuery(): string {
|
||||||
let query = '';
|
let query = '';
|
||||||
|
|
||||||
|
@@ -980,6 +980,81 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"facetIntervals": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"intervals"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"intervals": {
|
||||||
|
"description": "List of facet intervals",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"label",
|
||||||
|
"field",
|
||||||
|
"sets"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"label": {
|
||||||
|
"description": "This specifies the label to use to identify the field facet.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"field": {
|
||||||
|
"description": "This specifies the field to facet on.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sets": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"label",
|
||||||
|
"start",
|
||||||
|
"end"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"label": {
|
||||||
|
"description": "This specifies the label to use to identify the set.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"description": "This specifies the start of the range.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"description": "This specifies the end of the range.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"startInclusive": {
|
||||||
|
"description": "When true, the set will include values greater or equal to 'start'. The default value is true.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"endInclusive": {
|
||||||
|
"description": "When true, the set will include values less than or equal to 'end'. The default value is true.",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pageSize": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Display page size"
|
||||||
|
},
|
||||||
|
"mincount": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "This specifies the minimum count required for a facet interval to be displayed. The default value is 1."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expanded": {
|
||||||
|
"description": "Toggles expanded state of the facet intervals",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"facetQueries": {
|
"facetQueries": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -1017,6 +1092,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
"description": "Unique identifier for the query",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
|
Reference in New Issue
Block a user