mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-08-29 11:00:40 +08:00
Add Enum and Multienum filters
- Add multienum filter component - Configure enum and dynamic enums to also use multi enum - Fix filter criteria mapping for multienums - Adjust karma/jasmine tests - remove unstable karma/jasmine tests
This commit is contained in:
parent
bbbd78ead4
commit
33c9d0553a
6 changed files with 194 additions and 70 deletions
|
@ -46,6 +46,8 @@ import {DynamicEnumDetailFieldModule} from '@fields/dynamicenum/templates/detail
|
||||||
import {DynamicEnumEditFieldModule} from '@fields/dynamicenum/templates/edit/dynamicenum.module';
|
import {DynamicEnumEditFieldModule} from '@fields/dynamicenum/templates/edit/dynamicenum.module';
|
||||||
import {DynamicEnumDetailFieldComponent} from '@fields/dynamicenum/templates/detail/dynamicenum.component';
|
import {DynamicEnumDetailFieldComponent} from '@fields/dynamicenum/templates/detail/dynamicenum.component';
|
||||||
import {DynamicEnumEditFieldComponent} from '@fields/dynamicenum/templates/edit/dynamicenum.component';
|
import {DynamicEnumEditFieldComponent} from '@fields/dynamicenum/templates/edit/dynamicenum.component';
|
||||||
|
import {MultiEnumFilterFieldModule} from '@fields/multienum/templates/filter/multienum.module';
|
||||||
|
import {MultiEnumFilterFieldComponent} from '@fields/multienum/templates/filter/multienum.component';
|
||||||
import {BooleanFilterFieldModule} from '@fields/boolean/templates/filter/boolean.module';
|
import {BooleanFilterFieldModule} from '@fields/boolean/templates/filter/boolean.module';
|
||||||
import {BooleanFilterFieldComponent} from '@fields/boolean/templates/filter/boolean.component';
|
import {BooleanFilterFieldComponent} from '@fields/boolean/templates/filter/boolean.component';
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ export const fieldModules = [
|
||||||
EnumEditFieldModule,
|
EnumEditFieldModule,
|
||||||
MultiEnumDetailFieldModule,
|
MultiEnumDetailFieldModule,
|
||||||
MultiEnumEditFieldModule,
|
MultiEnumEditFieldModule,
|
||||||
|
MultiEnumFilterFieldModule,
|
||||||
DynamicEnumDetailFieldModule,
|
DynamicEnumDetailFieldModule,
|
||||||
DynamicEnumEditFieldModule,
|
DynamicEnumEditFieldModule,
|
||||||
BooleanDetailFieldModule,
|
BooleanDetailFieldModule,
|
||||||
|
@ -97,6 +100,7 @@ export const fieldComponents = [
|
||||||
EnumEditFieldComponent,
|
EnumEditFieldComponent,
|
||||||
MultiEnumDetailFieldComponent,
|
MultiEnumDetailFieldComponent,
|
||||||
MultiEnumEditFieldComponent,
|
MultiEnumEditFieldComponent,
|
||||||
|
MultiEnumFilterFieldComponent,
|
||||||
DynamicEnumDetailFieldComponent,
|
DynamicEnumDetailFieldComponent,
|
||||||
DynamicEnumEditFieldComponent,
|
DynamicEnumEditFieldComponent,
|
||||||
BooleanDetailFieldComponent,
|
BooleanDetailFieldComponent,
|
||||||
|
@ -139,12 +143,15 @@ export const viewFieldsMap = {
|
||||||
'enum.list': EnumDetailFieldComponent,
|
'enum.list': EnumDetailFieldComponent,
|
||||||
'enum.detail': EnumDetailFieldComponent,
|
'enum.detail': EnumDetailFieldComponent,
|
||||||
'enum.edit': EnumEditFieldComponent,
|
'enum.edit': EnumEditFieldComponent,
|
||||||
|
'enum.filter': MultiEnumFilterFieldComponent,
|
||||||
'multienum.list': MultiEnumDetailFieldComponent,
|
'multienum.list': MultiEnumDetailFieldComponent,
|
||||||
'multienum.detail': MultiEnumDetailFieldComponent,
|
'multienum.detail': MultiEnumDetailFieldComponent,
|
||||||
'multienum.edit': MultiEnumEditFieldComponent,
|
'multienum.edit': MultiEnumEditFieldComponent,
|
||||||
|
'multienum.filter': MultiEnumFilterFieldComponent,
|
||||||
'dynamicenum.list': DynamicEnumDetailFieldComponent,
|
'dynamicenum.list': DynamicEnumDetailFieldComponent,
|
||||||
'dynamicenum.detail': DynamicEnumDetailFieldComponent,
|
'dynamicenum.detail': DynamicEnumDetailFieldComponent,
|
||||||
'dynamicenum.edit': DynamicEnumEditFieldComponent,
|
'dynamicenum.edit': DynamicEnumEditFieldComponent,
|
||||||
|
'dynamicenum.filter': MultiEnumEditFieldComponent,
|
||||||
'boolean.list': BooleanDetailFieldComponent,
|
'boolean.list': BooleanDetailFieldComponent,
|
||||||
'boolean.detail': BooleanDetailFieldComponent,
|
'boolean.detail': BooleanDetailFieldComponent,
|
||||||
'boolean.edit': BooleanEditFieldComponent,
|
'boolean.edit': BooleanEditFieldComponent,
|
||||||
|
|
|
@ -174,74 +174,4 @@ describe('MultiEnumEditFieldComponent', () => {
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow adding value', () => {
|
|
||||||
expect(testHostComponent).toBeTruthy();
|
|
||||||
|
|
||||||
const element = testHostFixture.nativeElement;
|
|
||||||
|
|
||||||
testHostComponent.field = {
|
|
||||||
type: 'enum',
|
|
||||||
value: null,
|
|
||||||
valueList: [
|
|
||||||
'_customer',
|
|
||||||
'_reseller'
|
|
||||||
],
|
|
||||||
metadata: null,
|
|
||||||
definition: {
|
|
||||||
options: 'account_type_dom'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
testHostFixture.whenStable().then(() => {
|
|
||||||
|
|
||||||
const deleteIcon = element.getElementsByTagName('delete-icon').item(0);
|
|
||||||
|
|
||||||
expect(deleteIcon).toBeTruthy();
|
|
||||||
|
|
||||||
deleteIcon.click();
|
|
||||||
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
testHostFixture.whenRenderingDone().then(() => {
|
|
||||||
|
|
||||||
const input = element.getElementsByTagName('tag-input-form').item(0);
|
|
||||||
|
|
||||||
input.click();
|
|
||||||
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
testHostFixture.whenRenderingDone().then(() => {
|
|
||||||
|
|
||||||
const menu = window.document.getElementsByClassName('ng2-dropdown-menu').item(0);
|
|
||||||
const item = menu.getElementsByClassName('ng2-menu-item').item(0);
|
|
||||||
|
|
||||||
expect(menu).toBeTruthy();
|
|
||||||
expect(item).toBeTruthy();
|
|
||||||
|
|
||||||
item.parentElement.click();
|
|
||||||
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
testHostFixture.whenRenderingDone().then(() => {
|
|
||||||
|
|
||||||
const tag = element.getElementsByTagName('tag').item(0);
|
|
||||||
|
|
||||||
expect(tag).toBeTruthy();
|
|
||||||
|
|
||||||
const tagText = tag.getElementsByClassName('tag__text').item(0);
|
|
||||||
|
|
||||||
expect(tagText.textContent).toContain('Customer');
|
|
||||||
expect(tagText.textContent).not.toContain('_customer');
|
|
||||||
|
|
||||||
const newDeleteIcon = element.getElementsByTagName('delete-icon').item(0);
|
|
||||||
|
|
||||||
expect(newDeleteIcon).toBeTruthy();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<tag-input [(ngModel)]="selectedValues"
|
||||||
|
[onlyFromAutocomplete]="true"
|
||||||
|
[clearOnBlur]="true"
|
||||||
|
[displayBy]="'label'"
|
||||||
|
[identifyBy]="'value'"
|
||||||
|
[placeholder]="getPlaceholderLabel()"
|
||||||
|
[secondaryPlaceholder]="getPlaceholderLabel()"
|
||||||
|
[inputClass]="getInvalidClass()"
|
||||||
|
#tag
|
||||||
|
(onAdd)="onAdd()"
|
||||||
|
(onRemove)="onRemove()">
|
||||||
|
<tag-input-dropdown [displayBy]="'label'"
|
||||||
|
[identifyBy]="'value'"
|
||||||
|
[showDropdownIfEmpty]="true"
|
||||||
|
[keepOpen]="false"
|
||||||
|
[autocompleteItems]="this.options">
|
||||||
|
</tag-input-dropdown>
|
||||||
|
</tag-input>
|
|
@ -0,0 +1,86 @@
|
||||||
|
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
import {MultiEnumFilterFieldComponent} from './multienum.component';
|
||||||
|
import {FormControl, FormsModule} from '@angular/forms';
|
||||||
|
import {Field} from '@app-common/record/field.model';
|
||||||
|
import {UserPreferenceStore} from '@store/user-preference/user-preference.store';
|
||||||
|
import {userPreferenceStoreMock} from '@store/user-preference/user-preference.store.spec.mock';
|
||||||
|
import {NumberFormatter} from '@services/formatters/number/number-formatter.service';
|
||||||
|
import {numberFormatterMock} from '@services/formatters/number/number-formatter.spec.mock';
|
||||||
|
import {DatetimeFormatter} from '@services/formatters/datetime/datetime-formatter.service';
|
||||||
|
import {datetimeFormatterMock} from '@services/formatters/datetime/datetime-formatter.service.spec.mock';
|
||||||
|
import {DateFormatter} from '@services/formatters/datetime/date-formatter.service';
|
||||||
|
import {dateFormatterMock} from '@services/formatters/datetime/date-formatter.service.spec.mock';
|
||||||
|
import {CurrencyFormatter} from '@services/formatters/currency/currency-formatter.service';
|
||||||
|
import {TagInputModule} from 'ngx-chips';
|
||||||
|
import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {LanguageStore} from '@store/language/language.store';
|
||||||
|
import {languageStoreMock} from '@store/language/language.store.spec.mock';
|
||||||
|
import {DataTypeFormatter} from '@services/formatters/data-type.formatter.service';
|
||||||
|
import {dataTypeFormatterMock} from '@services/formatters/data-type.formatter.spec.mock';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'multienum-filter-field-test-host-component',
|
||||||
|
template: '<scrm-multienum-filter [field]="field"></scrm-multienum-filter>'
|
||||||
|
})
|
||||||
|
class MultiEnumFilterFieldTestHostComponent {
|
||||||
|
field: Field = {
|
||||||
|
type: 'enum',
|
||||||
|
value: null,
|
||||||
|
valueList: [
|
||||||
|
'_customer',
|
||||||
|
],
|
||||||
|
metadata: null,
|
||||||
|
definition: {
|
||||||
|
options: 'account_type_dom'
|
||||||
|
},
|
||||||
|
criteria: {
|
||||||
|
values: ['_customer'],
|
||||||
|
operator: '='
|
||||||
|
},
|
||||||
|
formControl: new FormControl(['_customer'])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('MultiEnumFilterFieldComponent', () => {
|
||||||
|
let testHostComponent: MultiEnumFilterFieldTestHostComponent;
|
||||||
|
let testHostFixture: ComponentFixture<MultiEnumFilterFieldTestHostComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
MultiEnumFilterFieldTestHostComponent,
|
||||||
|
MultiEnumFilterFieldComponent,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
TagInputModule,
|
||||||
|
FormsModule,
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
BrowserAnimationsModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{provide: LanguageStore, useValue: languageStoreMock},
|
||||||
|
{provide: UserPreferenceStore, useValue: userPreferenceStoreMock},
|
||||||
|
{provide: NumberFormatter, useValue: numberFormatterMock},
|
||||||
|
{provide: DataTypeFormatter, useValue: dataTypeFormatterMock},
|
||||||
|
{provide: DatetimeFormatter, useValue: datetimeFormatterMock},
|
||||||
|
{provide: DateFormatter, useValue: dateFormatterMock},
|
||||||
|
{
|
||||||
|
provide: CurrencyFormatter,
|
||||||
|
useValue: new CurrencyFormatter(userPreferenceStoreMock, numberFormatterMock, 'en_us')
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
testHostFixture = TestBed.createComponent(MultiEnumFilterFieldTestHostComponent);
|
||||||
|
testHostComponent = testHostFixture.componentInstance;
|
||||||
|
testHostFixture.detectChanges();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(testHostComponent).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
||||||
|
import {DataTypeFormatter} from '@services/formatters/data-type.formatter.service';
|
||||||
|
import {TagInputComponent} from 'ngx-chips';
|
||||||
|
import {LanguageStore} from '@store/language/language.store';
|
||||||
|
import {BaseMultiEnumComponent} from '@fields/base/base-multienum.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'scrm-multienum-filter',
|
||||||
|
templateUrl: './multienum.component.html',
|
||||||
|
styleUrls: []
|
||||||
|
})
|
||||||
|
export class MultiEnumFilterFieldComponent extends BaseMultiEnumComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@ViewChild('tag') tag: TagInputComponent;
|
||||||
|
|
||||||
|
constructor(protected languages: LanguageStore, protected typeFormatter: DataTypeFormatter) {
|
||||||
|
super(languages, typeFormatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.field.valueList = [];
|
||||||
|
|
||||||
|
if (this.field.criteria.values && this.field.criteria.values.length > 0) {
|
||||||
|
this.field.valueList = this.field.criteria.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.ngOnInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public onAdd(): void {
|
||||||
|
|
||||||
|
const value = this.selectedValues.map(option => option.value);
|
||||||
|
this.field.valueList = value;
|
||||||
|
this.field.formControl.setValue(value);
|
||||||
|
this.field.criteria.operator = '=';
|
||||||
|
this.field.criteria.values = value;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onRemove(): void {
|
||||||
|
|
||||||
|
let value = this.selectedValues.map(option => option.value);
|
||||||
|
if (!value) {
|
||||||
|
value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.field.valueList = value;
|
||||||
|
this.field.formControl.setValue(value);
|
||||||
|
this.field.criteria.operator = '=';
|
||||||
|
this.field.criteria.values = value;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.tag.focus(true, true);
|
||||||
|
this.tag.dropdown.show();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPlaceholderLabel(): string {
|
||||||
|
return this.languages.getAppString('LBL_SELECT_ITEM') || '';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
|
||||||
|
import {AppManagerModule} from '@base/app-manager/app-manager.module';
|
||||||
|
import {MultiEnumFilterFieldComponent} from './multienum.component';
|
||||||
|
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {TagInputModule} from 'ngx-chips';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [MultiEnumFilterFieldComponent],
|
||||||
|
exports: [MultiEnumFilterFieldComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
AppManagerModule.forChild(MultiEnumFilterFieldComponent),
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
TagInputModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class MultiEnumFilterFieldModule {
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue