From 14e93d27abac5e203c1ab38e88ed80efdf5beaed Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Thu, 30 Nov 2023 11:10:55 +0100 Subject: [PATCH 1/9] Add confirm dialog on draft, adjust state tooltip and rename freigeben --- frontend/cypress/e2e/objective.cy.ts | 2 +- .../keyresult-detail.component.html | 2 +- .../keyresult-detail.component.ts | 38 ++++++++++++++++++- .../app/objective/objective.component.html | 2 +- .../src/app/objective/objective.component.ts | 17 ++++++++- .../confirm-dialog.component.ts | 32 +++++++++------- frontend/src/assets/i18n/de.json | 3 ++ 7 files changed, 78 insertions(+), 18 deletions(-) diff --git a/frontend/cypress/e2e/objective.cy.ts b/frontend/cypress/e2e/objective.cy.ts index 1273087421..9ced6699b3 100644 --- a/frontend/cypress/e2e/objective.cy.ts +++ b/frontend/cypress/e2e/objective.cy.ts @@ -100,7 +100,7 @@ describe('OKR Objective e2e tests', () => { .last() .getByTestId('three-dot-menu') .click(); - cy.get('.mat-mdc-menu-content').contains('Objective freigeben').click(); + cy.get('.mat-mdc-menu-content').contains('Objective veröffentlichen').click(); cy.getByTestId('confirmYes').click(); cy.getByTestId('objective') diff --git a/frontend/src/app/keyresult-detail/keyresult-detail.component.html b/frontend/src/app/keyresult-detail/keyresult-detail.component.html index c48d8ad322..26ee09c3b1 100644 --- a/frontend/src/app/keyresult-detail/keyresult-detail.component.html +++ b/frontend/src/app/keyresult-detail/keyresult-detail.component.html @@ -130,7 +130,7 @@

Action Plan

cdkFocusInitial color="primary" mat-flat-button - (click)="openCheckInForm()" + (click)="checkForDraftState(keyResult)" [attr.data-testId]="'add-check-in'" > Check-in erfassen diff --git a/frontend/src/app/keyresult-detail/keyresult-detail.component.ts b/frontend/src/app/keyresult-detail/keyresult-detail.component.ts index 03f0c84397..31060b5779 100644 --- a/frontend/src/app/keyresult-detail/keyresult-detail.component.ts +++ b/frontend/src/app/keyresult-detail/keyresult-detail.component.ts @@ -11,9 +11,10 @@ import { RefreshDataService } from '../shared/services/refresh-data.service'; import { CloseState } from '../shared/types/enums/CloseState'; import { CheckInFormComponent } from '../shared/dialog/checkin/check-in-form/check-in-form.component'; import { State } from '../shared/types/enums/State'; -import { DATE_FORMAT } from '../shared/constantLibary'; +import { CONFIRM_DIALOG_WIDTH, DATE_FORMAT } from '../shared/constantLibary'; import { isInValid, isMobileDevice } from '../shared/common'; import { KeyresultDialogComponent } from '../shared/dialog/keyresult-dialog/keyresult-dialog.component'; +import { ConfirmDialogComponent } from '../shared/dialog/confirm-dialog/confirm-dialog.component'; @Component({ selector: 'app-keyresult-detail', @@ -127,6 +128,41 @@ export class KeyresultDetailComponent implements OnInit { }); } + checkForDraftState(keyResult: KeyResult) { + if (keyResult.objective.state.toUpperCase() === 'DRAFT') { + const dialogConfig = isMobileDevice() + ? { + maxWidth: '100vw', + maxHeight: '100vh', + height: '100vh', + width: CONFIRM_DIALOG_WIDTH, + } + : { + width: '45em', + height: 'auto', + }; + + this.dialog + .open(ConfirmDialogComponent, { + data: { + draftCreate: true, + }, + width: dialogConfig.width, + height: dialogConfig.height, + maxHeight: dialogConfig.maxHeight, + maxWidth: dialogConfig.maxWidth, + }) + .afterClosed() + .subscribe((result) => { + if (result) { + this.openCheckInForm(); + } + }); + } else { + this.openCheckInForm(); + } + } + openCheckInForm() { const dialogConfig = isMobileDevice() ? { diff --git a/frontend/src/app/objective/objective.component.html b/frontend/src/app/objective/objective.component.html index a2c1235217..ce638bf23e 100644 --- a/frontend/src/app/objective/objective.component.html +++ b/frontend/src/app/objective/objective.component.html @@ -11,7 +11,7 @@ The objectives state Date: Thu, 30 Nov 2023 13:56:40 +0100 Subject: [PATCH 2/9] Rename confirm dialog message --- .../shared/dialog/confirm-dialog/confirm-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.ts b/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.ts index ebd4105cbd..849a79493e 100644 --- a/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.ts +++ b/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.ts @@ -18,7 +18,7 @@ export class ConfirmDialogComponent implements OnInit { if (this.data.draftCreate) { this.dialogTitle = 'Check-in im Draft-Status'; this.dialogText = - 'Möchtest du wirklich ein Check-in zu einem Key Result erstellen, wessen Objective im Status DRAFT ist?'; + 'Dein Objective befindet sich noch im DRAFT Status. Möchtest du das Check-in trotzdem erfassen?'; } else { if (this.data.action) { if (this.data.action === 'release') { From 64a46a24d21b9127dfa4b5c33b240064a4b2c2ac Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Thu, 30 Nov 2023 16:35:30 +0100 Subject: [PATCH 3/9] Use new Error messages in frontend dialogs --- .../keyresult-type.component.html | 48 +++++++------------ .../keyresult-type.component.ts | 17 +++---- frontend/src/app/shared/common.ts | 8 ++++ .../check-in-form-metric.component.html | 8 ++-- .../check-in-form-metric.component.ts | 17 +++---- .../check-in-form.component.html | 16 +++---- .../check-in-form/check-in-form.component.ts | 16 +++---- .../complete-dialog.component.html | 8 ++-- .../complete-dialog.component.ts | 17 +++---- .../key-result-form.component.html | 22 ++++----- .../key-result-form.component.ts | 13 +++-- .../objective-form.component.html | 16 +++---- .../objective-form.component.ts | 16 +++---- .../team-management.component.html | 16 +++---- .../team-management.component.ts | 16 +++---- frontend/src/assets/i18n/de.json | 8 +++- 16 files changed, 110 insertions(+), 152 deletions(-) diff --git a/frontend/src/app/keyresult-type/keyresult-type.component.html b/frontend/src/app/keyresult-type/keyresult-type.component.html index 59a52cee8a..d13367c42a 100644 --- a/frontend/src/app/keyresult-type/keyresult-type.component.html +++ b/frontend/src/app/keyresult-type/keyresult-type.component.html @@ -45,11 +45,9 @@ {{ "UNIT." + unit.value | translate }} -
- - {{ errorMessages[errorKey.toUpperCase()] }} - -
+ + {{ getErrorMessage("MUST_SELECT", "Einheit", null, null) }} +
@@ -61,11 +59,9 @@ formControlName="baseline" id="baseline" /> - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("MUST_BE_NUMBER", "Baseline", null, null) }} +
@@ -77,11 +73,9 @@ formControlName="stretchGoal" id="stretchGoal" /> - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("MUST_BE_NUMBER", "Stretch Goal", null, null) }} +
@@ -105,11 +99,9 @@ id="commitZone" [attr.data-testId]="'commitZone'" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("SIZE_BETWEEN", "Commit Zone", 1, 400) }} +
@@ -121,11 +113,9 @@ formControlName="targetZone" id="targetZone" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("SIZE_BETWEEN", "Target Zone", 1, 400) }} +
@@ -137,11 +127,9 @@ formControlName="stretchZone" id="stretchZone" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("SIZE_BETWEEN", "Stretch Zone", 1, 400) }} +
diff --git a/frontend/src/app/keyresult-type/keyresult-type.component.ts b/frontend/src/app/keyresult-type/keyresult-type.component.ts index a736dd8531..4e1ad5f846 100644 --- a/frontend/src/app/keyresult-type/keyresult-type.component.ts +++ b/frontend/src/app/keyresult-type/keyresult-type.component.ts @@ -3,9 +3,9 @@ import { KeyResult } from '../shared/types/model/KeyResult'; import { FormGroup, Validators } from '@angular/forms'; import { KeyResultMetric } from '../shared/types/model/KeyResultMetric'; import { KeyResultOrdinal } from '../shared/types/model/KeyResultOrdinal'; -import errorMessages from '../../assets/errors/error-messages.json'; import { Unit } from '../shared/types/enums/Unit'; -import { formInputCheck } from '../shared/common'; +import { formInputCheck, hasFormFieldErrors } from '../shared/common'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-keyresult-type', @@ -18,9 +18,11 @@ export class KeyresultTypeComponent implements OnInit { @Output() formValidityEmitter = new EventEmitter(); isMetric: boolean = true; typeChangeAllowed: boolean = true; - protected readonly errorMessages: any = errorMessages; protected readonly Unit = Unit; protected readonly formInputCheck = formInputCheck; + protected readonly hasFormFieldErrors = hasFormFieldErrors; + + constructor(private translate: TranslateService) {} ngOnInit(): void { if (this.keyresult) { @@ -98,12 +100,7 @@ export class KeyresultTypeComponent implements OnInit { } } - isTouchedOrDirty(name: string) { - return this.keyResultForm.get(name)?.dirty || this.keyResultForm.get(name)?.touched; - } - - getErrorKeysOfFormField(name: string) { - const errors = this.keyResultForm.get(name)?.errors; - return errors == null ? [] : Object.keys(errors); + getErrorMessage(error: string, field: string, firstNumber: number | null, secondNumber: number | null): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(firstNumber, secondNumber); } } diff --git a/frontend/src/app/shared/common.ts b/frontend/src/app/shared/common.ts index 6d98093c06..1421cb60f1 100644 --- a/frontend/src/app/shared/common.ts +++ b/frontend/src/app/shared/common.ts @@ -94,3 +94,11 @@ export function getQuarterLabel(quarter: any, index: number): string { export function isMobileDevice() { return window.navigator.userAgent.toLowerCase().includes('mobile'); } + +export function hasFormFieldErrors(formGroup: FormGroup, field: string) { + if (formGroup.get(field)?.dirty || formGroup.get(field)?.touched) { + return formGroup.get(field)?.errors; + } else { + return false; + } +} diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.html b/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.html index a0bbe9193b..d16ee9f51b 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.html +++ b/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.html @@ -12,9 +12,7 @@ {{ generateUnitLabel() }} - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("MUST_BE_NUMBER", "Neuer Wert") }} + diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.ts b/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.ts index a2f3322bd1..2af5bdb634 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.ts +++ b/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; -import errorMessages from '../../../../../assets/errors/error-messages.json'; import { KeyResultMetric } from '../../../types/model/KeyResultMetric'; import { CheckInMin } from '../../../types/model/CheckInMin'; -import { formInputCheck } from '../../../common'; +import { formInputCheck, hasFormFieldErrors } from '../../../common'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-check-in-form-metric', @@ -18,8 +18,10 @@ export class CheckInFormMetricComponent implements OnInit { checkIn!: CheckInMin; @Input() dialogForm!: FormGroup; - protected readonly errorMessages: any = errorMessages; protected readonly formInputCheck = formInputCheck; + protected readonly hasFormFieldErrors = hasFormFieldErrors; + + constructor(private translate: TranslateService) {} ngOnInit() { this.dialogForm.controls['value'].setValidators([Validators.required, Validators.pattern('^-?\\d+\\.?\\d*$')]); @@ -38,12 +40,7 @@ export class CheckInFormMetricComponent implements OnInit { } } - isTouchedOrDirty(name: string) { - return this.dialogForm.get(name)?.dirty || this.dialogForm.get(name)?.touched; - } - - getErrorKeysOfFormField(name: string) { - const errors = this.dialogForm.get(name)?.errors; - return errors === null ? [] : Object.keys(errors!); + getErrorMessage(error: string, field: string): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error); } } diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html index cc7e41045e..613f10be41 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html +++ b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html @@ -28,11 +28,9 @@ class="big-dialog-form-field" formControlName="changeInfo" > -
- - {{ errorMessages[errorKey.toUpperCase()] }} - -
+ + {{ getErrorMessage("MAX_VALUE", "Kommentar / Veränderung", 4096, null) }} + -
- - {{ errorMessages[errorKey.toUpperCase()] }} - -
+ + {{ getErrorMessage("MAX_VALUE", "Massnahmen", 4096, null) }} +
diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts index e898eb5269..3744e0f4fc 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts +++ b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts @@ -9,8 +9,8 @@ import { ParseUnitValuePipe } from '../../../pipes/parse-unit-value/parse-unit-v import { CheckInService } from '../../../services/check-in.service'; import { Action } from '../../../types/model/Action'; import { ActionService } from '../../../services/action.service'; -import { formInputCheck } from '../../../common'; -import errorMessages from '../../../../../assets/errors/error-messages.json'; +import { formInputCheck, hasFormFieldErrors } from '../../../common'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-check-in-form', @@ -31,7 +31,7 @@ export class CheckInFormComponent implements OnInit { actionList: new FormControl([]), }); protected readonly formInputCheck = formInputCheck; - protected readonly errorMessages: { [key: string]: string } = errorMessages; + protected readonly hasFormFieldErrors = hasFormFieldErrors; constructor( public dialogRef: MatDialogRef, @@ -39,6 +39,7 @@ export class CheckInFormComponent implements OnInit { public parserPipe: ParseUnitValuePipe, private checkInService: CheckInService, private actionService: ActionService, + private translate: TranslateService, ) { this.currentDate = new Date(); this.keyResult = data.keyResult; @@ -49,13 +50,8 @@ export class CheckInFormComponent implements OnInit { this.dialogForm.patchValue({ actionList: this.keyResult.actionList }); } - isTouchedOrDirty(name: string) { - return this.dialogForm.get(name)?.dirty || this.dialogForm.get(name)?.touched; - } - - getErrorKeysOfFormField(name: string): string[] { - const errors = this.dialogForm.get(name)?.errors; - return errors == null ? [] : Object.keys(errors); + getErrorMessage(error: string, field: string, firstNumber: number | null, secondNumber: number | null): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(firstNumber, secondNumber); } setDefaultValues() { diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html index 89658a2799..e0844f08c2 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html @@ -48,11 +48,9 @@ [ngClass]="formInputCheck(completeForm, 'comment')" id="comment" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("MAX_VALUE", "Kommentar", 4096) }} +
diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts index 0113882e2c..4ea353be8f 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts @@ -1,8 +1,8 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { formInputCheck } from '../../common'; -import errorMessages from '../../../../assets/errors/error-messages.json'; +import { formInputCheck, hasFormFieldErrors } from '../../common'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-complete-dialog', @@ -15,10 +15,12 @@ export class CompleteDialogComponent { comment: new FormControl(null, [Validators.maxLength(4096)]), }); protected readonly formInputCheck = formInputCheck; + protected readonly hasFormFieldErrors = hasFormFieldErrors; constructor( public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: { objectiveTitle: string }, + private translate: TranslateService, ) {} switchSuccessState(input: string) { @@ -48,14 +50,7 @@ export class CompleteDialogComponent { }); } - isTouchedOrDirty(name: string) { - return this.completeForm.get(name)?.dirty || this.completeForm.get(name)?.touched; + getErrorMessage(error: string, field: string, maxLength: number | null): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(maxLength); } - - getErrorKeysOfFormField(name: string) { - const errors = this.completeForm.get(name)?.errors; - return errors == null ? [] : Object.keys(errors); - } - - protected readonly errorMessages: any = errorMessages; } diff --git a/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.html b/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.html index 72e7b8c7f8..6918f71845 100644 --- a/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.html +++ b/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.html @@ -9,11 +9,9 @@ formControlName="title" id="title" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("SIZE_BETWEEN", "Titel", 2, 250) }} +
@@ -40,9 +38,9 @@ {{ user.firstname + " " + user.lastname }} -
- Du musst einen Owner auswählen -
+ + {{ getErrorMessage("MUST_SELECT", "Owner", null, null) }} +
@@ -54,11 +52,9 @@ formControlName="description" id="description" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("MAX_VALUE", "Beschreibung", 4096, null) }} +
diff --git a/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.ts b/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.ts index bd1cd84ded..e273ab0e93 100644 --- a/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.ts +++ b/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.ts @@ -2,14 +2,14 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core import { FormGroup } from '@angular/forms'; import { User } from '../../types/model/User'; import { KeyResult } from '../../types/model/KeyResult'; -import errorMessages from '../../../../assets/errors/error-messages.json'; import { KeyResultMetric } from '../../types/model/KeyResultMetric'; import { KeyResultOrdinal } from '../../types/model/KeyResultOrdinal'; import { BehaviorSubject, filter, map, Observable, of, startWith, switchMap } from 'rxjs'; import { UserService } from '../../services/user.service'; import { Action } from '../../types/model/Action'; -import { formInputCheck } from '../../common'; +import { formInputCheck, hasFormFieldErrors } from '../../common'; import { OAuthService } from 'angular-oauth2-oidc'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-key-result-form', @@ -22,17 +22,17 @@ export class KeyResultFormComponent implements OnInit { filteredUsers$: Observable | undefined = of([]); actionList$: BehaviorSubject = new BehaviorSubject([] as Action[]); protected readonly formInputCheck = formInputCheck; + protected readonly hasFormFieldErrors = hasFormFieldErrors; @Input() keyResultForm!: FormGroup; @Input() keyResult!: KeyResult | null; - protected readonly errorMessages: any = errorMessages; - constructor( public userService: UserService, private oauthService: OAuthService, + private translate: TranslateService, ) {} ngOnInit(): void { @@ -96,9 +96,8 @@ export class KeyResultFormComponent implements OnInit { return this.keyResultForm.get(name)?.dirty || this.keyResultForm.get(name)?.touched; } - getErrorKeysOfFormField(name: string) { - const errors = this.keyResultForm.get(name)?.errors; - return errors == null ? [] : Object.keys(errors); + getErrorMessage(error: string, field: string, firstNumber: number | null, secondNumber: number | null): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(firstNumber, secondNumber); } filter(value: string): Observable { diff --git a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.html b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.html index a720765341..5cb6f00008 100644 --- a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.html +++ b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.html @@ -28,11 +28,9 @@ formControlName="title" id="title" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("SIZE_BETWEEN", "Titel", 2, 250) }} +
@@ -42,11 +40,9 @@ class="big-dialog-form-field" [ngClass]="formInputCheck(objectiveForm, 'description')" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("MAX_VALUE", "Beschreibung", 4096, null) }} +
diff --git a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts index 04af4ea776..0e3a61aff8 100644 --- a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts +++ b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts @@ -10,11 +10,11 @@ import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dial import { State } from '../../types/enums/State'; import { ObjectiveMin } from '../../types/model/ObjectiveMin'; import { Objective } from '../../types/model/Objective'; -import errorMessages from '../../../../assets/errors/error-messages.json'; import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component'; -import { formInputCheck, getQuarterLabel, getValueFromQuery, isMobileDevice } from '../../common'; +import { formInputCheck, getQuarterLabel, getValueFromQuery, hasFormFieldErrors, isMobileDevice } from '../../common'; import { ActivatedRoute } from '@angular/router'; import { CONFIRM_DIALOG_WIDTH } from '../../constantLibary'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-objective-form', @@ -36,8 +36,8 @@ export class ObjectiveFormComponent implements OnInit { currentTeam: Subject = new Subject(); state: string | null = null; version!: number; - protected readonly errorMessages: any = errorMessages; protected readonly formInputCheck = formInputCheck; + protected readonly hasFormFieldErrors = hasFormFieldErrors; constructor( private route: ActivatedRoute, @@ -55,6 +55,7 @@ export class ObjectiveFormComponent implements OnInit { teamVersion?: number; }; }, + private translate: TranslateService, ) {} onSubmit(submitType: any): void { @@ -168,13 +169,8 @@ export class ObjectiveFormComponent implements OnInit { }); } - isTouchedOrDirty(name: string) { - return this.objectiveForm.get(name)?.dirty || this.objectiveForm.get(name)?.touched; - } - - getErrorKeysOfFormField(name: string) { - const errors = this.objectiveForm.get(name)?.errors; - return errors == null ? [] : Object.keys(errors); + getErrorMessage(error: string, field: string, firstNumber: number | null, secondNumber: number | null): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(firstNumber, secondNumber); } getDefaultObjective() { diff --git a/frontend/src/app/shared/dialog/team-management/team-management.component.html b/frontend/src/app/shared/dialog/team-management/team-management.component.html index b372295549..85b5f97d7b 100644 --- a/frontend/src/app/shared/dialog/team-management/team-management.component.html +++ b/frontend/src/app/shared/dialog/team-management/team-management.component.html @@ -14,11 +14,9 @@ formControlName="name" id="name" > - - - {{ errorMessages[errorKey.toUpperCase()] }} - - + + {{ getErrorMessage("SIZE_BETWEEN", "Teamname", 2, 250) }} +
@@ -49,11 +47,9 @@ -
- - {{ errorMessages[errorKey.toUpperCase()] }} - -
+ + {{ getErrorMessage("MUST_SELECT", "Organisation", null, null) }} +
diff --git a/frontend/src/app/shared/dialog/team-management/team-management.component.ts b/frontend/src/app/shared/dialog/team-management/team-management.component.ts index b32a7f060d..f948456cf3 100644 --- a/frontend/src/app/shared/dialog/team-management/team-management.component.ts +++ b/frontend/src/app/shared/dialog/team-management/team-management.component.ts @@ -1,8 +1,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { formInputCheck, isMobileDevice } from '../../common'; +import { formInputCheck, isMobileDevice, hasFormFieldErrors } from '../../common'; import { FormControl, FormGroup, Validators } from '@angular/forms'; -import errorMessages from '../../../../assets/errors/error-messages.json'; import { Organisation } from '../../types/model/Organisation'; import { OrganisationService } from '../../services/organisation.service'; import { Observable, of } from 'rxjs'; @@ -13,6 +12,7 @@ import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.compone import { OrganisationState } from '../../types/enums/OrganisationState'; import { CONFIRM_DIALOG_WIDTH } from '../../constantLibary'; import { CloseState } from '../../types/enums/CloseState'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-team-management', @@ -27,7 +27,7 @@ export class TeamManagementComponent implements OnInit { organisations$: Observable = new Observable(); public hasInActiveOrganisations: boolean = false; protected readonly formInputCheck = formInputCheck; - protected readonly errorMessages: any = errorMessages; + protected readonly hasFormFieldErrors = hasFormFieldErrors; constructor( public dialogRef: MatDialogRef, @@ -38,6 +38,7 @@ export class TeamManagementComponent implements OnInit { public data: { team: TeamMin; }, + private translate: TranslateService, ) {} ngOnInit(): void { @@ -126,13 +127,8 @@ export class TeamManagementComponent implements OnInit { return { 'text-decoration': isInActive ? 'line-through' : 'none' }; } - isTouchedOrDirty(name: string) { - return this.teamForm.get(name)?.dirty || this.teamForm.get(name)?.touched; - } - - getErrorKeysOfFormField(name: string) { - const errors = this.teamForm.get(name)?.errors; - return errors == null ? [] : Object.keys(errors); + getErrorMessage(error: string, field: string, firstNumber: number | null, secondNumber: number | null): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(firstNumber, secondNumber); } compareWithFunc(a: Organisation, b: Organisation) { diff --git a/frontend/src/assets/i18n/de.json b/frontend/src/assets/i18n/de.json index 3e7c1e2e4e..48dc0ac06c 100644 --- a/frontend/src/assets/i18n/de.json +++ b/frontend/src/assets/i18n/de.json @@ -43,7 +43,7 @@ "ATTRIBUTE_NOT_SET": "Das Attribut {0} ist nicht gesetzt", "ATTRIBUTE_CANNOT_CHANGE": "Das Attribut {0} auf dem Objekt {1} kann nicht geändert werden", "ATTRIBUTE_MIN_VALUE": "Das Attribut {0} auf dem Objekt muss mindestens einen Wert von {1} haben", - "ATTRIBUTE_MAX_VALUE": "Das Attribut {0} auf dem Objekt darf maximal einen Wert von {1} haben", + "ATTRIBUTE_MAX_VALUE": "Das Attribut {0} auf dem Objekt {1} darf maximal einen Wert von {2} haben", "NOT_AUTHORIZED_TO_READ": "Du bist nicht autorisiert um dieses {0} anzuzeigen", "NOT_AUTHORIZED_TO_WRITE": "Du bist nicht autorisiert um dieses {0} zu bearbeiten", "NOT_AUTHORIZED_TO_DELETE": "Du bist nicht autorisiert um dieses {0} zu löschen", @@ -72,5 +72,11 @@ "POST": "Das Check-in wurde erfolgreich erstellt", "PUT": "Das Check-in wurde erfolgreich aktualisiert" } + }, + "DIALOG_ERRORS": { + "MUST_BE_NUMBER": " muss eine Zahl sein", + "MUST_SELECT": " muss ausgewählt sein", + "MAX_VALUE": " darf maximal eine Länge von {0} haben", + "SIZE_BETWEEN": " muss folgende Länge haben: {0}-{1}" } } From 585a32175b3f0b847a2a45a3658b941953e92a0f Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Thu, 30 Nov 2023 16:42:51 +0100 Subject: [PATCH 4/9] Fix frontend tests --- .../app/objective/objective.component.spec.ts | 5 +++++ .../check-in-form-metric.component.spec.ts | 5 +++++ .../check-in-form.component.spec.ts | 5 +++++ .../complete-dialog.component.spec.ts | 2 ++ .../key-result-form.component.spec.ts | 5 +++++ .../objective-form.component.spec.ts | 5 +++++ .../team-management.component.spec.ts | 2 ++ frontend/src/app/team/team.component.spec.ts | 21 +++++++++++-------- 8 files changed, 41 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/objective/objective.component.spec.ts b/frontend/src/app/objective/objective.component.spec.ts index 6dc8d69ec7..ecdf43dd01 100644 --- a/frontend/src/app/objective/objective.component.spec.ts +++ b/frontend/src/app/objective/objective.component.spec.ts @@ -19,6 +19,8 @@ import { MatTooltipModule } from '@angular/material/tooltip'; import { ScoringComponent } from '../shared/custom/scoring/scoring.component'; import { ConfidenceComponent } from '../confidence/confidence.component'; import { ReactiveFormsModule } from '@angular/forms'; +import * as de from '../../assets/i18n/de.json'; +import { TranslateTestingModule } from 'ngx-translate-testing'; const overviewServiceMock = { getObjectiveWithKeyresults: jest.fn(), @@ -42,6 +44,9 @@ describe('ObjectiveColumnComponent', () => { MatIconModule, MatTooltipModule, ReactiveFormsModule, + TranslateTestingModule.withTranslations({ + de: de, + }), ], providers: [{ provide: OverviewService, useValue: overviewServiceMock }], }).compileComponents(); diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts b/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts index 9962c2d462..2c7d15bb3b 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts +++ b/frontend/src/app/shared/dialog/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts @@ -11,6 +11,8 @@ import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; import { Unit } from '../../../types/enums/Unit'; import { ParseUnitValuePipe } from '../../../pipes/parse-unit-value/parse-unit-value.pipe'; +import { TranslateTestingModule } from 'ngx-translate-testing'; +import * as de from '../../../../../assets/i18n/de.json'; describe('CheckInFormComponent', () => { let component: CheckInFormMetricComponent; @@ -25,6 +27,9 @@ describe('CheckInFormComponent', () => { MatInputModule, MatRadioModule, ReactiveFormsModule, + TranslateTestingModule.withTranslations({ + de: de, + }), ], declarations: [CheckInFormMetricComponent, UnitValueTransformationPipe], providers: [UnitValueTransformationPipe, ParseUnitValuePipe], diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.spec.ts b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.spec.ts index bb5f938552..e63bc52673 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.spec.ts +++ b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.spec.ts @@ -23,6 +23,8 @@ import { ParseUnitValuePipe } from '../../../pipes/parse-unit-value/parse-unit-v import { CheckInService } from '../../../services/check-in.service'; import { of } from 'rxjs'; import { ActionService } from '../../../services/action.service'; +import * as de from '../../../../../assets/i18n/de.json'; +import { TranslateTestingModule } from 'ngx-translate-testing'; const dialogMock = { close: jest.fn(), @@ -52,6 +54,9 @@ describe('CheckInFormComponent', () => { MatInputModule, NoopAnimationsModule, MatCheckboxModule, + TranslateTestingModule.withTranslations({ + de: de, + }), ], providers: [ { provide: MAT_DIALOG_DATA, useValue: { keyResult: {} } }, diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts index 53b4b9ec22..96dd62fa53 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts @@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CompleteDialogComponent } from './complete-dialog.component'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DialogHeaderComponent } from '../../custom/dialog-header/dialog-header.component'; +import { TranslateService } from '@ngx-translate/core'; const dialogMock = { close: jest.fn(), @@ -25,6 +26,7 @@ describe('CompleteDialogComponent', () => { providers: [ { provide: MatDialogRef, useValue: dialogMock }, { provide: MAT_DIALOG_DATA, useValue: matDataMock }, + { provide: TranslateService, useValue: {} }, ], }); fixture = TestBed.createComponent(CompleteDialogComponent); diff --git a/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.spec.ts b/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.spec.ts index 0d8caa98cd..70df372799 100644 --- a/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.spec.ts +++ b/frontend/src/app/shared/dialog/key-result-form/key-result-form.component.spec.ts @@ -25,6 +25,8 @@ import { KeyResultFormComponent } from '../key-result-form/key-result-form.compo import { Action } from '../../types/model/Action'; import { KeyResultMetric } from '../../types/model/KeyResultMetric'; import { KeyResultOrdinal } from '../../types/model/KeyResultOrdinal'; +import { TranslateTestingModule } from 'ngx-translate-testing'; +import * as de from '../../../../assets/i18n/de.json'; describe('KeyResultFormComponent', () => { let component: KeyResultFormComponent; @@ -100,6 +102,9 @@ describe('KeyResultFormComponent', () => { MatIconModule, TranslateModule.forRoot(), DragDropModule, + TranslateTestingModule.withTranslations({ + de: de, + }), ], providers: [ KeyresultService, diff --git a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts index 040e880c1f..f4c47ce796 100644 --- a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts +++ b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts @@ -24,6 +24,8 @@ import { By } from '@angular/platform-browser'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { RouterTestingHarness, RouterTestingModule } from '@angular/router/testing'; import { DialogHeaderComponent } from '../../custom/dialog-header/dialog-header.component'; +import { TranslateTestingModule } from 'ngx-translate-testing'; +import * as de from '../../../../assets/i18n/de.json'; let objectiveService = { getFullObjective: jest.fn(), @@ -78,6 +80,9 @@ describe('ObjectiveDialogComponent', () => { NoopAnimationsModule, MatCheckboxModule, RouterTestingModule, + TranslateTestingModule.withTranslations({ + de: de, + }), ], declarations: [ObjectiveFormComponent, DialogHeaderComponent], providers: [ diff --git a/frontend/src/app/shared/dialog/team-management/team-management.component.spec.ts b/frontend/src/app/shared/dialog/team-management/team-management.component.spec.ts index e4e5819190..feadaf94cb 100644 --- a/frontend/src/app/shared/dialog/team-management/team-management.component.spec.ts +++ b/frontend/src/app/shared/dialog/team-management/team-management.component.spec.ts @@ -18,6 +18,7 @@ import { of } from 'rxjs'; import { organisationActive, organisationInActive, teamFormObject, teamMin1 } from '../../testData'; import { Team } from '../../types/model/Team'; import { OrganisationService } from '../../services/organisation.service'; +import { TranslateService } from '@ngx-translate/core'; const dialogRefMock = { close: jest.fn(), @@ -79,6 +80,7 @@ describe('TeamManagementComponent', () => { provide: MAT_DIALOG_DATA, useValue: null, }, + { provide: TranslateService, useValue: {} }, ], }); fixture = TestBed.createComponent(TeamManagementComponent); diff --git a/frontend/src/app/team/team.component.spec.ts b/frontend/src/app/team/team.component.spec.ts index 9923830fff..21f808a76a 100644 --- a/frontend/src/app/team/team.component.spec.ts +++ b/frontend/src/app/team/team.component.spec.ts @@ -1,14 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TeamComponent } from './team.component'; import { MatIcon } from '@angular/material/icon'; -import { - organisationActive, - organisationInActive, - overViewEntity1, - overViewEntity2, - team1, - teamMin1, -} from '../shared/testData'; +import { overViewEntity1, overViewEntity2, team1, teamMin1 } from '../shared/testData'; import { ObjectiveComponent } from '../objective/objective.component'; import { RouterTestingModule } from '@angular/router/testing'; import { MatMenuModule } from '@angular/material/menu'; @@ -19,6 +12,8 @@ import { By } from '@angular/platform-browser'; import { OrganisationService } from '../shared/services/organisation.service'; import { of, ReplaySubject } from 'rxjs'; import { RefreshDataService } from '../shared/services/refresh-data.service'; +import { TranslateTestingModule } from 'ngx-translate-testing'; +import * as de from '../../assets/i18n/de.json'; const organisationServiceMock = { getOrganisationsByTeamId: jest.fn(), @@ -38,7 +33,15 @@ describe('TeamComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [RouterTestingModule, MatMenuModule, MatDialogModule, HttpClientTestingModule], + imports: [ + RouterTestingModule, + MatMenuModule, + MatDialogModule, + HttpClientTestingModule, + TranslateTestingModule.withTranslations({ + de: de, + }), + ], declarations: [TeamComponent, MatIcon, ObjectiveComponent, KeyresultComponent], providers: [ { From 8f47ada58e2324d7d2ccf17298ceb7920ae76174 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Fri, 1 Dec 2023 09:33:00 +0100 Subject: [PATCH 5/9] Fix e2e tests --- frontend/cypress/e2e/keyresult.cy.ts | 20 ++++++++++---------- frontend/cypress/e2e/objective.cy.ts | 11 ++++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/frontend/cypress/e2e/keyresult.cy.ts b/frontend/cypress/e2e/keyresult.cy.ts index 2e4ba4b143..0a7aa115ac 100644 --- a/frontend/cypress/e2e/keyresult.cy.ts +++ b/frontend/cypress/e2e/keyresult.cy.ts @@ -198,7 +198,7 @@ describe('OKR Overview', () => { cy.contains('This is my new description'); }); - it('Check validation in keyresult dialog', () => { + it.only('Check validation in keyresult dialog', () => { cy.getByTestId('objective').first().getByTestId('add-keyResult').first().click(); cy.getByTestId('submit').should('be.disabled'); cy.contains('Key Result erfassen'); @@ -219,28 +219,28 @@ describe('OKR Overview', () => { cy.getByTestId('titleInput').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Titel muss folgende Länge haben: 2-250'); cy.getByTestId('titleInput').type('My title'); cy.getByTestId('submit').should('not.be.disabled'); cy.getByTestId('baseline').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Baseline muss eine Zahl sein'); cy.getByTestId('baseline').type('abc'); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieser Wert muss dem vorgegebenen Muster entsprechen'); + cy.contains('Baseline muss eine Zahl sein'); cy.getByTestId('baseline').clear(); cy.getByTestId('baseline').type('45'); cy.getByTestId('submit').should('not.be.disabled'); cy.getByTestId('stretchGoal').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Stretch Goal muss eine Zahl sein'); cy.getByTestId('stretchGoal').type('abc'); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieser Wert muss dem vorgegebenen Muster entsprechen'); + cy.contains('Stretch Goal muss eine Zahl sein'); cy.getByTestId('stretchGoal').clear(); cy.getByTestId('stretchGoal').type('83'); @@ -251,7 +251,7 @@ describe('OKR Overview', () => { cy.getByTestId('ownerInput').type('abc'); cy.getByTestId('titleInput').type('Hello'); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Du musst einen Owner auswählen'); + cy.contains('Owner muss ausgewählt sein'); cy.getByTestId('ownerInput').clear(); cy.getByTestId('ownerInput').type('Pac').type('{downarrow}').type('{enter}'); @@ -267,19 +267,19 @@ describe('OKR Overview', () => { cy.getByTestId('commitZone').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Commit Zone muss folgende Länge haben: 1-400'); cy.getByTestId('commitZone').type('Commit'); cy.getByTestId('submit').should('not.be.disabled'); cy.getByTestId('targetZone').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Target Zone muss folgende Länge haben: 1-400'); cy.getByTestId('targetZone').type('Target'); cy.getByTestId('submit').should('not.be.disabled'); cy.getByTestId('stretchZone').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Stretch Zone muss folgende Länge haben: 1-400'); cy.getByTestId('stretchZone').type('Commit'); cy.getByTestId('submit').should('not.be.disabled'); diff --git a/frontend/cypress/e2e/objective.cy.ts b/frontend/cypress/e2e/objective.cy.ts index 9ced6699b3..b0880ce30f 100644 --- a/frontend/cypress/e2e/objective.cy.ts +++ b/frontend/cypress/e2e/objective.cy.ts @@ -35,8 +35,9 @@ describe('OKR Objective e2e tests', () => { it(`Create objective, should display error message`, () => { cy.getByTestId('add-objective').first().click(); + cy.getByTestId('title').first().clear(); cy.getByTestId('description').first().clear().type('description'); - cy.contains('Dieses Feld muss ausgefüllt sein'); + cy.contains('Titel muss folgende Länge haben: 2-250'); cy.getByTestId('safe').should('be.disabled'); cy.getByTestId('safe-draft').should('be.disabled'); cy.getByTestId('cancel').should('not.be.disabled'); @@ -122,8 +123,8 @@ describe('OKR Objective e2e tests', () => { cy.get('.mat-mdc-menu-content').contains('Objective abschliessen').click(); cy.contains('Bewertung'); - cy.contains('Objective erfolgreich'); - cy.contains('Objective nicht erfolgreich'); + cy.contains('Objective erreicht'); + cy.contains('Objective nicht erreicht'); cy.contains('Kommentar (optional)'); cy.contains('Objective abschliessen'); cy.contains('Abbrechen'); @@ -150,8 +151,8 @@ describe('OKR Objective e2e tests', () => { cy.get('.mat-mdc-menu-content').contains('Objective abschliessen').click(); cy.contains('Bewertung'); - cy.contains('Objective erfolgreich'); - cy.contains('Objective nicht erfolgreich'); + cy.contains('Objective erreicht'); + cy.contains('Objective nicht erreicht'); cy.contains('Kommentar (optional)'); cy.contains('Objective abschliessen'); cy.contains('Abbrechen'); From 6d3ba2c0276e5f14ae29322d9377672cf79adb32 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 4 Dec 2023 08:39:44 +0100 Subject: [PATCH 6/9] Remove some unused code --- frontend/cypress/e2e/keyresult.cy.ts | 2 +- frontend/cypress/e2e/tab.cy.ts | 4 ++-- .../dialog/checkin/check-in-form/check-in-form.component.html | 4 ++-- .../dialog/checkin/check-in-form/check-in-form.component.ts | 4 ++-- .../dialog/complete-dialog/complete-dialog.component.ts | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/cypress/e2e/keyresult.cy.ts b/frontend/cypress/e2e/keyresult.cy.ts index 0a7aa115ac..a520ed5954 100644 --- a/frontend/cypress/e2e/keyresult.cy.ts +++ b/frontend/cypress/e2e/keyresult.cy.ts @@ -198,7 +198,7 @@ describe('OKR Overview', () => { cy.contains('This is my new description'); }); - it.only('Check validation in keyresult dialog', () => { + it('Check validation in keyresult dialog', () => { cy.getByTestId('objective').first().getByTestId('add-keyResult').first().click(); cy.getByTestId('submit').should('be.disabled'); cy.contains('Key Result erfassen'); diff --git a/frontend/cypress/e2e/tab.cy.ts b/frontend/cypress/e2e/tab.cy.ts index ad2fa6b35c..3887c266b5 100644 --- a/frontend/cypress/e2e/tab.cy.ts +++ b/frontend/cypress/e2e/tab.cy.ts @@ -209,8 +209,8 @@ describe('Tab workflow tests', () => { cy.focused().contains('Objective abschliessen'); cy.realPress('Enter'); cy.contains('Objective abschliessen'); - cy.contains('Objective erfolgreich'); - cy.contains('Objective nicht erfolgreich'); + cy.contains('Objective erreicht'); + cy.contains('Objective nicht erreicht'); cy.tabForward(); cy.tabForward(); cy.realPress('Enter'); diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html index 613f10be41..56989a063c 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html +++ b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.html @@ -29,7 +29,7 @@ formControlName="changeInfo" > - {{ getErrorMessage("MAX_VALUE", "Kommentar / Veränderung", 4096, null) }} + {{ getErrorMessage("MAX_VALUE", "Kommentar / Veränderung", 4096) }}
@@ -55,7 +55,7 @@ formControlName="initiatives" > - {{ getErrorMessage("MAX_VALUE", "Massnahmen", 4096, null) }} + {{ getErrorMessage("MAX_VALUE", "Massnahmen", 4096) }}
diff --git a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts index 3744e0f4fc..c5f6c406ab 100644 --- a/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts +++ b/frontend/src/app/shared/dialog/checkin/check-in-form/check-in-form.component.ts @@ -50,8 +50,8 @@ export class CheckInFormComponent implements OnInit { this.dialogForm.patchValue({ actionList: this.keyResult.actionList }); } - getErrorMessage(error: string, field: string, firstNumber: number | null, secondNumber: number | null): string { - return field + this.translate.instant('DIALOG_ERRORS.' + error).format(firstNumber, secondNumber); + getErrorMessage(error: string, field: string, maxLength: number): string { + return field + this.translate.instant('DIALOG_ERRORS.' + error).format(maxLength); } setDefaultValues() { diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts index 4ea353be8f..ab8623bac5 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts @@ -50,7 +50,7 @@ export class CompleteDialogComponent { }); } - getErrorMessage(error: string, field: string, maxLength: number | null): string { + getErrorMessage(error: string, field: string, maxLength: number): string { return field + this.translate.instant('DIALOG_ERRORS.' + error).format(maxLength); } } From 28e607d70cafd4837d5472aed9dcc0d60d62c4e4 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 4 Dec 2023 10:19:55 +0100 Subject: [PATCH 7/9] Add e2e test --- frontend/cypress/e2e/checkIn.cy.ts | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/frontend/cypress/e2e/checkIn.cy.ts b/frontend/cypress/e2e/checkIn.cy.ts index bbf9c4a3dc..43864a0522 100644 --- a/frontend/cypress/e2e/checkIn.cy.ts +++ b/frontend/cypress/e2e/checkIn.cy.ts @@ -226,6 +226,37 @@ describe('OKR Check-in e2e tests', () => { cy.contains('Buy now a new pool'); cy.contains('STRETCH'); }); + + it.only(`Should display confirm dialog when creating checkin on draft objective`, () => { + cy.getByTestId('add-objective').first().click(); + cy.fillOutObjective('draft objective title', 'safe-draft', '3'); + cy.visit('/?quarter=3'); + cy.contains('draft objective title').first().parentsUntil('#objective-column').last().focus(); + + cy.tabForwardUntil('[data-testId="add-keyResult"]'); + cy.focused().contains('Key Result hinzufügen'); + cy.realPress('Enter'); + + cy.fillOutKeyResult( + 'I am a metric keyresult for testing', + 'PERCENT', + '21', + '52', + null, + null, + null, + null, + 'This is my description', + ); + cy.getByTestId('submit').click(); + + cy.getByTestId('keyresult').contains('I am a metric keyresult for testing').click(); + cy.tabForward(); + cy.tabForward(); + cy.focused().contains('Check-in erfassen').click(); + cy.contains('Check-in im Draft-Status'); + cy.contains('Dein Objective befindet sich noch im DRAFT Status. Möchtest du das Check-in trotzdem erfassen?'); + }); }); }); From 26c9d18646ba01dac2c8071cb79d802d03819e5f Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 4 Dec 2023 10:33:10 +0100 Subject: [PATCH 8/9] Fix bugs --- .../dialog/complete-dialog/complete-dialog.component.html | 6 ++++-- frontend/src/assets/i18n/de.json | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html index e0844f08c2..721fec9e86 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.html @@ -3,8 +3,10 @@ -

Objective

-

{{ data.objectiveTitle }}

+
+

Objective

+

{{ data.objectiveTitle }}

+
diff --git a/frontend/src/assets/i18n/de.json b/frontend/src/assets/i18n/de.json index 48dc0ac06c..842789979b 100644 --- a/frontend/src/assets/i18n/de.json +++ b/frontend/src/assets/i18n/de.json @@ -76,7 +76,7 @@ "DIALOG_ERRORS": { "MUST_BE_NUMBER": " muss eine Zahl sein", "MUST_SELECT": " muss ausgewählt sein", - "MAX_VALUE": " darf maximal eine Länge von {0} haben", - "SIZE_BETWEEN": " muss folgende Länge haben: {0}-{1}" + "MAX_VALUE": " darf maximal eine Länge von {0} Zeichen haben", + "SIZE_BETWEEN": " muss folgende Länge haben: {0}-{1} Zeichen" } } From 955317fef06cde6f2b9d6cfe4c8ae9c9fc7f94b6 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 4 Dec 2023 10:39:49 +0100 Subject: [PATCH 9/9] Fix e2e tests --- frontend/cypress/e2e/keyresult.cy.ts | 8 ++++---- frontend/cypress/e2e/objective.cy.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/cypress/e2e/keyresult.cy.ts b/frontend/cypress/e2e/keyresult.cy.ts index a520ed5954..257ba1475a 100644 --- a/frontend/cypress/e2e/keyresult.cy.ts +++ b/frontend/cypress/e2e/keyresult.cy.ts @@ -219,7 +219,7 @@ describe('OKR Overview', () => { cy.getByTestId('titleInput').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Titel muss folgende Länge haben: 2-250'); + cy.contains('Titel muss folgende Länge haben: 2-250 Zeichen'); cy.getByTestId('titleInput').type('My title'); cy.getByTestId('submit').should('not.be.disabled'); @@ -267,19 +267,19 @@ describe('OKR Overview', () => { cy.getByTestId('commitZone').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Commit Zone muss folgende Länge haben: 1-400'); + cy.contains('Commit Zone muss folgende Länge haben: 1-400 Zeichen'); cy.getByTestId('commitZone').type('Commit'); cy.getByTestId('submit').should('not.be.disabled'); cy.getByTestId('targetZone').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Target Zone muss folgende Länge haben: 1-400'); + cy.contains('Target Zone muss folgende Länge haben: 1-400 Zeichen'); cy.getByTestId('targetZone').type('Target'); cy.getByTestId('submit').should('not.be.disabled'); cy.getByTestId('stretchZone').clear(); cy.getByTestId('submit').should('be.disabled'); - cy.contains('Stretch Zone muss folgende Länge haben: 1-400'); + cy.contains('Stretch Zone muss folgende Länge haben: 1-400 Zeichen'); cy.getByTestId('stretchZone').type('Commit'); cy.getByTestId('submit').should('not.be.disabled'); diff --git a/frontend/cypress/e2e/objective.cy.ts b/frontend/cypress/e2e/objective.cy.ts index b0880ce30f..650fef4868 100644 --- a/frontend/cypress/e2e/objective.cy.ts +++ b/frontend/cypress/e2e/objective.cy.ts @@ -37,7 +37,7 @@ describe('OKR Objective e2e tests', () => { cy.getByTestId('add-objective').first().click(); cy.getByTestId('title').first().clear(); cy.getByTestId('description').first().clear().type('description'); - cy.contains('Titel muss folgende Länge haben: 2-250'); + cy.contains('Titel muss folgende Länge haben: 2-250 Zeichen'); cy.getByTestId('safe').should('be.disabled'); cy.getByTestId('safe-draft').should('be.disabled'); cy.getByTestId('cancel').should('not.be.disabled');