Skip to content

Commit

Permalink
Refactor frontend code
Browse files Browse the repository at this point in the history
  • Loading branch information
Lias Kleisa authored and lkleisa committed Jun 24, 2024
1 parent 42f01eb commit 3dbac05
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 74 deletions.
7 changes: 5 additions & 2 deletions frontend/src/app/diagram/diagram.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<div *ngIf="!noAlignmentData" id="cy"></div>
<div *ngIf="(alignmentDataCache?.alignmentObjectDtoList)!.length != 0" id="cy"></div>

<div *ngIf="noAlignmentData" class="d-flex align-items-center flex-column pt-5 gap-5">
<div
*ngIf="(alignmentDataCache?.alignmentObjectDtoList)!.length == 0"
class="d-flex align-items-center flex-column pt-5 gap-5"
>
<p>Kein Alignment vorhanden</p>
<img src="assets/images/puzzle-p.svg" alt="Puzzle Logo" width="242" class="puzzle-logo" />
</div>
3 changes: 1 addition & 2 deletions frontend/src/app/diagram/diagram.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('DiagramComponent', () => {

component.prepareDiagramData(alignmentLists);
expect(component.generateNodes).toHaveBeenCalled();
expect(component.noAlignmentData).toBeFalsy();
expect(component.alignmentDataCache?.alignmentObjectDtoList.length).not.toEqual(0);
});

it('should not call generateElements if alignmentData is empty', () => {
Expand All @@ -57,7 +57,6 @@ describe('DiagramComponent', () => {

component.prepareDiagramData(alignmentLists);
expect(component.generateNodes).not.toHaveBeenCalled();
expect(component.noAlignmentData).toBeTruthy();
});

it('should call prepareDiagramData when Subject receives new data', () => {
Expand Down
59 changes: 27 additions & 32 deletions frontend/src/app/diagram/diagram.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core';
import { map, Observable, Subject, zip } from 'rxjs';
import { map, Observable, of, Subject, zip } from 'rxjs';
import { AlignmentLists } from '../shared/types/model/AlignmentLists';
import cytoscape from 'cytoscape';
import {
Expand All @@ -19,6 +19,8 @@ import { KeyResultOrdinal } from '../shared/types/model/KeyResultOrdinal';
import { Router } from '@angular/router';
import { AlignmentObject } from '../shared/types/model/AlignmentObject';
import { AlignmentConnection } from '../shared/types/model/AlignmentConnection';
import { Zone } from '../shared/types/enums/Zone';
import { ObjectiveState } from '../shared/types/enums/ObjectiveState';

@Component({
selector: 'app-diagram',
Expand All @@ -29,7 +31,6 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
private alignmentData$: Subject<AlignmentLists> = new Subject<AlignmentLists>();
cy!: cytoscape.Core;
diagramData: any[] = [];
noAlignmentData: boolean = false;
alignmentDataCache: AlignmentLists | null = null;

constructor(
Expand All @@ -51,7 +52,7 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
let lastAlignmentItem: AlignmentObject =
alignmentData.alignmentObjectDtoList[alignmentData.alignmentObjectDtoList.length - 1];

let diagramReloadRequired: boolean =
const diagramReloadRequired: boolean =
lastAlignmentItem?.objectTitle === 'reload'
? lastAlignmentItem?.objectType === 'true'
: JSON.stringify(this.alignmentDataCache) !== JSON.stringify(alignmentData);
Expand All @@ -70,6 +71,7 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {

ngOnDestroy(): void {
this.cleanUpDiagram();
this.alignmentData.unsubscribe();
}

generateDiagram(): void {
Expand Down Expand Up @@ -140,10 +142,7 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
}

prepareDiagramData(alignmentData: AlignmentLists): void {
if (alignmentData.alignmentObjectDtoList.length == 0) {
this.noAlignmentData = true;
} else {
this.noAlignmentData = false;
if (alignmentData.alignmentObjectDtoList.length != 0) {
this.generateNodes(alignmentData);
}
}
Expand All @@ -153,24 +152,20 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
let diagramElements: any[] = [];
alignmentData.alignmentObjectDtoList.forEach((alignmentObject: AlignmentObject) => {
if (alignmentObject.objectType == 'objective') {
let observable: Observable<any> = new Observable((observer) => {
let node = {
data: {
id: 'Ob' + alignmentObject.objectId,
},
style: {
'background-image': this.generateObjectiveSVG(
alignmentObject.objectTitle,
alignmentObject.objectTeamName,
alignmentObject.objectState!,
),
},
};
diagramElements.push(node);
observer.next(node);
observer.complete();
});
observableArray.push(observable);
let node = {
data: {
id: 'Ob' + alignmentObject.objectId,
},
style: {
'background-image': this.generateObjectiveSVG(
alignmentObject.objectTitle,
alignmentObject.objectTeamName,
alignmentObject.objectState!,
),
},
};
diagramElements.push(node);
observableArray.push(of(node));
} else {
let observable: Observable<void> = this.keyResultService.getFullKeyResult(alignmentObject.objectId).pipe(
map((keyResult: KeyResult) => {
Expand Down Expand Up @@ -248,11 +243,11 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {

generateObjectiveSVG(title: string, teamName: string, state: string): string {
switch (state) {
case 'ONGOING':
case ObjectiveState.ONGOING:
return generateObjectiveSVG(title, teamName, getOnGoingIcon);
case 'SUCCESSFUL':
case ObjectiveState.SUCCESSFUL:
return generateObjectiveSVG(title, teamName, getSuccessfulIcon);
case 'NOTSUCCESSFUL':
case ObjectiveState.NOTSUCCESSFUL:
return generateObjectiveSVG(title, teamName, getNotSuccessfulIcon);
default:
return generateObjectiveSVG(title, teamName, getDraftIcon);
Expand All @@ -261,13 +256,13 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {

generateKeyResultSVG(title: string, teamName: string, state: string | undefined): string {
switch (state) {
case 'FAIL':
case Zone.FAIL:
return generateKeyResultSVG(title, teamName, '#BA3838', 'white');
case 'COMMIT':
case Zone.COMMIT:
return generateKeyResultSVG(title, teamName, '#FFD600', 'black');
case 'TARGET':
case Zone.TARGET:
return generateKeyResultSVG(title, teamName, '#1E8A29', 'black');
case 'STRETCH':
case Zone.STRETCH:
return generateKeyResultSVG(title, teamName, '#1E5A96', 'white');
default:
return generateNeutralKeyResultSVG(title, teamName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,9 @@ export class ObjectiveDetailComponent {
.subscribe((result) => {
if (result?.openNew) {
this.openAddKeyResultDialog();
} else if (result == '' || result == undefined) {
return;
} else {
this.refreshDataService.markDataRefresh();
}
this.refreshDataService.markDataRefresh();
});
}

Expand Down
28 changes: 27 additions & 1 deletion frontend/src/app/overview/overview.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';

import { OverviewComponent } from './overview.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { overViewEntity1 } from '../shared/testData';
import { alignmentLists, overViewEntity1 } from '../shared/testData';
import { BehaviorSubject, of, Subject } from 'rxjs';
import { OverviewService } from '../shared/services/overview.service';
import { AppRoutingModule } from '../app-routing.module';
Expand All @@ -16,11 +16,16 @@ import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AlignmentService } from '../shared/services/alignment.service';

const overviewService = {
getOverview: jest.fn(),
};

const alignmentService = {
getAlignmentByFilter: jest.fn(),
};

const authGuardMock = () => {
return Promise.resolve(true);
};
Expand Down Expand Up @@ -53,6 +58,10 @@ describe('OverviewComponent', () => {
provide: OverviewService,
useValue: overviewService,
},
{
provide: AlignmentService,
useValue: alignmentService,
},
{
provide: authGuard,
useValue: authGuardMock,
Expand Down Expand Up @@ -132,6 +141,23 @@ describe('OverviewComponent', () => {
expect(component.loadOverview).toHaveBeenLastCalledWith();
});

it('should call overviewService on overview', async () => {
jest.spyOn(overviewService, 'getOverview');
component.isOverview = true;

component.loadOverview(3, [5, 6], '', null);
expect(overviewService.getOverview).toHaveBeenCalled();
});

it('should call alignmentService on diagram', async () => {
jest.spyOn(alignmentService, 'getAlignmentByFilter').mockReturnValue(of(alignmentLists));
component.isOverview = false;
fixture.detectChanges();

component.loadOverview(3, [5, 6], '', null);
expect(alignmentService.getAlignmentByFilter).toHaveBeenCalled();
});

function markFiltersAsReady() {
refreshDataServiceMock.quarterFilterReady.next(null);
refreshDataServiceMock.teamFilterReady.next(null);
Expand Down
76 changes: 42 additions & 34 deletions frontend/src/app/overview/overview.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,45 +69,53 @@ export class OverviewComponent implements OnInit, OnDestroy {
this.loadOverview(quarterId, teamIds, objectiveQueryString, reload);
}

loadOverview(quarterId?: number, teamIds?: number[], objectiveQuery?: string, reload?: boolean | null) {
loadOverview(quarterId?: number, teamIds?: number[], objectiveQuery?: string, reload?: boolean | null): void {
if (this.isOverview) {
this.overviewService
.getOverview(quarterId, teamIds, objectiveQuery)
.pipe(
catchError(() => {
this.loadOverview();
return EMPTY;
}),
)
.subscribe((dashboard) => {
this.hasAdminAccess.next(dashboard.adminAccess);
this.overviewEntities$.next(dashboard.overviews);
});
this.loadOverviewData(quarterId, teamIds, objectiveQuery);
} else {
this.alignmentService
.getAlignmentByFilter(quarterId, teamIds, objectiveQuery)
.pipe(
catchError(() => {
this.loadOverview();
return EMPTY;
}),
)
.subscribe((alignmentLists: AlignmentLists) => {
if (reload != null) {
let alignmentObjectReload: AlignmentObject = {
objectId: 0,
objectTitle: 'reload',
objectType: reload.toString(),
objectTeamName: '',
objectState: null,
};
alignmentLists.alignmentObjectDtoList.push(alignmentObjectReload);
}
this.alignmentLists$.next(alignmentLists);
});
this.loadAlignmentData(quarterId, teamIds, objectiveQuery, reload);
}
}

loadOverviewData(quarterId?: number, teamIds?: number[], objectiveQuery?: string): void {
this.overviewService
.getOverview(quarterId, teamIds, objectiveQuery)
.pipe(
catchError(() => {
this.loadOverview();
return EMPTY;
}),
)
.subscribe((dashboard) => {
this.hasAdminAccess.next(dashboard.adminAccess);
this.overviewEntities$.next(dashboard.overviews);
});
}

loadAlignmentData(quarterId?: number, teamIds?: number[], objectiveQuery?: string, reload?: boolean | null): void {
this.alignmentService
.getAlignmentByFilter(quarterId, teamIds, objectiveQuery)
.pipe(
catchError(() => {
this.loadOverview();
return EMPTY;
}),
)
.subscribe((alignmentLists: AlignmentLists) => {
if (reload != null) {
let alignmentObjectReload: AlignmentObject = {
objectId: 0,
objectTitle: 'reload',
objectType: reload.toString(),
objectTeamName: '',
objectState: null,
};
alignmentLists.alignmentObjectDtoList.push(alignmentObjectReload);
}
this.alignmentLists$.next(alignmentLists);
});
}

ngOnDestroy(): void {
this.destroyed$.next(true);
this.destroyed$.complete();
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/app/shared/types/enums/ObjectiveState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum ObjectiveState {
DRAFT = 'DRAFT',
ONGOING = 'ONGOING',
SUCCESSFUL = 'SUCCESSFUL',
NOTSUCCESSFUL = 'NOTSUCCESSFUL',
}

0 comments on commit 3dbac05

Please sign in to comment.