mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-08-29 07:50:08 +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 {DynamicEnumDetailFieldComponent} from '@fields/dynamicenum/templates/detail/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 {BooleanFilterFieldComponent} from '@fields/boolean/templates/filter/boolean.component';
|
||||
|
||||
|
@ -70,6 +72,7 @@ export const fieldModules = [
|
|||
EnumEditFieldModule,
|
||||
MultiEnumDetailFieldModule,
|
||||
MultiEnumEditFieldModule,
|
||||
MultiEnumFilterFieldModule,
|
||||
DynamicEnumDetailFieldModule,
|
||||
DynamicEnumEditFieldModule,
|
||||
BooleanDetailFieldModule,
|
||||
|
@ -97,6 +100,7 @@ export const fieldComponents = [
|
|||
EnumEditFieldComponent,
|
||||
MultiEnumDetailFieldComponent,
|
||||
MultiEnumEditFieldComponent,
|
||||
MultiEnumFilterFieldComponent,
|
||||
DynamicEnumDetailFieldComponent,
|
||||
DynamicEnumEditFieldComponent,
|
||||
BooleanDetailFieldComponent,
|
||||
|
@ -139,12 +143,15 @@ export const viewFieldsMap = {
|
|||
'enum.list': EnumDetailFieldComponent,
|
||||
'enum.detail': EnumDetailFieldComponent,
|
||||
'enum.edit': EnumEditFieldComponent,
|
||||
'enum.filter': MultiEnumFilterFieldComponent,
|
||||
'multienum.list': MultiEnumDetailFieldComponent,
|
||||
'multienum.detail': MultiEnumDetailFieldComponent,
|
||||
'multienum.edit': MultiEnumEditFieldComponent,
|
||||
'multienum.filter': MultiEnumFilterFieldComponent,
|
||||
'dynamicenum.list': DynamicEnumDetailFieldComponent,
|
||||
'dynamicenum.detail': DynamicEnumDetailFieldComponent,
|
||||
'dynamicenum.edit': DynamicEnumEditFieldComponent,
|
||||
'dynamicenum.filter': MultiEnumEditFieldComponent,
|
||||
'boolean.list': BooleanDetailFieldComponent,
|
||||
'boolean.detail': BooleanDetailFieldComponent,
|
||||
'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