[ACA-3507] [ACA-3523] Fix Filters (#5821)

* fix search one letter
fix navigation
add new property search text prefix and suffix

* fix unit test

* fix unit test

* fix failing test
This commit is contained in:
Eugenio Romano 2020-06-29 17:27:52 +01:00 committed by GitHub
parent 0183f9e7f7
commit 5180493aa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 102 additions and 64 deletions

View File

@ -459,7 +459,8 @@
"settings": {
"pattern": "cm:name:'(.*?)'",
"field": "cm:name",
"placeholder": "Enter the name"
"placeholder": "Enter the name",
"searchSuffix" : "*"
}
}
},

View File

@ -25,6 +25,8 @@ Implements a text input [widget](../../../lib/testing/src/lib/core/pages/form/wi
"component": {
"selector": "text",
"settings": {
"searchPrefix": "",
"searchSuffix": "",
"pattern": "cm:name:'(.*?)'",
"field": "cm:name",
"placeholder": "Enter the name"
@ -43,6 +45,8 @@ Implements a text input [widget](../../../lib/testing/src/lib/core/pages/form/wi
| field | string | Field to apply the query fragment to. Required value |
| pattern | string | Regular expression pattern to restrict the format of the input text |
| placeholder | string | Text displayed in the [widget](../../../lib/testing/src/lib/core/pages/form/widgets/widget.ts) when the input string is empty |
| searchSuffix | string | Text to append always in the search of a string|
| searchPrefix | string | Text to prepend always in the search of a string|
## Details

View File

@ -43,6 +43,7 @@ export class SearchCheckListComponent implements SearchWidget, OnInit {
options: SearchFilterList<SearchListOption>;
operator: string = 'OR';
pageSize = 5;
isActive = false;
constructor() {
this.options = new SearchFilterList<SearchListOption>();
@ -60,6 +61,7 @@ export class SearchCheckListComponent implements SearchWidget, OnInit {
}
reset() {
this.isActive = false;
this.options.items.forEach((opt) => {
opt.checked = false;
});
@ -80,6 +82,8 @@ export class SearchCheckListComponent implements SearchWidget, OnInit {
.filter((option) => option.checked)
.map((option) => option.value);
this.isActive = !!checkedValues.length;
const query = checkedValues.join(` ${this.operator} `);
if (this.id && this.context) {

View File

@ -56,6 +56,8 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
context?: SearchQueryBuilderService;
datePickerDateFormat = DEFAULT_FORMAT_DATE;
maxDate: any;
isActive = false;
private onDestroy$ = new Subject<boolean>();
constructor(private dateAdapter: DateAdapter<Moment>,
@ -117,6 +119,8 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
apply(model: { from: string, to: string }, isValid: boolean) {
if (isValid && this.id && this.context && this.settings && this.settings.field) {
this.isActive = true;
const start = moment(model.from).startOf('day').format();
const end = moment(model.to).endOf('day').format();
@ -130,6 +134,7 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy
}
reset() {
this.isActive = false;
this.form.reset({
from: '',
to: ''

View File

@ -7,10 +7,10 @@
class="adf-filter-button"
[matTooltip]="getTooltipTranslation(col?.title)">
<adf-icon value="adf:filter"
[ngClass]="{ 'adf-icon-active': isActive || menuTrigger.menuOpen }"
[ngClass]="{ 'adf-icon-active': isActive()|| menuTrigger.menuOpen }"
matBadge="filter"
matBadgeColor="warn"
[matBadgeHidden]="!isActive"></adf-icon>
[matBadgeHidden]="!isActive()"></adf-icon>
</button>
<mat-menu #filter="matMenu" class="adf-filter-menu">

View File

@ -95,6 +95,7 @@ describe('SearchHeaderComponent', () => {
menuButton.click();
fixture.detectChanges();
await fixture.whenStable();
component.widgetContainer.componentRef.instance.value = 'searchText';
const applyButton = fixture.debugElement.query(By.css('#apply-filter-button'));
applyButton.triggerEventHandler('click', {});
fixture.detectChanges();

View File

@ -15,7 +15,19 @@
* limitations under the License.
*/
import { Component, Input, Output, OnInit, OnChanges, EventEmitter, SimpleChanges, ViewEncapsulation, ViewChild, Inject, OnDestroy } from '@angular/core';
import {
Component,
Input,
Output,
OnInit,
OnChanges,
EventEmitter,
SimpleChanges,
ViewEncapsulation,
ViewChild,
Inject,
OnDestroy
} from '@angular/core';
import { DataColumn, TranslationService } from '@alfresco/adf-core';
import { SearchWidgetContainerComponent } from '../search-widget-container/search-widget-container.component';
import { SearchHeaderQueryBuilderService } from '../../search-header-query-builder.service';
@ -60,8 +72,6 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild(SearchWidgetContainerComponent)
widgetContainer: SearchWidgetContainerComponent;
public isActive: boolean;
category: SearchCategory;
isFilterServiceActive: boolean;
@ -81,19 +91,13 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
.pipe(takeUntil(this.onDestroy$))
.subscribe((newNodePaging: NodePaging) => {
this.update.emit(newNodePaging);
});
});
}
ngOnChanges(changes: SimpleChanges) {
if (changes['currentFolderNodeId'] && changes['currentFolderNodeId'].currentValue) {
const currentIdValue = changes['currentFolderNodeId'].currentValue;
const previousIdValue = changes['currentFolderNodeId'].previousValue;
this.searchHeaderQueryBuilder.setCurrentRootFolderId(
currentIdValue,
previousIdValue
);
this.isActive = false;
if (changes['currentFolderNodeId'] && changes['currentFolderNodeId'].currentValue !== changes['currentFolderNodeId'].previousValue) {
this.searchHeaderQueryBuilder.setCurrentRootFolderId(changes['currentFolderNodeId'].currentValue);
this.clearHeader();
}
if (changes['maxItems'] || changes['skipCount']) {
@ -125,7 +129,12 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
}
onApplyButtonClick() {
this.isActive = true;
// TODO Move this piece of code in the search text widget
if (this.widgetContainer.selector === 'text' && this.widgetContainer.componentRef.instance.value === '') {
this.clearHeader();
return;
}
this.widgetContainer.applyInnerWidget();
this.searchHeaderQueryBuilder.setActiveFilter(this.category.columnKey);
this.searchHeaderQueryBuilder.execute();
@ -133,13 +142,14 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
onClearButtonClick(event: Event) {
event.stopPropagation();
this.widgetContainer.resetInnerWidget();
this.isActive = false;
this.searchHeaderQueryBuilder.removeActiveFilter(this.category.columnKey);
if (this.searchHeaderQueryBuilder.isNoFilterActive()) {
this.clearHeader();
}
clearHeader() {
if (this.widgetContainer) {
this.widgetContainer.resetInnerWidget();
this.searchHeaderQueryBuilder.removeActiveFilter(this.category.columnKey);
this.clear.emit();
} else {
this.searchHeaderQueryBuilder.execute();
}
}
@ -147,6 +157,10 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
if (!columnTitle) {
columnTitle = 'SEARCH.SEARCH_HEADER.TYPE';
}
return this.translationService.instant('SEARCH.SEARCH_HEADER.FILTER_BY', {category: this.translationService.instant(columnTitle)});
return this.translationService.instant('SEARCH.SEARCH_HEADER.FILTER_BY', { category: this.translationService.instant(columnTitle) });
}
isActive(): boolean {
return this.widgetContainer && this.widgetContainer.componentRef && this.widgetContainer.componentRef.instance.isActive;
}
}

View File

@ -44,6 +44,8 @@ export class SearchNumberRangeComponent implements SearchWidget, OnInit {
field: string;
format = '[{FROM} TO {TO}]';
isActive = false;
validators: Validators;
ngOnInit(): void {
@ -74,6 +76,8 @@ export class SearchNumberRangeComponent implements SearchWidget, OnInit {
apply(model: { from: string, to: string }, isValid: boolean) {
if (isValid && this.id && this.context && this.field) {
this.isActive = true;
const map = new Map<string, string>();
map.set('FROM', model.from);
map.set('TO', model.to);
@ -97,6 +101,8 @@ export class SearchNumberRangeComponent implements SearchWidget, OnInit {
}
reset() {
this.isActive = false;
this.form.reset({
from: '',
to: ''

View File

@ -46,6 +46,7 @@ export class SearchRadioComponent implements SearchWidget, OnInit {
context: SearchQueryBuilderService;
options: SearchFilterList<SearchRadioOption>;
pageSize = 5;
isActive = false;
constructor() {
this.options = new SearchFilterList<SearchRadioOption>();
@ -71,6 +72,8 @@ export class SearchRadioComponent implements SearchWidget, OnInit {
private getSelectedValue(): string {
const options: any[] = this.settings['options'] || [];
if (options && options.length > 0) {
this.isActive = true;
let selected = options.find((opt) => opt.default);
if (!selected) {
selected = options[0];
@ -91,6 +94,8 @@ export class SearchRadioComponent implements SearchWidget, OnInit {
}
reset() {
this.isActive = false;
const initialValue = this.getSelectedValue();
if (initialValue !== null) {
this.setValue(initialValue);

View File

@ -36,6 +36,7 @@ export class SearchTextComponent implements SearchWidget, OnInit {
id: string;
settings: SearchWidgetSettings;
context: SearchQueryBuilderService;
isActive = false;
ngOnInit() {
if (this.context && this.settings && this.settings.pattern) {
@ -49,6 +50,8 @@ export class SearchTextComponent implements SearchWidget, OnInit {
}
reset() {
this.isActive = false;
this.value = '';
this.updateQuery(null);
}
@ -59,10 +62,21 @@ export class SearchTextComponent implements SearchWidget, OnInit {
}
private updateQuery(value: string) {
this.isActive = !!value;
if (this.context && this.settings && this.settings.field) {
this.context.queryFragments[this.id] = value ? `${this.settings.field}:'${value}'` : '';
this.context.queryFragments[this.id] = value ? `${this.settings.field}:'${this.getSearchPrefix()}${value}${this.getSearchSuffix()}'` : '';
this.context.update();
}
}
private getSearchPrefix(): string {
return this.settings.searchPrefix ? this.settings.searchPrefix : '';
}
private getSearchSuffix(): string {
return this.settings.searchSuffix ? this.settings.searchSuffix : '';
}
}

View File

@ -41,7 +41,7 @@ export class SearchWidgetContainerComponent implements OnInit, OnDestroy {
@Input()
config: any;
private componentRef: ComponentRef<any>;
componentRef: ComponentRef<any>;
constructor(
private searchFilterService: SearchFilterService,

View File

@ -94,8 +94,6 @@ describe('SearchHeaderQueryBuilder', () => {
};
const expectedResult = [
{ query: 'query1' },
{ query: 'query2' },
{ query: 'PARENT:"workspace://SpacesStore/fake-node-id"' }
];
@ -105,7 +103,7 @@ describe('SearchHeaderQueryBuilder', () => {
null
);
searchHeaderService.setCurrentRootFolderId('fake-node-id', undefined);
searchHeaderService.setCurrentRootFolderId('fake-node-id');
expect(searchHeaderService.filterQueries).toEqual(expectedResult, 'Filters are not as expected');
});
@ -113,9 +111,7 @@ describe('SearchHeaderQueryBuilder', () => {
it('should not add again the parent filter if that node is already added', () => {
const expectedResult = [
{ query: 'query1' },
{ query: 'query2' },
{ query: 'PARENT:"workspace://SpacesStore/fake-node-id' }
{ query: 'PARENT:"workspace://SpacesStore/fake-node-id"' }
];
const config: SearchConfiguration = {
@ -132,7 +128,7 @@ describe('SearchHeaderQueryBuilder', () => {
null
);
searchHeaderService.setCurrentRootFolderId('fake-node-id', undefined);
searchHeaderService.setCurrentRootFolderId('fake-node-id');
expect(searchHeaderService.filterQueries).toEqual(
expectedResult,
@ -142,8 +138,6 @@ describe('SearchHeaderQueryBuilder', () => {
it('should replace the new query filter for the old parent node with the new one', () => {
const expectedResult = [
{ query: 'query1' },
{ query: 'query2' },
{ query: 'PARENT:"workspace://SpacesStore/fake-next-node-id"' }
];
@ -153,8 +147,6 @@ describe('SearchHeaderQueryBuilder', () => {
<any> { id: 'cat2', enabled: true }
],
filterQueries: [
{ query: 'query1' },
{ query: 'query2' },
{ query: 'PARENT:"workspace://SpacesStore/fake-node-id' }
]
};
@ -165,9 +157,10 @@ describe('SearchHeaderQueryBuilder', () => {
null
);
searchHeaderService.currentParentFolderId = 'fake-node-id';
searchHeaderService.setCurrentRootFolderId(
'fake-next-node-id',
'fake-node-id'
'fake-next-node-id'
);
expect(searchHeaderService.filterQueries).toEqual(

View File

@ -30,7 +30,7 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
private customSources = ['-trashcan-', '-sharedlinks-', '-sites-', '-mysites-', '-favorites-', '-recent-', '-my-'];
activeFilters: string[] = [];
currentParentFolderID: string;
currentParentFolderId: string;
constructor(appConfig: AppConfigService, alfrescoApiService: AlfrescoApiService, private nodeApiService: NodesApiService) {
super(appConfig, alfrescoApiService);
@ -78,41 +78,31 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
return foundCategory;
}
setCurrentRootFolderId(currentFolderId: string, previousFolderId: string) {
if (this.customSources.includes(currentFolderId)) {
if (currentFolderId !== this.currentParentFolderID) {
setCurrentRootFolderId(currentFolderId: string) {
if (currentFolderId !== this.currentParentFolderId) {
if (this.customSources.includes(currentFolderId)) {
this.nodeApiService.getNode(currentFolderId).subscribe((nodeEntity: MinimalNode) => {
this.updateCurrentParentFilter(nodeEntity.id, previousFolderId);
this.updateCurrentParentFilter(nodeEntity.id);
});
} else {
this.currentParentFolderId = currentFolderId;
this.updateCurrentParentFilter(currentFolderId);
}
} else {
this.updateCurrentParentFilter(currentFolderId, previousFolderId);
}
}
private updateCurrentParentFilter(currentFolderId: string, previousFolderId: string) {
private updateCurrentParentFilter(currentFolderId: string) {
const alreadyAddedFilter = this.filterQueries.find(filterQueries =>
filterQueries.query.includes(currentFolderId)
);
if (!alreadyAddedFilter) {
this.removeOldFolderFiltering(previousFolderId, this.currentParentFolderID);
this.currentParentFolderID = currentFolderId;
this.filterQueries.push({
query: `PARENT:"workspace://SpacesStore/${currentFolderId}"`
});
if (alreadyAddedFilter !== undefined) {
this.filterQueries = [];
}
this.filterQueries = [{
query: `PARENT:"workspace://SpacesStore/${currentFolderId}"`
}];
}
private removeOldFolderFiltering(previousFolderId: string, actualSetFolderId: string) {
if (previousFolderId || actualSetFolderId) {
const folderIdToRetrieve = previousFolderId ? previousFolderId : actualSetFolderId;
const oldFilterIndex = this.filterQueries.findIndex(filterQueries =>
filterQueries.query.includes(folderIdToRetrieve)
);
if (oldFilterIndex) {
this.filterQueries.splice(oldFilterIndex, 1);
}
}
}
}

View File

@ -22,5 +22,6 @@ export interface SearchWidget {
id: string;
settings?: SearchWidgetSettings;
context?: SearchQueryBuilderService;
isActive?: boolean;
reset();
}