diff --git a/backend/src/main/java/ch/puzzle/okr/service/business/AlignmentBusinessService.java b/backend/src/main/java/ch/puzzle/okr/service/business/AlignmentBusinessService.java index ef9f954fbc..2e4e3b1a69 100644 --- a/backend/src/main/java/ch/puzzle/okr/service/business/AlignmentBusinessService.java +++ b/backend/src/main/java/ch/puzzle/okr/service/business/AlignmentBusinessService.java @@ -99,9 +99,10 @@ public boolean isAlignmentTypeChange(Alignment alignment, Alignment savedAlignme || (alignment instanceof KeyResultAlignment && savedAlignment instanceof ObjectiveAlignment); } - public void updateKeyResultIdOnIdChange(Long oldId, KeyResult keyResult) { - List alignments = alignmentPersistenceService.findByKeyResultAlignmentId(oldId); - alignments.forEach(alignment -> { + public void updateKeyResultIdOnIdChange(Long oldKeyResultId, KeyResult keyResult) { + List keyResultAlignmentList = alignmentPersistenceService + .findByKeyResultAlignmentId(oldKeyResultId); + keyResultAlignmentList.forEach(alignment -> { alignment.setAlignmentTarget(keyResult); alignmentValidationService.validateOnUpdate(alignment.getId(), alignment); alignmentPersistenceService.save(alignment); @@ -114,16 +115,18 @@ public void deleteAlignmentByObjectiveId(Long objectiveId) { alignmentValidationService.validateOnDelete(alignment.getId()); alignmentPersistenceService.deleteById(alignment.getId()); } - List alignmentList = alignmentPersistenceService.findByObjectiveAlignmentId(objectiveId); - alignmentList.forEach(objectiveAlignment -> { + List objectiveAlignmentList = alignmentPersistenceService + .findByObjectiveAlignmentId(objectiveId); + objectiveAlignmentList.forEach(objectiveAlignment -> { alignmentValidationService.validateOnDelete(objectiveAlignment.getId()); alignmentPersistenceService.deleteById(objectiveAlignment.getId()); }); } public void deleteAlignmentByKeyResultId(Long keyResultId) { - List alignmentList = alignmentPersistenceService.findByKeyResultAlignmentId(keyResultId); - alignmentList.forEach(keyResultAlignment -> { + List keyResultAlignmentList = alignmentPersistenceService + .findByKeyResultAlignmentId(keyResultId); + keyResultAlignmentList.forEach(keyResultAlignment -> { alignmentValidationService.validateOnDelete(keyResultAlignment.getId()); alignmentPersistenceService.deleteById(keyResultAlignment.getId()); }); diff --git a/backend/src/main/java/ch/puzzle/okr/service/business/ObjectiveBusinessService.java b/backend/src/main/java/ch/puzzle/okr/service/business/ObjectiveBusinessService.java index 2fc9c40a54..a97c43bcd1 100644 --- a/backend/src/main/java/ch/puzzle/okr/service/business/ObjectiveBusinessService.java +++ b/backend/src/main/java/ch/puzzle/okr/service/business/ObjectiveBusinessService.java @@ -65,23 +65,23 @@ public List getAlignmentPossibilities(Long quarterId) { .filter(objective -> objective.getTeam().equals(team)).toList().stream() .sorted(Comparator.comparing(Objective::getTitle)).toList(); - List alignmentObjectDtos = new ArrayList<>(); + List alignmentObjectDtoList = new ArrayList<>(); filteredObjectiveList.forEach(objective -> { AlignmentObjectDto objectiveDto = new AlignmentObjectDto(objective.getId(), "O - " + objective.getTitle(), "objective"); - alignmentObjectDtos.add(objectiveDto); + alignmentObjectDtoList.add(objectiveDto); - List keyResults = keyResultBusinessService.getAllKeyResultsByObjective(objective.getId()) + List keyResultList = keyResultBusinessService.getAllKeyResultsByObjective(objective.getId()) .stream().sorted(Comparator.comparing(KeyResult::getTitle)).toList(); - keyResults.forEach(keyResult -> { + keyResultList.forEach(keyResult -> { AlignmentObjectDto keyResultDto = new AlignmentObjectDto(keyResult.getId(), "KR - " + keyResult.getTitle(), "keyResult"); - alignmentObjectDtos.add(keyResultDto); + alignmentObjectDtoList.add(keyResultDto); }); }); - AlignmentDto alignmentDto = new AlignmentDto(team.getId(), team.getName(), alignmentObjectDtos); + AlignmentDto alignmentDto = new AlignmentDto(team.getId(), team.getName(), alignmentObjectDtoList); alignmentDtoList.add(alignmentDto); }); diff --git a/backend/src/main/java/ch/puzzle/okr/service/validation/AlignmentValidationService.java b/backend/src/main/java/ch/puzzle/okr/service/validation/AlignmentValidationService.java index 8a656cd679..40bbba8ee5 100644 --- a/backend/src/main/java/ch/puzzle/okr/service/validation/AlignmentValidationService.java +++ b/backend/src/main/java/ch/puzzle/okr/service/validation/AlignmentValidationService.java @@ -33,10 +33,10 @@ public AlignmentValidationService(AlignmentPersistenceService alignmentPersisten public void validateOnCreate(Alignment model) { throwExceptionWhenModelIsNull(model); throwExceptionWhenIdIsNotNull(model.getId()); - throwExceptionWhenAlignedObjectIsNull(model); + throwExceptionWhenAlignmentObjectIsNull(model); throwExceptionWhenAlignedIdIsSameAsTargetId(model); throwExceptionWhenAlignmentIsInSameTeam(model); - throwExceptionWhenAlignedObjectiveAlreadyExists(model); + throwExceptionWhenAlignmentWithAlignedObjectiveAlreadyExists(model); validate(model); } @@ -44,13 +44,13 @@ public void validateOnCreate(Alignment model) { public void validateOnUpdate(Long id, Alignment model) { throwExceptionWhenModelIsNull(model); throwExceptionWhenIdIsNull(model.getId()); - throwExceptionWhenAlignedObjectIsNull(model); + throwExceptionWhenAlignmentObjectIsNull(model); throwExceptionWhenAlignedIdIsSameAsTargetId(model); throwExceptionWhenAlignmentIsInSameTeam(model); validate(model); } - private void throwExceptionWhenAlignedObjectIsNull(Alignment model) { + private void throwExceptionWhenAlignmentObjectIsNull(Alignment model) { if (model.getAlignedObjective() == null) { throw new OkrResponseStatusException(HttpStatus.BAD_REQUEST, ErrorKey.ATTRIBUTE_NULL, List.of("alignedObjectiveId")); @@ -68,19 +68,20 @@ private void throwExceptionWhenAlignedObjectIsNull(Alignment model) { } private void throwExceptionWhenAlignmentIsInSameTeam(Alignment model) { - Team alignedTeam = teamPersistenceService.findById(model.getAlignedObjective().getTeam().getId()); - Team targetTeam = null; + Team alignedObjectiveTeam = teamPersistenceService.findById(model.getAlignedObjective().getTeam().getId()); + Team targetObjectTeam = null; if (model instanceof ObjectiveAlignment objectiveAlignment) { - targetTeam = teamPersistenceService.findById(objectiveAlignment.getAlignmentTarget().getTeam().getId()); + targetObjectTeam = teamPersistenceService + .findById(objectiveAlignment.getAlignmentTarget().getTeam().getId()); } else if (model instanceof KeyResultAlignment keyResultAlignment) { - targetTeam = teamPersistenceService + targetObjectTeam = teamPersistenceService .findById(keyResultAlignment.getAlignmentTarget().getObjective().getTeam().getId()); } - if (alignedTeam.equals(targetTeam)) { + if (alignedObjectiveTeam.equals(targetObjectTeam)) { throw new OkrResponseStatusException(HttpStatus.BAD_REQUEST, ErrorKey.NOT_LINK_IN_SAME_TEAM, - List.of("teamId", targetTeam.getId())); + List.of("teamId", targetObjectTeam.getId())); } } @@ -94,7 +95,7 @@ private void throwExceptionWhenAlignedIdIsSameAsTargetId(Alignment model) { } } - private void throwExceptionWhenAlignedObjectiveAlreadyExists(Alignment model) { + private void throwExceptionWhenAlignmentWithAlignedObjectiveAlreadyExists(Alignment model) { if (this.alignmentPersistenceService.findByAlignedObjectiveId(model.getAlignedObjective().getId()) != null) { throw new OkrResponseStatusException(HttpStatus.BAD_REQUEST, ErrorKey.ALIGNMENT_ALREADY_EXISTS, List.of("alignedObjectiveId", model.getAlignedObjective().getId())); 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 a9a41bbc52..e88271b068 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 @@ -70,22 +70,22 @@
- @for (group of filteredOptions$ | async; track group) { + @for (group of filteredAlignmentOptions$ | async; track group) { @for (alignmentObject of group.alignmentObjectDtos; track alignmentObject) { {{ alignmentObject.objectTitle }} 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 87677017e6..4b8e150f8b 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 @@ -509,7 +509,7 @@ describe('ObjectiveDialogComponent', () => { }); expect(alignmentPossibilities).toStrictEqual([alignmentPossibility1, alignmentPossibility2]); - expect(component.filteredOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); expect(component.objectiveForm.getRawValue().alignment).toEqual(null); }); @@ -522,15 +522,15 @@ describe('ObjectiveDialogComponent', () => { }); expect(alignmentPossibilities).toStrictEqual([alignmentPossibility2]); - expect(component.filteredOptions$.getValue()).toEqual([alignmentPossibility2]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([alignmentPossibility2]); expect(component.objectiveForm.getRawValue().alignment).toEqual(null); }); it('should return team and objective with same text in alignment possibilities', async () => { - component.input.nativeElement.value = 'puzzle'; + component.alignmentInput.nativeElement.value = 'puzzle'; component.alignmentPossibilities$ = of([alignmentPossibility1, alignmentPossibility2]); component.filter(); - expect(component.filteredOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); }); it('should load existing objective alignment to objectiveForm', async () => { @@ -542,7 +542,7 @@ describe('ObjectiveDialogComponent', () => { }); expect(alignmentPossibilities).toStrictEqual([alignmentPossibility1, alignmentPossibility2]); - expect(component.filteredOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); expect(component.objectiveForm.getRawValue().alignment).toEqual(alignmentObject2); }); @@ -556,13 +556,13 @@ describe('ObjectiveDialogComponent', () => { }); expect(alignmentPossibilities).toStrictEqual([alignmentPossibility1, alignmentPossibility2]); - expect(component.filteredOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([alignmentPossibility1, alignmentPossibility2]); expect(component.objectiveForm.getRawValue().alignment).toEqual(alignmentObject3); }); it('should filter correct alignment possibilities', async () => { // Search for one title - component.input.nativeElement.value = 'palm'; + component.alignmentInput.nativeElement.value = 'palm'; component.alignmentPossibilities$ = of([alignmentPossibility1, alignmentPossibility2]); component.filter(); let modifiedAlignmentPossibility: AlignmentPossibility = { @@ -570,10 +570,10 @@ describe('ObjectiveDialogComponent', () => { teamName: 'Puzzle ITC', alignmentObjectDtos: [alignmentObject3], }; - expect(component.filteredOptions$.getValue()).toEqual([modifiedAlignmentPossibility]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([modifiedAlignmentPossibility]); // Search for team name - component.input.nativeElement.value = 'Puzzle IT'; + component.alignmentInput.nativeElement.value = 'Puzzle IT'; component.alignmentPossibilities$ = of([alignmentPossibility1, alignmentPossibility2]); component.filter(); modifiedAlignmentPossibility = { @@ -581,10 +581,10 @@ describe('ObjectiveDialogComponent', () => { teamName: 'Puzzle ITC', alignmentObjectDtos: [alignmentObject2, alignmentObject3], }; - expect(component.filteredOptions$.getValue()).toEqual([modifiedAlignmentPossibility]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([modifiedAlignmentPossibility]); // Search for two objects - component.input.nativeElement.value = 'buy'; + component.alignmentInput.nativeElement.value = 'buy'; component.alignmentPossibilities$ = of([alignmentPossibility1, alignmentPossibility2]); component.filter(); let modifiedAlignmentPossibilities = [ @@ -599,18 +599,18 @@ describe('ObjectiveDialogComponent', () => { alignmentObjectDtos: [alignmentObject1], }, ]; - expect(component.filteredOptions$.getValue()).toEqual(modifiedAlignmentPossibilities); + expect(component.filteredAlignmentOptions$.getValue()).toEqual(modifiedAlignmentPossibilities); // No match - component.input.nativeElement.value = 'findus'; + component.alignmentInput.nativeElement.value = 'findus'; component.alignmentPossibilities$ = of([alignmentPossibility1, alignmentPossibility2]); component.filter(); - expect(component.filteredOptions$.getValue()).toEqual([]); + expect(component.filteredAlignmentOptions$.getValue()).toEqual([]); }); it('should find correct alignment object', () => { // objective - let alignmentObject = component.findAlignmentObject( + let alignmentObject = component.findAlignmentPossibilityObject( [alignmentPossibility1, alignmentPossibility2], 1, 'objective', @@ -619,38 +619,46 @@ describe('ObjectiveDialogComponent', () => { expect(alignmentObject!.objectTitle).toEqual('We want to increase the income puzzle buy'); // keyResult - alignmentObject = component.findAlignmentObject([alignmentPossibility1, alignmentPossibility2], 1, 'keyResult'); + alignmentObject = component.findAlignmentPossibilityObject( + [alignmentPossibility1, alignmentPossibility2], + 1, + 'keyResult', + ); expect(alignmentObject!.objectId).toEqual(1); expect(alignmentObject!.objectTitle).toEqual('We buy 3 palms'); // no match - alignmentObject = component.findAlignmentObject([alignmentPossibility1, alignmentPossibility2], 133, 'keyResult'); + alignmentObject = component.findAlignmentPossibilityObject( + [alignmentPossibility1, alignmentPossibility2], + 133, + 'keyResult', + ); expect(alignmentObject).toEqual(null); }); it('should display kein alignment vorhanden when no alignment possibility', () => { - component.filteredOptions$.next([alignmentPossibility1, alignmentPossibility2]); + component.filteredAlignmentOptions$.next([alignmentPossibility1, alignmentPossibility2]); fixture.detectChanges(); - expect(component.input.nativeElement.getAttribute('placeholder')).toEqual('Bezug wählen'); + expect(component.alignmentInput.nativeElement.getAttribute('placeholder')).toEqual('Bezug wählen'); - component.filteredOptions$.next([]); + component.filteredAlignmentOptions$.next([]); fixture.detectChanges(); - expect(component.input.nativeElement.getAttribute('placeholder')).toEqual('Kein Alignment vorhanden'); + expect(component.alignmentInput.nativeElement.getAttribute('placeholder')).toEqual('Kein Alignment vorhanden'); }); it('should update alignments on quarter change', () => { objectiveService.getAlignmentPossibilities.mockReturnValue(of([alignmentPossibility1, alignmentPossibility2])); component.updateAlignments(); - expect(component.input.nativeElement.value).toEqual(''); + expect(component.alignmentInput.nativeElement.value).toEqual(''); expect(component.objectiveForm.getRawValue().alignment).toEqual(null); expect(objectiveService.getAlignmentPossibilities).toHaveBeenCalled(); }); it('should return correct displayedValue', () => { - component.input.nativeElement.value = 'O - Objective 1'; + component.alignmentInput.nativeElement.value = 'O - Objective 1'; expect(component.displayedValue).toEqual('O - Objective 1'); - component.input = new ElementRef(document.createElement('input')); + component.alignmentInput = new ElementRef(document.createElement('input')); expect(component.displayedValue).toEqual(''); }); }); 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 767716d530..7a54524ce3 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 @@ -25,8 +25,7 @@ import { AlignmentPossibilityObject } from '../../types/model/AlignmentPossibili changeDetection: ChangeDetectionStrategy.OnPush, }) export class ObjectiveFormComponent implements OnInit { - @ViewChild('input') input!: ElementRef; - filteredOptions$: BehaviorSubject = new BehaviorSubject([]); + @ViewChild('alignmentInput') alignmentInput!: ElementRef; objectiveForm = new FormGroup({ title: new FormControl('', [Validators.required, Validators.minLength(2), Validators.maxLength(250)]), @@ -40,6 +39,7 @@ export class ObjectiveFormComponent implements OnInit { quarters: Quarter[] = []; teams$: Observable = of([]); alignmentPossibilities$: Observable = of([]); + filteredAlignmentOptions$: BehaviorSubject = new BehaviorSubject([]); currentTeam$: BehaviorSubject = new BehaviorSubject(null); state: string | null = null; version!: number; @@ -69,9 +69,9 @@ export class ObjectiveFormComponent implements OnInit { const value = this.objectiveForm.getRawValue(); const state = this.data.objective.objectiveId == null ? submitType : this.state; - let alignmentEntity: AlignmentPossibilityObject | null = value.alignment; - let alignment: string | null = alignmentEntity - ? (alignmentEntity.objectType == 'objective' ? 'O' : 'K') + alignmentEntity.objectId + let alignment: AlignmentPossibilityObject | null = value.alignment; + let alignmentEntity: string | null = alignment + ? (alignment.objectType == 'objective' ? 'O' : 'K') + alignment.objectId : null; let objectiveDTO: Objective = { @@ -82,7 +82,7 @@ export class ObjectiveFormComponent implements OnInit { title: value.title, teamId: value.team, state: state, - alignedEntityId: alignment, + alignedEntityId: alignmentEntity, } as unknown as Objective; const submitFunction = this.getSubmitFunction(objectiveDTO.id, objectiveDTO); @@ -253,24 +253,28 @@ export class ObjectiveFormComponent implements OnInit { } if (objective) { - let alignment: string | null = objective.alignedEntityId; - if (alignment) { - let alignmentType: string = alignment.charAt(0); - let alignmentId: number = parseInt(alignment.substring(1)); + let alignmentEntity: string | null = objective.alignedEntityId; + if (alignmentEntity) { + let alignmentType: string = alignmentEntity.charAt(0); + let alignmentId: number = parseInt(alignmentEntity.substring(1)); alignmentType = alignmentType == 'O' ? 'objective' : 'keyResult'; - let element: AlignmentPossibilityObject | null = this.findAlignmentObject(value, alignmentId, alignmentType); + let alignmentPossibilityObject: AlignmentPossibilityObject | null = this.findAlignmentPossibilityObject( + value, + alignmentId, + alignmentType, + ); this.objectiveForm.patchValue({ - alignment: element, + alignment: alignmentPossibilityObject, }); } } - this.filteredOptions$.next(value.slice()); + this.filteredAlignmentOptions$.next(value.slice()); this.alignmentPossibilities$ = of(value); }); } - findAlignmentObject( + findAlignmentPossibilityObject( alignmentPossibilities: AlignmentPossibility[], objectId: number, objectType: string, @@ -288,8 +292,8 @@ export class ObjectiveFormComponent implements OnInit { } updateAlignments() { - this.input.nativeElement.value = ''; - this.filteredOptions$.next([]); + this.alignmentInput.nativeElement.value = ''; + this.filteredAlignmentOptions$.next([]); this.objectiveForm.patchValue({ alignment: null, }); @@ -297,7 +301,7 @@ export class ObjectiveFormComponent implements OnInit { } filter() { - let filterValue: string = this.input.nativeElement.value.toLowerCase(); + let filterValue: string = this.alignmentInput.nativeElement.value.toLowerCase(); this.alignmentPossibilities$.subscribe((alignmentPossibilities: AlignmentPossibility[]) => { let matchingTeams: AlignmentPossibility[] = alignmentPossibilities.filter((possibility: AlignmentPossibility) => possibility.teamName.toLowerCase().includes(filterValue), @@ -319,7 +323,7 @@ export class ObjectiveFormComponent implements OnInit { matchingPossibilities = [...new Set(matchingPossibilities)]; - let optionList = matchingPossibilities.map((possibility: AlignmentPossibility) => ({ + let alignmentOptionList = matchingPossibilities.map((possibility: AlignmentPossibility) => ({ ...possibility, alignmentObjectDtos: possibility.alignmentObjectDtos.filter( (alignmentPossibilityObject: AlignmentPossibilityObject) => @@ -327,8 +331,9 @@ export class ObjectiveFormComponent implements OnInit { ), })); - let finalArray: AlignmentPossibility[] = filterValue == '' ? matchingTeams : matchingTeams.concat(optionList); - this.filteredOptions$.next([...new Set(finalArray)]); + let concatAlignmentOptionList: AlignmentPossibility[] = + filterValue == '' ? matchingTeams : matchingTeams.concat(alignmentOptionList); + this.filteredAlignmentOptions$.next([...new Set(concatAlignmentOptionList)]); }); } @@ -339,15 +344,15 @@ export class ObjectiveFormComponent implements OnInit { } get displayedValue(): string { - if (this.input) { - return this.input.nativeElement.value; + if (this.alignmentInput) { + return this.alignmentInput.nativeElement.value; } else { return ''; } } scrollLeft() { - this.input.nativeElement.scrollLeft = 0; + this.alignmentInput.nativeElement.scrollLeft = 0; } protected readonly getQuarterLabel = getQuarterLabel;