Skip to content

Commit

Permalink
Merge pull request #640 from puzzle/feature/619-wording-warnings
Browse files Browse the repository at this point in the history
Feature/619: Wording and Warnings
  • Loading branch information
peggimann authored Dec 4, 2023
2 parents b36dd24 + 955317f commit 58bd280
Show file tree
Hide file tree
Showing 33 changed files with 281 additions and 197 deletions.
31 changes: 31 additions & 0 deletions frontend/cypress/e2e/checkIn.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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?');
});
});
});

Expand Down
18 changes: 9 additions & 9 deletions frontend/cypress/e2e/keyresult.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 Zeichen');

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');
Expand All @@ -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}');
Expand All @@ -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 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('Dieses Feld muss ausgefüllt sein');
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('Dieses Feld muss ausgefüllt sein');
cy.contains('Stretch Zone muss folgende Länge haben: 1-400 Zeichen');

cy.getByTestId('stretchZone').type('Commit');
cy.getByTestId('submit').should('not.be.disabled');
Expand Down
13 changes: 7 additions & 6 deletions frontend/cypress/e2e/objective.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 Zeichen');
cy.getByTestId('safe').should('be.disabled');
cy.getByTestId('safe-draft').should('be.disabled');
cy.getByTestId('cancel').should('not.be.disabled');
Expand Down Expand Up @@ -100,7 +101,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')
Expand All @@ -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');
Expand All @@ -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');
Expand Down
4 changes: 2 additions & 2 deletions frontend/cypress/e2e/tab.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ <h2 class="sub-title-keyresult-detail fw-bold">Action Plan</h2>
cdkFocusInitial
color="primary"
mat-flat-button
(click)="openCheckInForm()"
(click)="checkForDraftState(keyResult)"
[attr.data-testId]="'add-check-in'"
>
Check-in erfassen
Expand Down
38 changes: 37 additions & 1 deletion frontend/src/app/keyresult-detail/keyresult-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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()
? {
Expand Down
48 changes: 18 additions & 30 deletions frontend/src/app/keyresult-type/keyresult-type.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,9 @@
{{ "UNIT." + unit.value | translate }}
</option>
</select>
<div *ngIf="isTouchedOrDirty('unit')">
<mat-error *ngFor="let errorKey of getErrorKeysOfFormField('unit')">
<span>{{ errorMessages[errorKey.toUpperCase()] }}</span>
</mat-error>
</div>
<mat-error *ngIf="hasFormFieldErrors(keyResultForm, 'unit')">
<span>{{ getErrorMessage("MUST_SELECT", "Einheit", null, null) }}</span>
</mat-error>
</div>

<div class="input-style gap-2">
Expand All @@ -61,11 +59,9 @@
formControlName="baseline"
id="baseline"
/>
<span *ngIf="isTouchedOrDirty('baseline')">
<mat-error *ngFor="let errorKey of getErrorKeysOfFormField('baseline')">
<span>{{ errorMessages[errorKey.toUpperCase()] }}</span>
</mat-error>
</span>
<mat-error *ngIf="hasFormFieldErrors(keyResultForm, 'baseline')">
<span>{{ getErrorMessage("MUST_BE_NUMBER", "Baseline", null, null) }}</span>
</mat-error>
</div>

<div class="input-style gap-2">
Expand All @@ -77,11 +73,9 @@
formControlName="stretchGoal"
id="stretchGoal"
/>
<span *ngIf="isTouchedOrDirty('stretchGoal')">
<mat-error *ngFor="let errorKey of getErrorKeysOfFormField('stretchGoal')">
<span>{{ errorMessages[errorKey.toUpperCase()] }}</span>
</mat-error>
</span>
<mat-error *ngIf="hasFormFieldErrors(keyResultForm, 'stretchGoal')">
<span>{{ getErrorMessage("MUST_BE_NUMBER", "Stretch Goal", null, null) }}</span>
</mat-error>
</div>
</div>
</div>
Expand All @@ -105,11 +99,9 @@
id="commitZone"
[attr.data-testId]="'commitZone'"
></textarea>
<span *ngIf="isTouchedOrDirty('commitZone')">
<mat-error *ngFor="let errorKey of getErrorKeysOfFormField('commitZone')">
<span>{{ errorMessages[errorKey.toUpperCase()] }}</span>
</mat-error>
</span>
<mat-error *ngIf="hasFormFieldErrors(keyResultForm, 'commitZone')">
<span>{{ getErrorMessage("SIZE_BETWEEN", "Commit Zone", 1, 400) }}</span>
</mat-error>
</div>

<div class="input-style gap-2">
Expand All @@ -121,11 +113,9 @@
formControlName="targetZone"
id="targetZone"
></textarea>
<span *ngIf="isTouchedOrDirty('targetZone')">
<mat-error *ngFor="let errorKey of getErrorKeysOfFormField('targetZone')">
<span>{{ errorMessages[errorKey.toUpperCase()] }}</span>
</mat-error>
</span>
<mat-error *ngIf="hasFormFieldErrors(keyResultForm, 'targetZone')">
<span>{{ getErrorMessage("SIZE_BETWEEN", "Target Zone", 1, 400) }}</span>
</mat-error>
</div>

<div class="input-style gap-2">
Expand All @@ -137,11 +127,9 @@
formControlName="stretchZone"
id="stretchZone"
></textarea>
<span *ngIf="isTouchedOrDirty('stretchZone')">
<mat-error *ngFor="let errorKey of getErrorKeysOfFormField('stretchZone')">
<span>{{ errorMessages[errorKey.toUpperCase()] }}</span>
</mat-error>
</span>
<mat-error *ngIf="hasFormFieldErrors(keyResultForm, 'stretchZone')">
<span>{{ getErrorMessage("SIZE_BETWEEN", "Stretch Zone", 1, 400) }}</span>
</mat-error>
</div>
</div>
</div>
Expand Down
17 changes: 7 additions & 10 deletions frontend/src/app/keyresult-type/keyresult-type.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -18,9 +18,11 @@ export class KeyresultTypeComponent implements OnInit {
@Output() formValidityEmitter = new EventEmitter<boolean>();
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) {
Expand Down Expand Up @@ -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);
}
}
2 changes: 1 addition & 1 deletion frontend/src/app/objective/objective.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<img
alt="The objectives state"
(click)="$event.stopPropagation()"
matTooltip="The objectives state is {{ objective.state.split('-')[0] | uppercase }}"
matTooltip="{{ getStateTooltip() + ' ' + formatObjectiveState(objective.state) }}"
matTooltipPosition="above"
[attr.data-testId]="'objective-state'"
class="icon col-1 ms-1 me-2"
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/app/objective/objective.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -42,6 +44,9 @@ describe('ObjectiveColumnComponent', () => {
MatIconModule,
MatTooltipModule,
ReactiveFormsModule,
TranslateTestingModule.withTranslations({
de: de,
}),
],
providers: [{ provide: OverviewService, useValue: overviewServiceMock }],
}).compileComponents();
Expand Down
Loading

0 comments on commit 58bd280

Please sign in to comment.