diff --git a/frontend/cypress/e2e/check-in.cy.ts b/frontend/cypress/e2e/check-in.cy.ts index fc1f6a5eee..a20c3011e6 100644 --- a/frontend/cypress/e2e/check-in.cy.ts +++ b/frontend/cypress/e2e/check-in.cy.ts @@ -44,6 +44,28 @@ describe('okr check-in', () => { cy.contains('- A new action on the action-plan'); }); + it('should show an error message when new check-in value is not numeric', () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle('This key-result will have errors') + .withMetricValues(Unit.NUMBER, '21', '51') + .submit(); + + const detailPage = keyResultDetailPage + .visit('Very important keyresult') + .createCheckIn() + .fillMetricCheckInValue('asdf'); + cy.contains('Neuer Wert muss eine Zahl sein.'); + + detailPage.fillMetricCheckInValue('21. 2'); + cy.contains('Neuer Wert muss eine Zahl sein.'); + + detailPage.fillMetricCheckInValue('123'); + cy.contains('Neuer Wert muss eine Zahl sein.') + .should('not.exist'); + }); + + it('should create check-in metric and assert correct owner', () => { overviewPage .addKeyResult() diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index beb9894af1..8a3873b4f3 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -67,7 +67,6 @@ import { CheckInFormComponent } from './components/checkin/check-in-form/check-i import { ApplicationTopBarComponent } from './components/application-top-bar/application-top-bar.component'; import { A11yModule } from '@angular/cdk/a11y'; import { CustomizationService } from './services/customization.service'; -import { MetricCheckInDirective } from './components/checkin/check-in-form-metric/metric-check-in-directive'; function initOauthFactory(configService: ConfigService, oauthService: OAuthService) { return async() => { @@ -122,8 +121,7 @@ export const MY_FORMATS = { CheckInHistoryDialogComponent, CheckInFormMetricComponent, CheckInFormOrdinalComponent, - CheckInFormComponent, - MetricCheckInDirective + CheckInFormComponent ], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], diff --git a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.html b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.html index 7ace176202..53f222dc16 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.html +++ b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.html @@ -8,19 +8,16 @@ {{ generateUnitLabel() }} - - {{ getErrorMessage("MUST_BE_NUMBER", "Neuer Wert") }} - + diff --git a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts index b59ae70be5..a07fbb3373 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts @@ -10,6 +10,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; import { Unit } from '../../../shared/types/enums/unit'; import { TranslateTestingModule } from 'ngx-translate-testing'; +// @ts-ignore import * as de from '../../../../assets/i18n/de.json'; describe('CheckInFormComponent', () => { @@ -36,7 +37,7 @@ describe('CheckInFormComponent', () => { component.keyResult = keyResultMetric; component.checkIn = checkInMetric; component.dialogForm = new FormGroup({ - value: new FormControl('', [Validators.required]), + metricValue: new FormControl('', [Validators.required]), confidence: new FormControl(5, [Validators.required, Validators.min(1), Validators.max(10)]) @@ -50,37 +51,87 @@ describe('CheckInFormComponent', () => { }); it('should format percent correctly', waitForAsync(async() => { - component.keyResult = { ...keyResultMetric, - unit: Unit.PERCENT }; + component.keyResult = { + ...keyResultMetric, + unit: Unit.PERCENT + }; expect(component.generateUnitLabel()) .toEqual('%'); })); it('should format chf correctly', waitForAsync(async() => { - component.keyResult = { ...keyResultMetric, - unit: Unit.CHF }; + component.keyResult = { + ...keyResultMetric, + unit: Unit.CHF + }; expect(component.generateUnitLabel()) .toEqual('CHF'); })); it('should format eur correctly', waitForAsync(async() => { - component.keyResult = { ...keyResultMetric, - unit: Unit.EUR }; + component.keyResult = { + ...keyResultMetric, + unit: Unit.EUR + }; expect(component.generateUnitLabel()) .toEqual('EUR'); })); it('should format fte correctly', waitForAsync(async() => { - component.keyResult = { ...keyResultMetric, - unit: Unit.FTE }; + component.keyResult = { + ...keyResultMetric, + unit: Unit.FTE + }; expect(component.generateUnitLabel()) .toEqual('FTE'); })); it('should format number correctly', waitForAsync(async() => { - component.keyResult = { ...keyResultMetric, - unit: Unit.NUMBER }; + component.keyResult = { + ...keyResultMetric, + unit: Unit.NUMBER + }; expect(component.generateUnitLabel()) .toEqual(''); })); + + + it.each([ + [0, + true], + [150, + true], + [-23, + true], + [12.3, + true], + [-100.3, + true], + [' 123 ', + true], + [' -123.4 ', + true], + ['12 .3', + false], + ['1 2', + false], + ['', + false], + ['asdf', + false], + ['a1', + false], + ['1a', + false], + [null, + false] + ])('should correctly validate value input', (value, validity) => { + component.dialogForm = new FormGroup({ + metricValue: new FormControl(undefined, [Validators.required, + Validators.pattern('^\\s*-?\\d+\\.?\\d*\\s*$')]) + }); + component.dialogForm.setValue({ metricValue: value }); + expect(component.dialogForm.valid) + .toEqual(validity); + }); }); diff --git a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts index cdffb73982..e1c1c99282 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts @@ -1,8 +1,8 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; -import { FormGroup, Validators } from '@angular/forms'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { FormGroup } from '@angular/forms'; import { KeyResultMetric } from '../../../shared/types/model/key-result-metric'; import { CheckInMin } from '../../../shared/types/model/check-in-min'; -import { formInputCheck, hasFormFieldErrors } from '../../../shared/common'; +import { formInputCheck } from '../../../shared/common'; import { TranslateService } from '@ngx-translate/core'; import { CheckInMetricMin } from '../../../shared/types/model/check-in-metric-min'; @@ -12,7 +12,7 @@ import { CheckInMetricMin } from '../../../shared/types/model/check-in-metric-mi changeDetection: ChangeDetectionStrategy.OnPush, standalone: false }) -export class CheckInFormMetricComponent implements OnInit { +export class CheckInFormMetricComponent { @Input() keyResult!: KeyResultMetric; @@ -24,15 +24,8 @@ export class CheckInFormMetricComponent implements OnInit { protected readonly formInputCheck = formInputCheck; - protected readonly hasFormFieldErrors = hasFormFieldErrors; - constructor(private translate: TranslateService) {} - ngOnInit() { - this.dialogForm.controls['value'].setValidators([Validators.required, - Validators.pattern('^-?\\d+\\.?\\d*$')]); - } - generateUnitLabel(): string { switch (this.keyResult.unit) { case 'PERCENT': @@ -48,10 +41,6 @@ export class CheckInFormMetricComponent implements OnInit { } } - getErrorMessage(error: string, field: string): string { - return field + this.translate.instant('DIALOG_ERRORS.' + error); - } - getCheckInMetric(): CheckInMetricMin { return this.checkIn as CheckInMetricMin; } diff --git a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts deleted file mode 100644 index c4a93de78e..0000000000 --- a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MetricCheckInDirective } from './metric-check-in-directive'; - -describe('MetricCheckInDirective', () => { - it('should create an instance', () => { - const directive = new MetricCheckInDirective(); - expect(directive) - .toBeTruthy(); - }); - - it.each([ - ['HelloWorld200', - 200], - ['200HelloWorld', - 200], - ['200\'000', - 200000], - ['1050&%ç*', - 1050], - ['-1', - -1], - ['-ç13&%', - -13] - ])('should parse value %s correctly to %s', (value: string, expected: number) => { - const mockOnChange = jest.fn(); - const directive = new MetricCheckInDirective(); - directive.registerOnChange(mockOnChange); - - directive.handleInput(value); - - expect(mockOnChange) - .toHaveBeenCalledWith(expected); - }); -}); diff --git a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts deleted file mode 100644 index 838c4fbdf0..0000000000 --- a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Directive, forwardRef, HostListener } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; - -@Directive({ - selector: '[metricCheckIn]', - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MetricCheckInDirective), - multi: true - }], - standalone: false -}) -export class MetricCheckInDirective implements ControlValueAccessor { - private onChange: (value: number | null) => void = () => { - }; - - protected readonly CHAR_REGEX = /[^0-9.]/g; - - writeValue(): void { - // does not need to be implemented because the display value does not need to be modified comment is here to make linter happy - } - - registerOnChange(fn: (value: number | null) => void): void { - this.onChange = fn; - } - - registerOnTouched(): void { - // does not need to be implemented comment is here to make linter happy - } - - @HostListener('input', ['$event.target.value']) - handleInput(param: string): void { - const value: string = param || '0'; - if (value.toString() - .at(0) == '-') { - this.onChange(+('-' + value.toString() - .replace(this.CHAR_REGEX, ''))); - return; - } - this.onChange(Number(value.toString() - .replace(this.CHAR_REGEX, ''))); - } -} diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html index 99eec7cbc4..5fb1861765 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html @@ -2,7 +2,7 @@
diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts index 937d65e1f6..7e23319c14 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts @@ -35,7 +35,7 @@ describe('CheckInFormOrdinalComponent', () => { component = fixture.componentInstance; component.keyResult = keyResultOrdinalMin as unknown as KeyResultOrdinal; component.dialogForm = new FormGroup({ - value: new FormControl('', [Validators.required]), + ordinalZone: new FormControl('', [Validators.required]), confidence: new FormControl(5, [Validators.required, Validators.min(1), Validators.max(10)]) @@ -50,35 +50,35 @@ describe('CheckInFormOrdinalComponent', () => { }); it('should set zone of check-in to fail if value is empty', waitForAsync(async() => { - expect(component.dialogForm.controls['value'].value) + expect(component.dialogForm.controls['ordinalZone'].value) .toBe(''); })); it('should be able to set zone to fail', waitForAsync(async() => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[0].check(); - expect(component.dialogForm.controls['value'].value) + expect(component.dialogForm.controls['ordinalZone'].value) .toBe(Zone.FAIL); })); it('should be able to set zone to commit', waitForAsync(async() => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[1].check(); - expect(component.dialogForm.controls['value'].value) + expect(component.dialogForm.controls['ordinalZone'].value) .toBe(Zone.COMMIT); })); it('should be able to set zone to target', waitForAsync(async() => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[2].check(); - expect(component.dialogForm.controls['value'].value) + expect(component.dialogForm.controls['ordinalZone'].value) .toBe(Zone.TARGET); })); it('should be able to set zone to stretch', waitForAsync(async() => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[3].check(); - expect(component.dialogForm.controls['value'].value) + expect(component.dialogForm.controls['ordinalZone'].value) .toBe(Zone.STRETCH); })); @@ -86,7 +86,7 @@ describe('CheckInFormOrdinalComponent', () => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[3].check(); await radioButtons[1].check(); - expect(component.dialogForm.controls['value'].value) + expect(component.dialogForm.controls['ordinalZone'].value) .toBe(Zone.COMMIT); })); }); diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html index 01f91d9e59..d14179cc8d 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html @@ -68,9 +68,7 @@ id="change-info" formControlName="changeInfo" > - - {{ getErrorMessage("MAX_VALUE", "Kommentar / Veränderung", 4096) }} - +
@@ -97,9 +95,7 @@ formControlName="initiatives" id="initiatives" > - - {{ getErrorMessage("MAX_VALUE", "Massnahmen", 4096) }} - + diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts index 9ca6f9b30f..04683245c4 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts @@ -29,9 +29,12 @@ import { MatSliderModule } from '@angular/material/slider'; import { provideRouter } from '@angular/router'; import { provideHttpClient } from '@angular/common/http'; import { provideHttpClientTesting } from '@angular/common/http/testing'; -import { DialogTemplateCoreComponent } from '../../../shared/custom/dialog-template-core/dialog-template-core.component'; +import { + DialogTemplateCoreComponent +} from '../../../shared/custom/dialog-template-core/dialog-template-core.component'; import { MatDividerModule } from '@angular/material/divider'; import { Action } from '../../../shared/types/model/action'; +import { Zone } from '../../../shared/types/enums/zone'; const dialogMock = { close: jest.fn() @@ -72,14 +75,22 @@ describe('CheckInFormComponent', () => { provideRouter([]), provideHttpClient(), provideHttpClientTesting(), - { provide: MAT_DIALOG_DATA, - useValue: { keyResult: {} } }, - { provide: MatDialogRef, - useValue: dialogMock }, - { provide: CheckInService, - useValue: checkInServiceMock }, - { provide: ActionService, - useValue: actionServiceMock } + { + provide: MAT_DIALOG_DATA, + useValue: { keyResult: {} } + }, + { + provide: MatDialogRef, + useValue: dialogMock + }, + { + provide: CheckInService, + useValue: checkInServiceMock + }, + { + provide: ActionService, + useValue: actionServiceMock + } ], declarations: [CheckInFormComponent, DialogTemplateCoreComponent, @@ -98,7 +109,7 @@ describe('CheckInFormComponent', () => { it('should save check-in correctly if key-result is metric', waitForAsync(async() => { component.checkIn = checkInMetric; component.keyResult = keyResultMetric; - component.dialogForm.controls['value'].setValue(checkInMetric?.value!.toString()); + component.dialogForm.controls['metricValue'].setValue(checkInMetric?.value); component.dialogForm.controls['confidence'].setValue(checkInMetric.confidence); component.dialogForm.controls['changeInfo'].setValue(checkInMetric.changeInfo); component.dialogForm.controls['initiatives'].setValue(checkInMetric.initiatives); @@ -113,9 +124,9 @@ describe('CheckInFormComponent', () => { id: checkInMetric.id, version: checkInMetric.version, confidence: checkInMetric.confidence, - value: checkInMetric.value!.toString(), changeInfo: checkInMetric.changeInfo, initiatives: checkInMetric.initiatives, + value: checkInMetric.value, keyResultId: keyResultMetric.id }); expect(actionServiceMock.updateActions) @@ -125,7 +136,7 @@ describe('CheckInFormComponent', () => { it('should save check-in correctly if key-result is ordinal', waitForAsync(async() => { component.checkIn = checkInOrdinal; component.keyResult = keyResultOrdinal; - component.dialogForm.controls['value'].setValue(checkInOrdinal?.zone!.toString()); + component.dialogForm.controls['ordinalZone'].setValue(checkInOrdinal?.zone as Zone); component.dialogForm.controls['confidence'].setValue(checkInOrdinal.confidence); component.dialogForm.controls['changeInfo'].setValue(checkInOrdinal.changeInfo); component.dialogForm.controls['initiatives'].setValue(checkInOrdinal.initiatives); @@ -156,7 +167,6 @@ describe('CheckInFormComponent', () => { expect(component.dialogForm.value) .toStrictEqual({ confidence: checkInMetric.confidence, - value: checkInMetric.value!.toString(), changeInfo: checkInMetric.changeInfo, initiatives: checkInMetric.initiatives, actionList: undefined @@ -170,7 +180,6 @@ describe('CheckInFormComponent', () => { expect(component.dialogForm.value) .toStrictEqual({ confidence: keyResultOrdinal.lastCheckIn!.confidence, - value: '', changeInfo: '', initiatives: '', actionList: [] @@ -184,7 +193,6 @@ describe('CheckInFormComponent', () => { expect(component.dialogForm.value) .toStrictEqual({ confidence: keyResultActions.lastCheckIn!.confidence, - value: '', changeInfo: '', initiatives: '', actionList: [action1, diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts index ccdb6db3cf..5f69fa4e36 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts @@ -10,10 +10,11 @@ import { Action } from '../../../shared/types/model/action'; import { ActionService } from '../../../services/action.service'; import { formInputCheck, hasFormFieldErrors } from '../../../shared/common'; import { TranslateService } from '@ngx-translate/core'; -import { CheckIn } from '../../../shared/types/model/check-in'; import { CheckInMetricMin } from '../../../shared/types/model/check-in-metric-min'; import { CheckInOrdinalMin } from '../../../shared/types/model/check-in-ordinal-min'; import { BehaviorSubject } from 'rxjs'; +import { Zone } from '../../../shared/types/enums/zone'; +import { numberValidator } from '../../../shared/constant-library'; @Component({ selector: 'app-check-in-form', @@ -34,7 +35,9 @@ export class CheckInFormComponent implements OnInit { isAddingAction = false; dialogForm = new FormGroup({ - value: new FormControl('', [Validators.required]), + metricValue: new FormControl(undefined, [Validators.required, + numberValidator()]), + ordinalZone: new FormControl(Zone.FAIL, [Validators.required]), confidence: new FormControl(5, [Validators.required, Validators.min(0), Validators.max(10)]), @@ -43,6 +46,9 @@ export class CheckInFormComponent implements OnInit { actionList: new FormControl([]) }); + checkInTypes: string[] = ['metricValue', + 'ordinalZone']; + protected readonly formInputCheck = formInputCheck; protected readonly hasFormFieldErrors = hasFormFieldErrors; @@ -57,6 +63,7 @@ export class CheckInFormComponent implements OnInit { this.currentDate = new Date(); this.keyResult = data.keyResult; this.setDefaultValues(); + this.setValidators(this.keyResult.keyResultType); } ngOnInit() { @@ -65,19 +72,13 @@ export class CheckInFormComponent implements OnInit { this.dialogForm.patchValue({ actionList: actionList }); } - getErrorMessage(error: string, field: string, maxLength: number): string { - return field + this.translate.instant('DIALOG_ERRORS.' + error) - .format(maxLength); - } - setDefaultValues() { this.dialogForm.controls.actionList.setValue(this.keyResult.actionList); - if (this.data.checkIn != null) { - this.checkIn = this.data.checkIn; - this.dialogForm.controls.value.setValue(this.getCheckInValue()); - this.dialogForm.controls.confidence.setValue(this.checkIn.confidence); - this.dialogForm.controls.changeInfo.setValue(this.checkIn.changeInfo); - this.dialogForm.controls.initiatives.setValue(this.checkIn.initiatives); + this.checkIn = this.data.checkIn; + + if (this.checkIn != null) { + this.dialogForm.patchValue({ ...this.checkIn }); + this.setValueOrZone(); return; } @@ -95,6 +96,12 @@ export class CheckInFormComponent implements OnInit { this.checkIn = { confidence: 5 } as CheckInMin; } + setValueOrZone() { + this.keyResult.keyResultType === 'metric' + ? this.dialogForm.controls.metricValue.setValue((this.checkIn as CheckInMetricMin).value) + : this.dialogForm.controls.ordinalZone.setValue((this.checkIn as CheckInOrdinalMin).zone); + } + calculateTarget(keyResult: KeyResultMetric): number { return keyResult.stretchGoal - (keyResult.stretchGoal - keyResult.baseline) * 0.3; } @@ -104,7 +111,6 @@ export class CheckInFormComponent implements OnInit { const actionList: Action[] = this.actionList$.value as Action[]; this.dialogForm.patchValue({ actionList: actionList }); - const baseCheckIn: any = { id: this.checkIn.id, version: this.checkIn.version, @@ -113,12 +119,15 @@ export class CheckInFormComponent implements OnInit { changeInfo: this.dialogForm.controls.changeInfo.value, initiatives: this.dialogForm.controls.initiatives.value }; - const checkIn: CheckIn = { - ...baseCheckIn, - [this.keyResult.keyResultType === 'ordinal' ? 'zone' : 'value']: this.dialogForm.controls.value.value - }; - this.checkInService.saveCheckIn(checkIn) + if (this.keyResult.keyResultType === 'metric') { + baseCheckIn.value = this.dialogForm.controls.metricValue.value; + } + if (this.keyResult.keyResultType === 'ordinal') { + baseCheckIn.zone = this.dialogForm.controls.ordinalZone.value; + } + + this.checkInService.saveCheckIn(baseCheckIn) .subscribe(() => { this.actionService.updateActions(this.dialogForm.value.actionList!) .subscribe(() => { @@ -127,14 +136,6 @@ export class CheckInFormComponent implements OnInit { }); } - getCheckInValue(): string { - if ((this.checkIn as CheckInMetricMin).value != null) { - return (this.checkIn as CheckInMetricMin).value!.toString(); - } else { - return (this.checkIn as CheckInOrdinalMin).zone!; - } - } - getKeyResultMetric(): KeyResultMetric { return this.keyResult as KeyResultMetric; } @@ -178,4 +179,11 @@ export class CheckInFormComponent implements OnInit { this.dialogForm.patchValue({ actionList: actionList }); this.isAddingAction = false; } + + setValidators(type: string) { + this.checkInTypes.map((e) => this.dialogForm.get(e)) + .forEach((e) => e?.disable({ emitEvent: false })); + this.dialogForm.get(this.checkInTypes.filter((formName) => formName.includes(type))) + ?.enable({ emitEvent: false }); + } } diff --git a/frontend/src/app/components/key-result-dialog/key-result-dialog.component.ts b/frontend/src/app/components/key-result-dialog/key-result-dialog.component.ts index 508ed16135..8728e95211 100644 --- a/frontend/src/app/components/key-result-dialog/key-result-dialog.component.ts +++ b/frontend/src/app/components/key-result-dialog/key-result-dialog.component.ts @@ -20,6 +20,9 @@ import { UserService } from '../../services/user.service'; export class KeyResultDialogComponent implements OnInit { keyResultForm: FormGroup = getKeyResultForm(); + keyResultTypes: string[] = ['metric', + 'ordinal']; + constructor( @Inject(MAT_DIALOG_DATA) public data: { objective: Objective; @@ -91,18 +94,10 @@ export class KeyResultDialogComponent implements OnInit { } setValidators(type: string) { - if (type == 'metric') { - this.keyResultForm.get('metric') - ?.enable({ emitEvent: false }); - this.keyResultForm.get('ordinal') - ?.disable({ emitEvent: false }); - } - if (type == 'ordinal') { - this.keyResultForm.get('metric') - ?.disable({ emitEvent: false }); - this.keyResultForm.get('ordinal') - ?.enable({ emitEvent: false }); - } + this.keyResultTypes.map((e) => this.keyResultForm.get(e)) + .forEach((e) => e?.disable({ emitEvent: false })); + this.keyResultForm.get(type) + ?.enable({ emitEvent: false }); } ngOnInit(): void { diff --git a/frontend/src/app/shared/constant-library.ts b/frontend/src/app/shared/constant-library.ts index a5c002d38a..ac14ce753d 100644 --- a/frontend/src/app/shared/constant-library.ts +++ b/frontend/src/app/shared/constant-library.ts @@ -127,9 +127,9 @@ function ownerValidator(): ValidatorFn { }; } -function numberValidator(): ValidatorFn { +export function numberValidator(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { - const isAllowed = (/^-?\d+\.?\d*$/).test(control.value); + const isAllowed = !Number.isNaN(+control.value); return isAllowed ? null : { number: { value: control.value } }; }; } diff --git a/frontend/src/app/shared/custom/error/error.component.ts b/frontend/src/app/shared/custom/error/error.component.ts index d3852b8ca2..86b8f743be 100644 --- a/frontend/src/app/shared/custom/error/error.component.ts +++ b/frontend/src/app/shared/custom/error/error.component.ts @@ -16,6 +16,8 @@ export class ErrorComponent { @Input() name?: string; + @Input() maxErrors: number = Number.POSITIVE_INFINITY; + constructor(private translate: TranslateService, private parentF: FormGroupDirective) { } @@ -27,7 +29,8 @@ export class ErrorComponent { } return Object.entries(formField.errors || {}) .map(([key, - value]) => this.buildErrorMessage(key, value)); + value]) => this.buildErrorMessage(key, value)) + .slice(0, this.maxErrors); } buildErrorMessage(key: string, value: any): string { diff --git a/frontend/src/app/shared/types/model/check-in-metric-min.ts b/frontend/src/app/shared/types/model/check-in-metric-min.ts index f5b5c3186c..0871ceeb8d 100644 --- a/frontend/src/app/shared/types/model/check-in-metric-min.ts +++ b/frontend/src/app/shared/types/model/check-in-metric-min.ts @@ -1,5 +1,5 @@ import { CheckInMin } from './check-in-min'; export interface CheckInMetricMin extends CheckInMin { - value: number | undefined; + value: number; } diff --git a/frontend/src/app/shared/types/model/check-in-ordinal-min.ts b/frontend/src/app/shared/types/model/check-in-ordinal-min.ts index b1a7c04c09..8144e1404b 100644 --- a/frontend/src/app/shared/types/model/check-in-ordinal-min.ts +++ b/frontend/src/app/shared/types/model/check-in-ordinal-min.ts @@ -1,5 +1,6 @@ import { CheckInMin } from './check-in-min'; +import { Zone } from '../enums/zone'; export interface CheckInOrdinalMin extends CheckInMin { - zone: string | undefined; + zone: Zone; }