mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-26 17:24:56 +00:00
[ADF-3365] search filter fixes (#3594)
* preserve ordering of facet fields and queries * update tests * rework facet queries * rework facet management, update unit tests * remove unused interfaces * fix test * remove deprecated interfaces * expose selection for the chip list
This commit is contained in:
parent
98243f0450
commit
c63184334f
@ -83,24 +83,24 @@
|
||||
{ "query": "NOT cm:creator:System" }
|
||||
],
|
||||
"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" }
|
||||
{ "field": "content.mimetype", "mincount": 1, "label": "1:Type" },
|
||||
{ "field": "content.size", "mincount": 1, "label": "2:Size" },
|
||||
{ "field": "creator", "mincount": 1, "label": "3:Creator" },
|
||||
{ "field": "modifier", "mincount": 1, "label": "4:Modifier" },
|
||||
{ "field": "created", "mincount": 1, "label": "5:Created" }
|
||||
],
|
||||
"facetQueries": {
|
||||
"label": "My facet queries",
|
||||
"pageSize": 5,
|
||||
"queries": [
|
||||
{ "query": "created:2018", "label": "Created This Year" },
|
||||
{ "query": "content.mimetype", "label": "Type" },
|
||||
{ "query": "content.size:[0 TO 10240]", "label": "Size: xtra small"},
|
||||
{ "query": "content.size:[10240 TO 102400]", "label": "Size: small"},
|
||||
{ "query": "content.size:[102400 TO 1048576]", "label": "Size: medium" },
|
||||
{ "query": "content.size:[1048576 TO 16777216]", "label": "Size: large" },
|
||||
{ "query": "content.size:[16777216 TO 134217728]", "label": "Size: xtra large" },
|
||||
{ "query": "content.size:[134217728 TO MAX]", "label": "Size: XX large" }
|
||||
{ "query": "created:2018", "label": "1.Created This Year" },
|
||||
{ "query": "content.mimetype", "label": "2.Type" },
|
||||
{ "query": "content.size:[0 TO 10240]", "label": "3.Size: xtra small"},
|
||||
{ "query": "content.size:[10240 TO 102400]", "label": "4.Size: small"},
|
||||
{ "query": "content.size:[102400 TO 1048576]", "label": "5.Size: medium" },
|
||||
{ "query": "content.size:[1048576 TO 16777216]", "label": "6.Size: large" },
|
||||
{ "query": "content.size:[16777216 TO 134217728]", "label": "7.Size: xtra large" },
|
||||
{ "query": "content.size:[134217728 TO MAX]", "label": "8.Size: XX large" }
|
||||
]
|
||||
},
|
||||
"categories": [
|
||||
|
@ -1,14 +1,14 @@
|
||||
<mat-chip-list>
|
||||
<ng-container *ngIf="searchFilter && searchFilter.selectedFacetQueries">
|
||||
<ng-container *ngIf="searchFilter && searchFilter.selectedFacetQueries.length">
|
||||
<mat-chip
|
||||
*ngFor="let label of searchFilter.selectedFacetQueries"
|
||||
*ngFor="let query of searchFilter.selectedFacetQueries"
|
||||
[removable]="true"
|
||||
(remove)="searchFilter.unselectFacetQuery(label)">
|
||||
{{ label | translate }}
|
||||
(remove)="searchFilter.unselectFacetQuery(query)">
|
||||
{{ query.label | translate }}
|
||||
<mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="searchFilter && searchFilter.selectedBuckets">
|
||||
<ng-container *ngIf="searchFilter && searchFilter.selectedBuckets.length">
|
||||
<mat-chip
|
||||
*ngFor="let bucket of searchFilter.selectedBuckets"
|
||||
[removable]="true"
|
||||
|
@ -15,23 +15,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ResponseFacetQuery } from '../../../facet-query.interface';
|
||||
import { FacetQuery } from '../../../facet-query.interface';
|
||||
import { SearchFilterList } from './search-filter-list.model';
|
||||
|
||||
export class ResponseFacetQueryList extends SearchFilterList<ResponseFacetQuery> {
|
||||
constructor(items: ResponseFacetQuery[] = [], pageSize: number = 5) {
|
||||
export class ResponseFacetQueryList extends SearchFilterList<FacetQuery> {
|
||||
constructor(items: FacetQuery[] = [], pageSize: number = 5) {
|
||||
super(
|
||||
items
|
||||
.filter(item => {
|
||||
return item.count > 0;
|
||||
})
|
||||
.map(item => {
|
||||
return <ResponseFacetQuery> { ...item };
|
||||
}),
|
||||
pageSize
|
||||
);
|
||||
|
||||
this.filter = (query: ResponseFacetQuery) => {
|
||||
this.filter = (query: FacetQuery) => {
|
||||
if (this.filterText && query.label) {
|
||||
const pattern = (this.filterText || '').toLowerCase();
|
||||
const label = query.label.toLowerCase();
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
<mat-expansion-panel
|
||||
*ngFor="let category of queryBuilder.categories"
|
||||
[expanded]="category.expanded"
|
||||
(opened)="onCategoryExpanded(category)"
|
||||
(closed)="onCategoryCollapsed(category)">
|
||||
[(expanded)]="category.expanded">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{ category.name | translate }}
|
||||
@ -17,7 +15,8 @@
|
||||
</adf-search-widget-container>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel *ngIf="isFacetQueriesDefined" [expanded]="facetQueriesExpanded">
|
||||
<ng-container *ngIf="responseFacetQueries">
|
||||
<mat-expansion-panel [expanded]="facetQueriesExpanded">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{ facetQueriesLabel | translate }}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
@ -37,15 +36,15 @@
|
||||
<div class="checklist">
|
||||
<ng-container *ngFor="let query of responseFacetQueries">
|
||||
<mat-checkbox
|
||||
[checked]="query.$checked"
|
||||
(change)="onFacetQueryToggle($event, query)">
|
||||
[checked]="query.checked"
|
||||
(change)="onToggleFacetQuery($event, query)">
|
||||
{{ query.label }} ({{ query.count }})
|
||||
</mat-checkbox>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="facet-buttons">
|
||||
<button mat-icon-button
|
||||
*ngIf="canResetSelectedQueries()"
|
||||
*ngIf="canResetSelectedQueries"
|
||||
title="{{ 'SEARCH.FILTER.ACTIONS.CLEAR-ALL' | translate }}"
|
||||
(click)="resetSelectedQueries()">
|
||||
<mat-icon>clear</mat-icon>
|
||||
@ -64,12 +63,10 @@
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
||||
|
||||
<mat-expansion-panel
|
||||
*ngFor="let field of responseFacetFields"
|
||||
[expanded]="field.expanded"
|
||||
(opened)="onFacetFieldExpanded(field)"
|
||||
(closed)="onFacetFieldCollapsed(field)">
|
||||
<ng-container *ngIf="responseFacetFields">
|
||||
<mat-expansion-panel *ngFor="let field of responseFacetFields">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{ field.label }}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
@ -91,8 +88,8 @@
|
||||
<div class="checklist">
|
||||
<mat-checkbox
|
||||
*ngFor="let bucket of field.buckets"
|
||||
[checked]="bucket.$checked"
|
||||
(change)="onFacetToggle($event, field, bucket)">
|
||||
[checked]="bucket.checked"
|
||||
(change)="onToggleBucket($event, bucket)">
|
||||
{{ bucket.display || bucket.label }} ({{ bucket.count }})
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
@ -127,5 +124,5 @@
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
</ng-container>
|
||||
</mat-accordion>
|
||||
|
@ -17,15 +17,15 @@
|
||||
|
||||
import { SearchFilterComponent } from './search-filter.component';
|
||||
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
||||
import { SearchConfiguration } from '../../search-configuration.interface';
|
||||
import { AppConfigService, TranslationMock } from '@alfresco/adf-core';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import { ResponseFacetQueryList } from './models/response-facet-query-list.model';
|
||||
import { ResponseFacetField } from '../../response-facet-field.interface';
|
||||
import { SearchFilterList } from './models/search-filter-list.model';
|
||||
import { FacetFieldBucket } from '../../facet-field-bucket.interface';
|
||||
import { FacetQuery } from '../../facet-query.interface';
|
||||
import { FacetField } from '../../facet-field.interface';
|
||||
import { SearchFilterList } from './models/search-filter-list.model';
|
||||
import { ResponseFacetQueryList } from './models/response-facet-query-list.model';
|
||||
|
||||
describe('SearchSettingsComponent', () => {
|
||||
describe('SearchFilterComponent', () => {
|
||||
|
||||
let component: SearchFilterComponent;
|
||||
let queryBuilder: SearchQueryBuilderService;
|
||||
@ -52,150 +52,60 @@ describe('SearchSettingsComponent', () => {
|
||||
expect(component.onDataLoaded).toHaveBeenCalledWith(data);
|
||||
});
|
||||
|
||||
it('should update category model on expand', () => {
|
||||
const category: any = { expanded: false };
|
||||
|
||||
component.onCategoryExpanded(category);
|
||||
|
||||
expect(category.expanded).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update category model on collapse', () => {
|
||||
const category: any = { expanded: true };
|
||||
|
||||
component.onCategoryCollapsed(category);
|
||||
|
||||
expect(category.expanded).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update facet field model on expand', () => {
|
||||
const field: any = { expanded: false };
|
||||
|
||||
component.onFacetFieldExpanded(field);
|
||||
|
||||
expect(field.expanded).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update facet field model on collapse', () => {
|
||||
const field: any = { expanded: true };
|
||||
|
||||
component.onFacetFieldCollapsed(field);
|
||||
|
||||
expect(field.expanded).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update bucket model and query builder on facet toggle', () => {
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
spyOn(queryBuilder, 'addUserFacetBucket').and.callThrough();
|
||||
|
||||
const event: any = { checked: true };
|
||||
const field: any = {};
|
||||
const bucket: any = { $checked: false, filterQuery: 'q1' };
|
||||
const bucket: FacetFieldBucket = { checked: false, filterQuery: 'q1', label: 'q1', count: 1 };
|
||||
|
||||
component.onFacetToggle(event, field, bucket);
|
||||
|
||||
expect(component.selectedBuckets.length).toBe(1);
|
||||
expect(component.selectedBuckets[0]).toEqual(bucket);
|
||||
|
||||
expect(queryBuilder.filterQueries.length).toBe(1);
|
||||
expect(queryBuilder.filterQueries[0].query).toBe('q1');
|
||||
component.onToggleBucket(event, bucket);
|
||||
|
||||
expect(bucket.checked).toBeTruthy();
|
||||
expect(queryBuilder.addUserFacetBucket).toHaveBeenCalledWith(bucket);
|
||||
expect(queryBuilder.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update bucket model and query builder on facet un-toggle', () => {
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
spyOn(queryBuilder, 'removeUserFacetBucket').and.callThrough();
|
||||
|
||||
const event: any = { checked: false };
|
||||
const field: any = { label: 'f1' };
|
||||
const bucket: any = { $checked: true, filterQuery: 'q1', $field: 'f1', label: 'b1' };
|
||||
const bucket: FacetFieldBucket = { checked: true, filterQuery: 'q1', label: 'q1', count: 1 };
|
||||
|
||||
component.selectedBuckets.push(bucket);
|
||||
queryBuilder.addFilterQuery(bucket.filterQuery);
|
||||
|
||||
component.onFacetToggle(event, field, bucket);
|
||||
|
||||
expect(bucket.$checked).toBeFalsy();
|
||||
expect(component.selectedBuckets.length).toBe(0);
|
||||
expect(queryBuilder.filterQueries.length).toBe(0);
|
||||
component.onToggleBucket(event, bucket);
|
||||
|
||||
expect(queryBuilder.removeUserFacetBucket).toHaveBeenCalledWith(bucket);
|
||||
expect(queryBuilder.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unselect facet query and update builder', () => {
|
||||
const translationMock = new TranslationMock();
|
||||
const config: SearchConfiguration = {
|
||||
categories: [],
|
||||
facetQueries: {
|
||||
queries: [
|
||||
{ label: 'q1', query: 'query1' }
|
||||
]
|
||||
}
|
||||
};
|
||||
appConfig.config.search = config;
|
||||
queryBuilder = new SearchQueryBuilderService(appConfig, null);
|
||||
component = new SearchFilterComponent(queryBuilder, null, translationMock);
|
||||
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
queryBuilder.filterQueries = [{ query: 'query1' }];
|
||||
component.selectedFacetQueries = ['q1'];
|
||||
spyOn(queryBuilder, 'removeUserFacetQuery').and.callThrough();
|
||||
|
||||
component.unselectFacetQuery('q1');
|
||||
const event: any = { checked: false };
|
||||
const query: FacetQuery = { checked: true, label: 'q1', query: 'query1' };
|
||||
|
||||
expect(component.selectedFacetQueries.length).toBe(0);
|
||||
expect(queryBuilder.filterQueries.length).toBe(0);
|
||||
component.onToggleFacetQuery(event, query);
|
||||
|
||||
expect(query.checked).toBeFalsy();
|
||||
expect(queryBuilder.removeUserFacetQuery).toHaveBeenCalledWith(query);
|
||||
expect(queryBuilder.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unselect facet bucket and update builder', () => {
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
|
||||
const bucket: any = { $checked: true, filterQuery: 'q1', $field: 'f1', label: 'b1' };
|
||||
component.selectedBuckets.push(bucket);
|
||||
queryBuilder.filterQueries.push({ query: 'q1' });
|
||||
|
||||
component.unselectFacetBucket(bucket);
|
||||
|
||||
expect(component.selectedBuckets.length).toBe(0);
|
||||
expect(queryBuilder.filterQueries.length).toBe(0);
|
||||
|
||||
expect(queryBuilder.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow facetQueries when defined in configuration', () => {
|
||||
component.queryBuilder.config = {
|
||||
categories: [],
|
||||
facetQueries: {
|
||||
queries: [
|
||||
{ label: 'q1', query: 'query1' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
expect(component.isFacetQueriesDefined).toBe(true);
|
||||
});
|
||||
|
||||
it('should not allow facetQueries when not defined in configuration', () => {
|
||||
component.queryBuilder.config = {
|
||||
categories: []
|
||||
};
|
||||
|
||||
expect(component.isFacetQueriesDefined).toBe(false);
|
||||
});
|
||||
|
||||
it('should not allow facetQueries when queries are not defined in configuration', () => {
|
||||
component.queryBuilder.config = {
|
||||
categories: [],
|
||||
facetQueries: {
|
||||
queries: []
|
||||
}
|
||||
};
|
||||
|
||||
expect(component.isFacetQueriesDefined).toBe(false);
|
||||
});
|
||||
|
||||
it('should fetch facet queries from response payload', () => {
|
||||
component.responseFacetQueries = new ResponseFacetQueryList();
|
||||
component.responseFacetQueries = null;
|
||||
|
||||
queryBuilder.config = {
|
||||
categories: [],
|
||||
facetQueries: {
|
||||
queries: [
|
||||
{ label: 'q1', query: 'query1' },
|
||||
{ label: 'q2', query: 'query2' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const queries = [
|
||||
{ label: 'q1', query: 'query1', count: 1 },
|
||||
{ label: 'q2', query: 'query2', count: 1 }
|
||||
@ -214,8 +124,51 @@ describe('SearchSettingsComponent', () => {
|
||||
expect(component.responseFacetQueries.items).toEqual(queries);
|
||||
});
|
||||
|
||||
it('should preserve order after response processing', () => {
|
||||
component.responseFacetQueries = null;
|
||||
|
||||
queryBuilder.config = {
|
||||
categories: [],
|
||||
facetQueries: {
|
||||
queries: [
|
||||
{ label: 'q1', query: 'query1' },
|
||||
{ label: 'q2', query: 'query2' },
|
||||
{ label: 'q3', query: 'query3' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const queries = [
|
||||
{ label: 'q2', query: 'query2', count: 1 },
|
||||
{ label: 'q1', query: 'query1', count: 1 },
|
||||
{ label: 'q3', query: 'query3', count: 1 }
|
||||
|
||||
];
|
||||
const data = {
|
||||
list: {
|
||||
context: {
|
||||
facetQueries: queries
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetQueries.length).toBe(3);
|
||||
expect(component.responseFacetQueries.items[0].label).toBe('q1');
|
||||
expect(component.responseFacetQueries.items[1].label).toBe('q2');
|
||||
expect(component.responseFacetQueries.items[2].label).toBe('q3');
|
||||
});
|
||||
|
||||
it('should not fetch facet queries from response payload', () => {
|
||||
component.responseFacetQueries = new ResponseFacetQueryList();
|
||||
component.responseFacetQueries = null;
|
||||
|
||||
queryBuilder.config = {
|
||||
categories: [],
|
||||
facetQueries: {
|
||||
queries: []
|
||||
}
|
||||
};
|
||||
|
||||
const data = {
|
||||
list: {
|
||||
@ -227,57 +180,22 @@ describe('SearchSettingsComponent', () => {
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetQueries.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should restore checked state for new response facet queries', () => {
|
||||
component.selectedFacetQueries = ['q3'];
|
||||
component.responseFacetQueries = new ResponseFacetQueryList();
|
||||
|
||||
const queries = [
|
||||
{ label: 'q1', query: 'query1', count: 1 },
|
||||
{ label: 'q2', query: 'query2', count: 1 }
|
||||
];
|
||||
const data = {
|
||||
list: {
|
||||
context: {
|
||||
facetQueries: queries
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetQueries.length).toBe(2);
|
||||
expect((<any> component.responseFacetQueries.items[0]).$checked).toBeFalsy();
|
||||
expect((<any> component.responseFacetQueries.items[1]).$checked).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not restore checked state for new response facet queries', () => {
|
||||
component.selectedFacetQueries = ['q2'];
|
||||
component.responseFacetQueries = new ResponseFacetQueryList();
|
||||
|
||||
const queries = [
|
||||
{ label: 'q1', query: 'query1', count: 1 },
|
||||
{ label: 'q2', query: 'query2', count: 1 }
|
||||
];
|
||||
const data = {
|
||||
list: {
|
||||
context: {
|
||||
facetQueries: queries
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetQueries.length).toBe(2);
|
||||
expect((<any> component.responseFacetQueries.items[0]).$checked).toBeFalsy();
|
||||
expect((<any> component.responseFacetQueries.items[1]).$checked).toBeTruthy();
|
||||
expect(component.responseFacetQueries).toBeNull();
|
||||
});
|
||||
|
||||
it('should fetch facet fields from response payload', () => {
|
||||
component.responseFacetFields = [];
|
||||
component.responseFacetFields = null;
|
||||
|
||||
queryBuilder.config = {
|
||||
categories: [],
|
||||
facetFields: [
|
||||
{ label: 'f1', field: 'f1' },
|
||||
{ label: 'f2', field: 'f2' }
|
||||
],
|
||||
facetQueries: {
|
||||
queries: []
|
||||
}
|
||||
};
|
||||
|
||||
const fields: any = [
|
||||
{ label: 'f1', buckets: [] },
|
||||
@ -293,95 +211,25 @@ describe('SearchSettingsComponent', () => {
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetFields).toEqual(fields);
|
||||
});
|
||||
|
||||
it('should restore expanded state for new response facet fields', () => {
|
||||
component.responseFacetFields = <any> [
|
||||
{ label: 'f1', buckets: [] },
|
||||
{ label: 'f2', buckets: [], expanded: true }
|
||||
];
|
||||
|
||||
const fields = [
|
||||
{ label: 'f1', buckets: [] },
|
||||
{ label: 'f2', buckets: [] }
|
||||
];
|
||||
const data = {
|
||||
list: {
|
||||
context: {
|
||||
facetsFields: fields
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetFields.length).toBe(2);
|
||||
expect(component.responseFacetFields[0].expanded).toBeFalsy();
|
||||
expect(component.responseFacetFields[1].expanded).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should restore checked buckets for new response facet fields', () => {
|
||||
const bucket1 = { label: 'b1', $field: 'f1', count: 1, filterQuery: 'q1' };
|
||||
const bucket2 = { label: 'b2', $field: 'f2', count: 1, filterQuery: 'q2' };
|
||||
|
||||
component.selectedBuckets = [bucket2];
|
||||
component.responseFacetFields = <any> [
|
||||
{ label: 'f2', buckets: [] }
|
||||
];
|
||||
|
||||
const data = {
|
||||
list: {
|
||||
context: {
|
||||
facetsFields: [
|
||||
{ label: 'f1', buckets: [bucket1] },
|
||||
{ label: 'f2', buckets: [bucket2] }
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetFields.length).toBe(2);
|
||||
expect(component.responseFacetFields[0].buckets.items[0].$checked).toBeFalsy();
|
||||
expect(component.responseFacetFields[1].buckets.items[0].$checked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should reset queries and fields on empty response payload', () => {
|
||||
component.responseFacetQueries = new ResponseFacetQueryList([<any> {}, <any> {}]);
|
||||
component.responseFacetFields = [<any> {}, <any> {}];
|
||||
|
||||
const data = {
|
||||
list: {
|
||||
context: {
|
||||
facetQueries: null,
|
||||
facetsFields: null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
component.onDataLoaded(data);
|
||||
|
||||
expect(component.responseFacetQueries.length).toBe(0);
|
||||
expect(component.responseFacetFields.length).toBe(0);
|
||||
expect(component.responseFacetFields.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should update query builder only when has bucket to unselect', () => {
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
|
||||
component.unselectFacetBucket(null);
|
||||
component.onToggleBucket(<any> { checked: true }, null);
|
||||
|
||||
expect(queryBuilder.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow to to reset selected buckets', () => {
|
||||
const buckets: FacetFieldBucket[] = [
|
||||
{ label: 'bucket1', $checked: true, count: 1, filterQuery: 'q1' },
|
||||
{ label: 'bucket2', $checked: false, count: 1, filterQuery: 'q2' }
|
||||
{ label: 'bucket1', checked: true, count: 1, filterQuery: 'q1' },
|
||||
{ label: 'bucket2', checked: false, count: 1, filterQuery: 'q2' }
|
||||
];
|
||||
|
||||
const field: ResponseFacetField = {
|
||||
const field: FacetField = {
|
||||
field: 'f1',
|
||||
label: 'field1',
|
||||
buckets: new SearchFilterList<FacetFieldBucket>(buckets)
|
||||
};
|
||||
@ -391,11 +239,12 @@ describe('SearchSettingsComponent', () => {
|
||||
|
||||
it('should not allow to reset selected buckets', () => {
|
||||
const buckets: FacetFieldBucket[] = [
|
||||
{ label: 'bucket1', $checked: false, count: 1, filterQuery: 'q1' },
|
||||
{ label: 'bucket2', $checked: false, count: 1, filterQuery: 'q2' }
|
||||
{ label: 'bucket1', checked: false, count: 1, filterQuery: 'q1' },
|
||||
{ label: 'bucket2', checked: false, count: 1, filterQuery: 'q2' }
|
||||
];
|
||||
|
||||
const field: ResponseFacetField = {
|
||||
const field: FacetField = {
|
||||
field: 'f1',
|
||||
label: 'field1',
|
||||
buckets: new SearchFilterList<FacetFieldBucket>(buckets)
|
||||
};
|
||||
@ -405,70 +254,57 @@ describe('SearchSettingsComponent', () => {
|
||||
|
||||
it('should reset selected buckets', () => {
|
||||
const buckets: FacetFieldBucket[] = [
|
||||
{ label: 'bucket1', $checked: false, count: 1, filterQuery: 'q1', $field: 'field1' },
|
||||
{ label: 'bucket2', $checked: true, count: 1, filterQuery: 'q2', $field: 'field1' }
|
||||
{ label: 'bucket1', checked: false, count: 1, filterQuery: 'q1' },
|
||||
{ label: 'bucket2', checked: true, count: 1, filterQuery: 'q2' }
|
||||
];
|
||||
|
||||
const field: ResponseFacetField = {
|
||||
const field: FacetField = {
|
||||
field: 'f1',
|
||||
label: 'field1',
|
||||
buckets: new SearchFilterList<FacetFieldBucket>(buckets)
|
||||
};
|
||||
|
||||
component.selectedBuckets = [buckets[1]];
|
||||
component.resetSelectedBuckets(field);
|
||||
|
||||
expect(buckets[0].$checked).toBeFalsy();
|
||||
expect(buckets[1].$checked).toBeFalsy();
|
||||
expect(component.selectedBuckets.length).toBe(0);
|
||||
expect(buckets[0].checked).toBeFalsy();
|
||||
expect(buckets[1].checked).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update query builder upon resetting buckets', () => {
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
|
||||
const buckets: FacetFieldBucket[] = [
|
||||
{ label: 'bucket1', $checked: false, count: 1, filterQuery: 'q1', $field: 'field1' },
|
||||
{ label: 'bucket2', $checked: true, count: 1, filterQuery: 'q2', $field: 'field1' }
|
||||
{ label: 'bucket1', checked: false, count: 1, filterQuery: 'q1' },
|
||||
{ label: 'bucket2', checked: true, count: 1, filterQuery: 'q2' }
|
||||
];
|
||||
|
||||
const field: ResponseFacetField = {
|
||||
const field: FacetField = {
|
||||
field: 'f1',
|
||||
label: 'field1',
|
||||
buckets: new SearchFilterList<FacetFieldBucket>(buckets)
|
||||
};
|
||||
|
||||
component.selectedBuckets = [buckets[1]];
|
||||
component.resetSelectedBuckets(field);
|
||||
|
||||
expect(queryBuilder.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow to reset selected queries', () => {
|
||||
component.selectedFacetQueries = ['q1', 'q2'];
|
||||
expect(component.canResetSelectedQueries()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not allow to reset selected queries when nothing selected', () => {
|
||||
component.selectedFacetQueries = [];
|
||||
expect(component.canResetSelectedQueries()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should reset selected queries', () => {
|
||||
const methodSpy = spyOn(component, 'unselectFacetQuery').and.stub();
|
||||
|
||||
component.selectedFacetQueries = ['q1', 'q2'];
|
||||
component.resetSelectedQueries();
|
||||
|
||||
expect(methodSpy.calls.count()).toBe(2);
|
||||
expect(methodSpy.calls.argsFor(0)).toEqual(['q1', false]);
|
||||
expect(methodSpy.calls.argsFor(1)).toEqual(['q2', false]);
|
||||
});
|
||||
|
||||
it('should update query builder upon resetting selected queries', () => {
|
||||
spyOn(queryBuilder, 'update').and.stub();
|
||||
spyOn(queryBuilder, 'removeUserFacetQuery').and.callThrough();
|
||||
|
||||
component.selectedFacetQueries = ['q1', 'q2'];
|
||||
component.canResetSelectedQueries = true;
|
||||
component.responseFacetQueries = new ResponseFacetQueryList([
|
||||
{ label: 'q1', query: 'q1', checked: true, count: 1 },
|
||||
{ label: 'q2', query: 'q2', checked: false, count: 1 },
|
||||
{ label: 'q3', query: 'q3', checked: true, count: 1 }
|
||||
]);
|
||||
component.resetSelectedQueries();
|
||||
|
||||
expect(queryBuilder.removeUserFacetQuery).toHaveBeenCalledTimes(3);
|
||||
expect(queryBuilder.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
for (let entry of component.responseFacetQueries.items) {
|
||||
expect(entry.checked).toBeFalsy();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -19,11 +19,10 @@ import { Component, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
|
||||
import { MatCheckboxChange } from '@angular/material';
|
||||
import { SearchService, TranslationService } from '@alfresco/adf-core';
|
||||
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
||||
import { ResponseFacetField } from '../../response-facet-field.interface';
|
||||
import { FacetFieldBucket } from '../../facet-field-bucket.interface';
|
||||
import { SearchCategory } from '../../search-category.interface';
|
||||
import { ResponseFacetQuery } from '../../response-facet-query.interface';
|
||||
import { ResponseFacetQueryList } from './models/response-facet-query-list.model';
|
||||
import { FacetQuery } from '../../facet-query.interface';
|
||||
import { FacetField } from '../../facet-field.interface';
|
||||
import { SearchFilterList } from './models/search-filter-list.model';
|
||||
|
||||
@Component({
|
||||
@ -38,20 +37,20 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
||||
private DEFAULT_PAGE_SIZE = 5;
|
||||
|
||||
isAlive = true;
|
||||
selectedFacetQueries: string[] = [];
|
||||
selectedBuckets: FacetFieldBucket[] = [];
|
||||
responseFacetQueries: ResponseFacetQueryList;
|
||||
responseFacetFields: ResponseFacetField[] = [];
|
||||
responseFacetQueries: ResponseFacetQueryList = null;
|
||||
responseFacetFields: FacetField[] = null;
|
||||
|
||||
private facetQueriesPageSize = this.DEFAULT_PAGE_SIZE;
|
||||
facetQueriesLabel: string = 'Facet Queries';
|
||||
facetQueriesPageSize = this.DEFAULT_PAGE_SIZE;
|
||||
facetQueriesExpanded = false;
|
||||
canResetSelectedQueries = false;
|
||||
|
||||
selectedFacetQueries: Array<FacetQuery> = [];
|
||||
selectedBuckets: Array<FacetFieldBucket> = [];
|
||||
|
||||
constructor(public queryBuilder: SearchQueryBuilderService,
|
||||
private searchService: SearchService,
|
||||
private translationService: TranslationService) {
|
||||
this.responseFacetQueries = new ResponseFacetQueryList();
|
||||
|
||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
||||
this.facetQueriesLabel = queryBuilder.config.facetQueries.label || 'Facet Queries';
|
||||
this.facetQueriesPageSize = queryBuilder.config.facetQueries.pageSize || this.DEFAULT_PAGE_SIZE;
|
||||
@ -60,7 +59,7 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.queryBuilder.updated
|
||||
.takeWhile(() => this.isAlive)
|
||||
.subscribe(query => {
|
||||
.subscribe(() => {
|
||||
this.queryBuilder.execute();
|
||||
});
|
||||
}
|
||||
@ -80,125 +79,111 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
||||
this.isAlive = false;
|
||||
}
|
||||
|
||||
get isFacetQueriesDefined() {
|
||||
return this.queryBuilder.hasFacetQueries;
|
||||
}
|
||||
|
||||
onCategoryExpanded(category: SearchCategory) {
|
||||
category.expanded = true;
|
||||
}
|
||||
|
||||
onCategoryCollapsed(category: SearchCategory) {
|
||||
category.expanded = false;
|
||||
}
|
||||
|
||||
onFacetFieldExpanded(field: ResponseFacetField) {
|
||||
field.expanded = true;
|
||||
}
|
||||
|
||||
onFacetFieldCollapsed(field: ResponseFacetField) {
|
||||
field.expanded = false;
|
||||
}
|
||||
|
||||
onFacetQueryToggle(event: MatCheckboxChange, query: ResponseFacetQuery) {
|
||||
const facetQuery = this.queryBuilder.getFacetQuery(query.label);
|
||||
|
||||
onToggleFacetQuery(event: MatCheckboxChange, facetQuery: FacetQuery) {
|
||||
if (event && facetQuery) {
|
||||
if (event.checked) {
|
||||
query.$checked = true;
|
||||
this.selectedFacetQueries.push(facetQuery.label);
|
||||
this.selectFacetQuery(facetQuery);
|
||||
} else {
|
||||
this.unselectFacetQuery(facetQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (facetQuery) {
|
||||
this.queryBuilder.addFilterQuery(facetQuery.query);
|
||||
selectFacetQuery(query: FacetQuery) {
|
||||
if (query) {
|
||||
query.checked = true;
|
||||
this.queryBuilder.addUserFacetQuery(query);
|
||||
this.updateSelectedFields();
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
|
||||
unselectFacetQuery(query: FacetQuery) {
|
||||
if (query) {
|
||||
query.checked = false;
|
||||
this.queryBuilder.removeUserFacetQuery(query);
|
||||
this.updateSelectedFields();
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
|
||||
private updateSelectedBuckets() {
|
||||
if (this.responseFacetFields) {
|
||||
this.selectedBuckets = [];
|
||||
for (let field of this.responseFacetFields) {
|
||||
if (field.buckets) {
|
||||
this.selectedBuckets.push(...field.buckets.items.filter(bucket => bucket.checked));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query.$checked = false;
|
||||
this.selectedFacetQueries = this.selectedFacetQueries.filter(selectedQuery => selectedQuery !== query.label);
|
||||
|
||||
if (facetQuery) {
|
||||
this.queryBuilder.removeFilterQuery(facetQuery.query);
|
||||
this.selectedBuckets = [];
|
||||
}
|
||||
}
|
||||
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
|
||||
onFacetToggle(event: MatCheckboxChange, field: ResponseFacetField, bucket: FacetFieldBucket) {
|
||||
if (event.checked) {
|
||||
bucket.$checked = true;
|
||||
this.selectedBuckets.push({ ...bucket });
|
||||
this.queryBuilder.addFilterQuery(bucket.filterQuery);
|
||||
private updateSelectedFields() {
|
||||
if (this.responseFacetQueries) {
|
||||
this.selectedFacetQueries = this.responseFacetQueries.items.filter(item => item.checked);
|
||||
this.canResetSelectedQueries = this.selectedFacetQueries.length > 0;
|
||||
} else {
|
||||
bucket.$checked = false;
|
||||
const idx = this.selectedBuckets.findIndex(
|
||||
b => b.$field === bucket.$field && b.label === bucket.label
|
||||
);
|
||||
|
||||
if (idx >= 0) {
|
||||
this.selectedBuckets.splice(idx, 1);
|
||||
}
|
||||
this.queryBuilder.removeFilterQuery(bucket.filterQuery);
|
||||
}
|
||||
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
|
||||
unselectFacetQuery(label: string, reloadQuery: boolean = true) {
|
||||
const facetQuery = this.queryBuilder.getFacetQuery(label);
|
||||
if (facetQuery) {
|
||||
this.queryBuilder.removeFilterQuery(facetQuery.query);
|
||||
}
|
||||
|
||||
this.selectedFacetQueries = this.selectedFacetQueries.filter(selectedQuery => selectedQuery !== label);
|
||||
|
||||
if (reloadQuery) {
|
||||
this.queryBuilder.update();
|
||||
this.selectedFacetQueries = [];
|
||||
this.canResetSelectedQueries = false;
|
||||
}
|
||||
}
|
||||
|
||||
unselectFacetBucket(bucket: FacetFieldBucket, reloadQuery: boolean = true) {
|
||||
onToggleBucket(event: MatCheckboxChange, bucket: FacetFieldBucket) {
|
||||
if (event && bucket) {
|
||||
if (event.checked) {
|
||||
this.selectFacetBucket(bucket);
|
||||
} else {
|
||||
this.unselectFacetBucket(bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectFacetBucket(bucket: FacetFieldBucket) {
|
||||
if (bucket) {
|
||||
const idx = this.selectedBuckets.findIndex(
|
||||
selectedBucket => selectedBucket.$field === bucket.$field && selectedBucket.label === bucket.label
|
||||
);
|
||||
|
||||
if (idx >= 0) {
|
||||
this.selectedBuckets.splice(idx, 1);
|
||||
}
|
||||
this.queryBuilder.removeFilterQuery(bucket.filterQuery);
|
||||
|
||||
bucket.$checked = false;
|
||||
|
||||
if (reloadQuery) {
|
||||
bucket.checked = true;
|
||||
this.queryBuilder.addUserFacetBucket(bucket);
|
||||
this.updateSelectedBuckets();
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canResetSelectedQueries(): boolean {
|
||||
return this.selectedFacetQueries && this.selectedFacetQueries.length > 0;
|
||||
unselectFacetBucket(bucket: FacetFieldBucket) {
|
||||
if (bucket) {
|
||||
bucket.checked = false;
|
||||
this.queryBuilder.removeUserFacetBucket(bucket);
|
||||
this.updateSelectedBuckets();
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
|
||||
resetSelectedQueries() {
|
||||
if (this.canResetSelectedQueries()) {
|
||||
this.selectedFacetQueries.forEach(query => {
|
||||
this.unselectFacetQuery(query, false);
|
||||
});
|
||||
if (this.canResetSelectedQueries) {
|
||||
for (let query of this.responseFacetQueries.items) {
|
||||
query.checked = false;
|
||||
this.queryBuilder.removeUserFacetQuery(query);
|
||||
}
|
||||
this.selectedFacetQueries = [];
|
||||
this.canResetSelectedQueries = false;
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
|
||||
canResetSelectedBuckets(field: ResponseFacetField): boolean {
|
||||
canResetSelectedBuckets(field: FacetField): boolean {
|
||||
if (field && field.buckets) {
|
||||
return field.buckets.items.some(bucket => bucket.$checked);
|
||||
return field.buckets.items.some(bucket => bucket.checked);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
resetSelectedBuckets(field: ResponseFacetField) {
|
||||
resetSelectedBuckets(field: FacetField) {
|
||||
if (field && field.buckets) {
|
||||
field.buckets.items.forEach(bucket => {
|
||||
this.unselectFacetBucket(bucket, false);
|
||||
});
|
||||
for (let bucket of field.buckets.items) {
|
||||
bucket.checked = false;
|
||||
this.queryBuilder.removeUserFacetBucket(bucket);
|
||||
}
|
||||
this.updateSelectedBuckets();
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
@ -207,47 +192,27 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
||||
const context = data.list.context;
|
||||
|
||||
if (context) {
|
||||
const facetQueries = (context.facetQueries || []).map(query => {
|
||||
query.label = this.translationService.instant(query.label);
|
||||
query.$checked = this.selectedFacetQueries.includes(query.label);
|
||||
return query;
|
||||
});
|
||||
|
||||
this.responseFacetQueries = new ResponseFacetQueryList(facetQueries, this.facetQueriesPageSize);
|
||||
|
||||
const expandedFields = this.responseFacetFields
|
||||
.filter(field => field.expanded)
|
||||
.map(field => field.label);
|
||||
|
||||
this.responseFacetFields = (context.facetsFields || []).map(
|
||||
field => {
|
||||
const settings = this.queryBuilder.getFacetField(field.label);
|
||||
|
||||
let fallbackPageSize = this.DEFAULT_PAGE_SIZE;
|
||||
if (settings && settings.pageSize) {
|
||||
fallbackPageSize = settings.pageSize;
|
||||
this.parseFacetFields(context);
|
||||
this.parseFacetQueries(context);
|
||||
} else {
|
||||
this.responseFacetQueries = null;
|
||||
this.responseFacetFields = null;
|
||||
}
|
||||
}
|
||||
|
||||
field.label = this.translationService.instant(field.label);
|
||||
field.pageSize = field.pageSize || fallbackPageSize;
|
||||
field.currentPageSize = field.pageSize;
|
||||
field.expanded = expandedFields.includes(field.label);
|
||||
|
||||
const buckets = (field.buckets || []).map(bucket => {
|
||||
bucket.$field = field.label;
|
||||
bucket.$checked = false;
|
||||
bucket.display = this.translationService.instant(bucket.display);
|
||||
bucket.label = this.translationService.instant(bucket.label);
|
||||
|
||||
const previousBucket = this.selectedBuckets.find(
|
||||
selectedBucket => selectedBucket.$field === bucket.$field && selectedBucket.label === bucket.label
|
||||
);
|
||||
if (previousBucket) {
|
||||
bucket.$checked = true;
|
||||
}
|
||||
return bucket;
|
||||
private parseFacetFields(context: any) {
|
||||
if (!this.responseFacetFields) {
|
||||
const configFacetFields = this.queryBuilder.config.facetFields || [];
|
||||
this.responseFacetFields = configFacetFields.map(field => {
|
||||
const responseField = (context.facetsFields || []).find(response => response.label === field.label);
|
||||
const buckets: FacetFieldBucket[] = (responseField.buckets || []).map(bucket => {
|
||||
return <FacetFieldBucket> {
|
||||
...bucket,
|
||||
checked: false,
|
||||
display: this.translationService.instant(bucket.display),
|
||||
label: this.translationService.instant(bucket.label)
|
||||
};
|
||||
});
|
||||
|
||||
const bucketList = new SearchFilterList<FacetFieldBucket>(buckets, field.pageSize);
|
||||
bucketList.filter = (bucket: FacetFieldBucket): boolean => {
|
||||
if (bucket && bucketList.filterText) {
|
||||
@ -257,14 +222,45 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return {
|
||||
...field,
|
||||
label: this.translationService.instant(field.label),
|
||||
pageSize: field.pageSize | this.DEFAULT_PAGE_SIZE,
|
||||
currentPageSize: field.pageSize | this.DEFAULT_PAGE_SIZE,
|
||||
buckets: bucketList
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
field.buckets = bucketList;
|
||||
return field;
|
||||
}
|
||||
);
|
||||
private parseFacetQueries(context: any) {
|
||||
const responseQueries = this.getFacetQueryMap(context);
|
||||
if (!this.responseFacetQueries) {
|
||||
const facetQueries = (this.queryBuilder.config.facetQueries.queries || [])
|
||||
.map(query => {
|
||||
const queryResult = responseQueries[query.label];
|
||||
return <FacetQuery> {
|
||||
...query,
|
||||
label: this.translationService.instant(query.label),
|
||||
count: queryResult.count
|
||||
};
|
||||
});
|
||||
|
||||
if (facetQueries.length > 0) {
|
||||
this.responseFacetQueries = new ResponseFacetQueryList(facetQueries, this.facetQueriesPageSize);
|
||||
} else {
|
||||
this.responseFacetQueries = new ResponseFacetQueryList([], this.facetQueriesPageSize);
|
||||
this.responseFacetFields = [];
|
||||
this.responseFacetQueries = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getFacetQueryMap(context: any): { [key: string]: any } {
|
||||
const result = {};
|
||||
|
||||
(context.facetQueries || []).forEach(query => {
|
||||
result[query.label] = query;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,5 @@ export interface FacetFieldBucket {
|
||||
label: string;
|
||||
filterQuery: string;
|
||||
|
||||
$checked?: boolean;
|
||||
$field?: string;
|
||||
checked?: boolean;
|
||||
}
|
||||
|
@ -15,6 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SearchFilterList } from './components/search-filter/models/search-filter-list.model';
|
||||
import { FacetFieldBucket } from './facet-field-bucket.interface';
|
||||
|
||||
export interface FacetField {
|
||||
field: string;
|
||||
label: string;
|
||||
@ -23,6 +26,8 @@ export interface FacetField {
|
||||
offset?: number;
|
||||
prefix?: string;
|
||||
|
||||
buckets?: SearchFilterList<FacetFieldBucket>;
|
||||
pageSize?: number;
|
||||
$checked?: boolean;
|
||||
currentPageSize?: number;
|
||||
checked?: boolean;
|
||||
}
|
||||
|
@ -16,12 +16,9 @@
|
||||
*/
|
||||
|
||||
export interface FacetQuery {
|
||||
query: string;
|
||||
label: string;
|
||||
}
|
||||
query: string;
|
||||
|
||||
export interface ResponseFacetQuery {
|
||||
label?: string;
|
||||
filterQuery?: string;
|
||||
checked?: boolean;
|
||||
count?: number;
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ export { FacetFieldBucket } from './facet-field-bucket.interface';
|
||||
export { FacetField } from './facet-field.interface';
|
||||
export { FacetQuery } from './facet-query.interface';
|
||||
export { FilterQuery } from './filter-query.interface';
|
||||
export { ResponseFacetField } from './response-facet-field.interface';
|
||||
export { ResponseFacetQuery } from './response-facet-query.interface';
|
||||
export { SearchCategory } from './search-category.interface';
|
||||
export { SearchWidgetSettings } from './search-widget-settings.interface';
|
||||
export { SearchWidget } from './search-widget.interface';
|
||||
|
@ -1,27 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FacetFieldBucket } from './facet-field-bucket.interface';
|
||||
import { SearchFilterList } from './components/search-filter/models/search-filter-list.model';
|
||||
|
||||
export interface ResponseFacetField {
|
||||
label: string;
|
||||
buckets: SearchFilterList<FacetFieldBucket>;
|
||||
pageSize?: number;
|
||||
currentPageSize?: number;
|
||||
expanded?: boolean;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface ResponseFacetQuery {
|
||||
label: string;
|
||||
mincount: number;
|
||||
|
||||
$checked?: boolean;
|
||||
}
|
@ -212,7 +212,7 @@ describe('SearchQueryBuilder', () => {
|
||||
const builder = new SearchQueryBuilderService(buildConfig(config), null);
|
||||
const field = builder.getFacetField('Missing');
|
||||
|
||||
expect(field).toBeUndefined();
|
||||
expect(field).toBeFalsy();
|
||||
});
|
||||
|
||||
xit('should build query and raise an event on update', async () => {
|
||||
|
@ -26,6 +26,7 @@ import { SearchConfiguration } from './search-configuration.interface';
|
||||
import { FacetQuery } from './facet-query.interface';
|
||||
import { SearchSortingDefinition } from './search-sorting-definition.interface';
|
||||
import { FacetField } from './facet-field.interface';
|
||||
import { FacetFieldBucket } from './facet-field-bucket.interface';
|
||||
|
||||
@Injectable()
|
||||
export class SearchQueryBuilderService {
|
||||
@ -41,6 +42,9 @@ export class SearchQueryBuilderService {
|
||||
paging: { maxItems?: number; skipCount?: number } = null;
|
||||
sorting: Array<SearchSortingDefinition> = [];
|
||||
|
||||
protected userFacetQueries: FacetQuery[] = [];
|
||||
protected userFacetBuckets: FacetFieldBucket[] = [];
|
||||
|
||||
get userQuery(): string {
|
||||
return this._userQuery;
|
||||
}
|
||||
@ -65,12 +69,48 @@ export class SearchQueryBuilderService {
|
||||
this.config = JSON.parse(JSON.stringify(template));
|
||||
this.categories = (this.config.categories || []).filter(category => category.enabled);
|
||||
this.filterQueries = this.config.filterQueries || [];
|
||||
this.userFacetBuckets = [];
|
||||
this.userFacetQueries = [];
|
||||
if (this.config.sorting) {
|
||||
this.sorting = this.config.sorting.defaults || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addUserFacetQuery(query: FacetQuery) {
|
||||
if (query) {
|
||||
const existing = this.userFacetQueries.find(facetQuery => facetQuery.label === query.label);
|
||||
if (existing) {
|
||||
existing.query = query.query;
|
||||
} else {
|
||||
this.userFacetQueries.push({ ...query });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeUserFacetQuery(query: FacetQuery) {
|
||||
if (query) {
|
||||
this.userFacetQueries = this.userFacetQueries
|
||||
.filter(facetQuery => facetQuery.label !== query.label);
|
||||
}
|
||||
}
|
||||
|
||||
addUserFacetBucket(bucket: FacetFieldBucket) {
|
||||
if (bucket) {
|
||||
const existing = this.userFacetBuckets.find(facetBucket => facetBucket.label === bucket.label);
|
||||
if (!existing) {
|
||||
this.userFacetBuckets.push(bucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeUserFacetBucket(bucket: FacetFieldBucket) {
|
||||
if (bucket) {
|
||||
this.userFacetBuckets = this.userFacetBuckets
|
||||
.filter(facetBucket => facetBucket.label !== bucket.label);
|
||||
}
|
||||
}
|
||||
|
||||
addFilterQuery(query: string): void {
|
||||
if (query) {
|
||||
const existing = this.filterQueries.find(filterQuery => filterQuery.query === query);
|
||||
@ -89,7 +129,10 @@ export class SearchQueryBuilderService {
|
||||
|
||||
getFacetQuery(label: string): FacetQuery {
|
||||
if (label && this.hasFacetQueries) {
|
||||
return this.config.facetQueries.queries.find(query => query.label === label);
|
||||
const result = this.config.facetQueries.queries.find(query => query.label === label);
|
||||
if (result) {
|
||||
return { ...result };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -97,7 +140,10 @@ export class SearchQueryBuilderService {
|
||||
getFacetField(label: string): FacetField {
|
||||
if (label) {
|
||||
const fields = this.config.facetFields || [];
|
||||
return fields.find(field => field.label === label);
|
||||
const result = fields.find(field => field.label === label);
|
||||
if (result) {
|
||||
return { ...result };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -175,7 +221,7 @@ export class SearchQueryBuilderService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private get sort(): RequestSortDefinitionInner[] {
|
||||
protected get sort(): RequestSortDefinitionInner[] {
|
||||
return this.sorting.map(def => {
|
||||
return {
|
||||
type: def.type,
|
||||
@ -185,7 +231,7 @@ export class SearchQueryBuilderService {
|
||||
});
|
||||
}
|
||||
|
||||
private get facetQueries(): FacetQuery[] {
|
||||
protected get facetQueries(): FacetQuery[] {
|
||||
if (this.hasFacetQueries) {
|
||||
return this.config.facetQueries.queries.map(query => {
|
||||
return <FacetQuery> { ...query };
|
||||
@ -195,7 +241,7 @@ export class SearchQueryBuilderService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private getFinalQuery(): string {
|
||||
protected getFinalQuery(): string {
|
||||
let query = '';
|
||||
|
||||
this.categories.forEach(facet => {
|
||||
@ -208,14 +254,28 @@ export class SearchQueryBuilderService {
|
||||
}
|
||||
});
|
||||
|
||||
const result = [this.userQuery, query]
|
||||
let result = [this.userQuery, query]
|
||||
.filter(entry => entry)
|
||||
.join(' AND ');
|
||||
|
||||
if (this.userFacetQueries && this.userFacetQueries.length > 0) {
|
||||
const combined = this.userFacetQueries
|
||||
.map(userQuery => userQuery.query)
|
||||
.join(' OR ');
|
||||
result += ` AND (${combined})`;
|
||||
}
|
||||
|
||||
if (this.userFacetBuckets && this.userFacetBuckets.length > 0) {
|
||||
const combined = this.userFacetBuckets
|
||||
.map(bucket => bucket.filterQuery)
|
||||
.join(' OR ');
|
||||
result += ` AND (${combined})`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private get facetFields(): RequestFacetFields {
|
||||
protected get facetFields(): RequestFacetFields {
|
||||
const facetFields = this.config.facetFields;
|
||||
|
||||
if (facetFields && facetFields.length > 0) {
|
||||
|
@ -5031,22 +5031,6 @@
|
||||
},
|
||||
"name": "RequiredFieldValidator"
|
||||
},
|
||||
{
|
||||
"position": {
|
||||
"line": 21,
|
||||
"character": 9,
|
||||
"fileName": "lib/content-services/search/public-api.ts"
|
||||
},
|
||||
"name": "ResponseFacetField"
|
||||
},
|
||||
{
|
||||
"position": {
|
||||
"line": 22,
|
||||
"character": 9,
|
||||
"fileName": "lib/content-services/search/public-api.ts"
|
||||
},
|
||||
"name": "ResponseFacetQuery"
|
||||
},
|
||||
{
|
||||
"position": {
|
||||
"line": 25,
|
||||
|
Loading…
x
Reference in New Issue
Block a user