diff --git a/core/app/core/src/lib/core.ts b/core/app/core/src/lib/core.ts index ab8b035733..64c0caf887 100644 --- a/core/app/core/src/lib/core.ts +++ b/core/app/core/src/lib/core.ts @@ -381,6 +381,8 @@ export * from './fields/icon/templates/detail/icon.component'; export * from './fields/icon/templates/detail/icon.module'; export * from './fields/int/templates/detail/int.component'; export * from './fields/int/templates/detail/int.module'; +export * from './fields/int/templates/edit/int.component'; +export * from './fields/int/templates/edit/int.module'; export * from './fields/line-items/line-items.component'; export * from './fields/line-items/line-items.module'; export * from './fields/multienum/templates/detail/multienum.component'; diff --git a/core/app/core/src/lib/fields/base-fields.manifest.ts b/core/app/core/src/lib/fields/base-fields.manifest.ts index e9de580f11..e1327a8ab7 100644 --- a/core/app/core/src/lib/fields/base-fields.manifest.ts +++ b/core/app/core/src/lib/fields/base-fields.manifest.ts @@ -38,8 +38,8 @@ import {DateTimeEditFieldModule} from './datetime/templates/edit/datetime.module import {DateFilterFieldComponent} from './date/templates/filter/date.component'; import {DateTimeDetailFieldComponent} from './datetime/templates/detail/datetime.component'; import {DateTimeDetailFieldModule} from './datetime/templates/detail/datetime.module'; -import {DateTimeFilterFieldComponent} from "./datetime/templates/filter/datetime.component"; -import {DateTimeFilterFieldModule} from "./datetime/templates/filter/datetime.module"; +import {DateTimeFilterFieldComponent} from './datetime/templates/filter/datetime.component'; +import {DateTimeFilterFieldModule} from './datetime/templates/filter/datetime.module'; import {MultiEnumDetailFieldComponent} from './multienum/templates/detail/multienum.component'; import {EnumEditFieldComponent} from './enum/templates/edit/enum.component'; import {BooleanDetailFieldComponent} from './boolean/templates/detail/boolean.component'; @@ -103,10 +103,12 @@ import {TinymceDetailFieldModule} from './tinymce/templates/detail/tinymce.modul import {TinymceEditFieldModule} from './tinymce/templates/edit/tinymce.module'; import {TinymceDetailFieldComponent} from './tinymce/templates/detail/tinymce.component'; import {TinymceEditFieldComponent} from './tinymce/templates/edit/tinymce.component'; -import {IconListFieldModule} from "./icon/templates/detail/icon.module"; -import {IconDetailFieldComponent} from "./icon/templates/detail/icon.component"; +import {IconListFieldModule} from './icon/templates/detail/icon.module'; +import {IconDetailFieldComponent} from './icon/templates/detail/icon.component'; import {TextListFieldModule} from './text/templates/list/text.module'; import {TextListFieldComponent} from './text/templates/list/text.component'; +import {IntEditFieldModule} from './int/templates/edit/int.module'; +import {IntEditFieldComponent} from './int/templates/edit/int.component'; export const baseFieldModules = [ VarcharDetailFieldModule, @@ -115,6 +117,7 @@ export const baseFieldModules = [ PasswordDetailFieldModule, PasswordEditFieldModule, IntDetailFieldModule, + IntEditFieldModule, IconListFieldModule, FileDetailFieldModule, FloatDetailFieldModule, @@ -158,6 +161,7 @@ export const baseFieldComponents = [ PasswordDetailFieldComponent, PasswordEditFieldComponent, IntDetailFieldComponent, + IntEditFieldComponent, FileDetailFieldComponent, FloatDetailFieldComponent, PhoneDetailFieldComponent, @@ -207,6 +211,7 @@ export const baseViewFieldsMap: FieldComponentMap = { 'char.detail': VarcharDetailFieldComponent, 'int.list': IntDetailFieldComponent, 'int.detail': IntDetailFieldComponent, + 'int.edit': IntEditFieldComponent, 'file.detail': FileDetailFieldComponent, 'float.list': FloatDetailFieldComponent, 'float.detail': FloatDetailFieldComponent, diff --git a/core/app/core/src/lib/fields/int/templates/edit/int.component.html b/core/app/core/src/lib/fields/int/templates/edit/int.component.html new file mode 100644 index 0000000000..591d09cc21 --- /dev/null +++ b/core/app/core/src/lib/fields/int/templates/edit/int.component.html @@ -0,0 +1,37 @@ + + + diff --git a/core/app/core/src/lib/fields/int/templates/edit/int.component.spec.ts b/core/app/core/src/lib/fields/int/templates/edit/int.component.spec.ts new file mode 100644 index 0000000000..488d438d81 --- /dev/null +++ b/core/app/core/src/lib/fields/int/templates/edit/int.component.spec.ts @@ -0,0 +1,116 @@ +/** + * SuiteCRM is a customer relationship management program developed by SalesAgility Ltd. + * Copyright (C) 2023 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {IntEditFieldComponent} from './int.component'; +import {Component} from '@angular/core'; +import {BehaviorSubject, of} from 'rxjs'; +import {Field} from 'common'; +import {UserPreferenceMockStore} from '../../../../store/user-preference/user-preference.store.spec.mock'; +import {SystemConfigStore} from '../../../../store/system-config/system-config.store'; +import {UserPreferenceStore} from '../../../../store/user-preference/user-preference.store'; +import {CurrencyFormatter} from '../../../../services/formatters/currency/currency-formatter.service'; +import {FormControlUtils} from '../../../../services/record/field/form-control.utils'; +import {FormatNumberPipe} from '../../../../pipes/format-number/format-number.pipe'; +import {NumberFormatter} from '../../../../services/formatters/number/number-formatter.service'; + +@Component({ + selector: 'int-edit-field-test-host-component', + template: '' +}) +class IntEditFieldTestHostComponent { + field: Field = { + type: 'int', + value: '10' + }; +} + +describe('IntEditFieldComponent', () => { + let testHostComponent: IntEditFieldTestHostComponent; + let testHostFixture: ComponentFixture; + + /* eslint-disable camelcase,@typescript-eslint/camelcase */ + const preferences = new BehaviorSubject({ + num_grp_sep: ',', + dec_sep: '.', + }); + const mockStore = new UserPreferenceMockStore(preferences); + const mockNumberFormatter = new NumberFormatter(mockStore, new FormControlUtils(), 'en-US'); + /* eslint-enable camelcase,@typescript-eslint/camelcase */ + + beforeEach(waitForAsync(() => { + /* eslint-disable camelcase,@typescript-eslint/camelcase */ + TestBed.configureTestingModule({ + declarations: [ + IntEditFieldTestHostComponent, + IntEditFieldComponent, + FormatNumberPipe + ], + imports: [], + providers: [ + {provide: UserPreferenceStore, useValue: mockStore}, + { + provide: CurrencyFormatter, + useValue: new CurrencyFormatter(mockStore, mockNumberFormatter, 'en_us') + }, + { + provide: SystemConfigStore, useValue: { + configs$: of({ + default_number_grouping_seperator: { + id: '/docroot/api/system-configs/default_number_grouping_seperator', + _id: 'default_number_grouping_seperator', + value: ';', + items: [] + }, + default_decimal_seperator: { + id: '/docroot/api/system-configs/default_decimal_seperator', + _id: 'default_decimal_seperator', + value: ',', + items: [] + } + }) + } + }, + {provide: NumberFormatter, useValue: mockNumberFormatter} + ], + }).compileComponents(); + /* eslint-enable camelcase,@typescript-eslint/camelcase */ + + testHostFixture = TestBed.createComponent(IntEditFieldTestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + })); + + it('should create', () => { + expect(testHostComponent).toBeTruthy(); + }); + + it('should have value', () => { + + expect(testHostComponent).toBeTruthy(); + expect(testHostFixture.nativeElement.textContent).toContain(10); + }); +}); diff --git a/core/app/core/src/lib/fields/int/templates/edit/int.component.ts b/core/app/core/src/lib/fields/int/templates/edit/int.component.ts new file mode 100644 index 0000000000..fa52d849e2 --- /dev/null +++ b/core/app/core/src/lib/fields/int/templates/edit/int.component.ts @@ -0,0 +1,87 @@ +/** + * SuiteCRM is a customer relationship management program developed by SalesAgility Ltd. + * Copyright (C) 2023 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +import { isEqual } from 'lodash-es'; +import {Component} from '@angular/core'; +import {FormControl} from '@angular/forms'; +import {BaseNumberComponent} from '../../../base/base-number.component'; +import {SystemConfigStore} from '../../../../store/system-config/system-config.store'; +import {DataTypeFormatter} from '../../../../services/formatters/data-type.formatter.service'; +import {UserPreferenceStore} from '../../../../store/user-preference/user-preference.store'; +import {FieldLogicManager} from '../../../field-logic/field-logic.manager'; +import {FieldLogicDisplayManager} from '../../../field-logic-display/field-logic-display.manager'; + +@Component({ + selector: 'scrm-int-edit', + templateUrl: './int.component.html', + styleUrls: [] +}) +export class IntEditFieldComponent extends BaseNumberComponent { + public intValue = 0; + public intValueFormControl: FormControl = new FormControl(this.intValue); + + constructor( + protected userPreferences: UserPreferenceStore, + protected systemConfig: SystemConfigStore, + protected typeFormatter: DataTypeFormatter, + protected logic: FieldLogicManager, + protected logicDisplay: FieldLogicDisplayManager, + ) { + super(userPreferences, systemConfig, typeFormatter, logic, logicDisplay); + } + + ngOnInit(): void { + this.subscribeIntValueChanges(); + + super.ngOnInit(); + this.subscribeValueChanges(); + } + + ngOnDestroy(): void { + this.unsubscribeAll(); + } + + private subscribeIntValueChanges(): void { + this.subs.push( + this.intValueFormControl.valueChanges.subscribe(valueChanges => { + this.intValue = valueChanges; + if (!this.field.formControl || isEqual(this.field.formControl.value, valueChanges)) { + return; + } + this.field.formControl.setValue(valueChanges.toString()); + }) + ); + this.subs.push( + this.field.valueChanges$.subscribe((fieldValue) => { + const intValue = parseInt(fieldValue.value,10) || 0; + if (isEqual(this.intValueFormControl.value, intValue)) { + return; + } + this.intValueFormControl.setValue(intValue); + }) + ); + } +} diff --git a/core/app/core/src/lib/fields/int/templates/edit/int.module.ts b/core/app/core/src/lib/fields/int/templates/edit/int.module.ts new file mode 100644 index 0000000000..d02410d4c6 --- /dev/null +++ b/core/app/core/src/lib/fields/int/templates/edit/int.module.ts @@ -0,0 +1,47 @@ +/** + * SuiteCRM is a customer relationship management program developed by SalesAgility Ltd. + * Copyright (C) 2023 SalesAgility Ltd. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {IntEditFieldComponent} from './int.component'; +import {FormatNumberModule} from '../../../../pipes/format-number/format-number.module'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {LabelModule} from '../../../../components/label/label.module'; + +@NgModule({ + declarations: [IntEditFieldComponent], + exports: [IntEditFieldComponent], + imports: [ + CommonModule, + FormatNumberModule, + FormsModule, + ReactiveFormsModule, + LabelModule + ] +}) +export class IntEditFieldModule { +}