Skip to content

Commit 3dbac05

Browse files
Lias Kleisalkleisa
Lias Kleisa
authored andcommitted
Refactor frontend code
1 parent 42f01eb commit 3dbac05

File tree

7 files changed

+109
-74
lines changed

7 files changed

+109
-74
lines changed
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
<div *ngIf="!noAlignmentData" id="cy"></div>
1+
<div *ngIf="(alignmentDataCache?.alignmentObjectDtoList)!.length != 0" id="cy"></div>
22

3-
<div *ngIf="noAlignmentData" class="d-flex align-items-center flex-column pt-5 gap-5">
3+
<div
4+
*ngIf="(alignmentDataCache?.alignmentObjectDtoList)!.length == 0"
5+
class="d-flex align-items-center flex-column pt-5 gap-5"
6+
>
47
<p>Kein Alignment vorhanden</p>
58
<img src="assets/images/puzzle-p.svg" alt="Puzzle Logo" width="242" class="puzzle-logo" />
69
</div>

frontend/src/app/diagram/diagram.component.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('DiagramComponent', () => {
4444

4545
component.prepareDiagramData(alignmentLists);
4646
expect(component.generateNodes).toHaveBeenCalled();
47-
expect(component.noAlignmentData).toBeFalsy();
47+
expect(component.alignmentDataCache?.alignmentObjectDtoList.length).not.toEqual(0);
4848
});
4949

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

5858
component.prepareDiagramData(alignmentLists);
5959
expect(component.generateNodes).not.toHaveBeenCalled();
60-
expect(component.noAlignmentData).toBeTruthy();
6160
});
6261

6362
it('should call prepareDiagramData when Subject receives new data', () => {

frontend/src/app/diagram/diagram.component.ts

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core';
2-
import { map, Observable, Subject, zip } from 'rxjs';
2+
import { map, Observable, of, Subject, zip } from 'rxjs';
33
import { AlignmentLists } from '../shared/types/model/AlignmentLists';
44
import cytoscape from 'cytoscape';
55
import {
@@ -19,6 +19,8 @@ import { KeyResultOrdinal } from '../shared/types/model/KeyResultOrdinal';
1919
import { Router } from '@angular/router';
2020
import { AlignmentObject } from '../shared/types/model/AlignmentObject';
2121
import { AlignmentConnection } from '../shared/types/model/AlignmentConnection';
22+
import { Zone } from '../shared/types/enums/Zone';
23+
import { ObjectiveState } from '../shared/types/enums/ObjectiveState';
2224

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

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

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

7172
ngOnDestroy(): void {
7273
this.cleanUpDiagram();
74+
this.alignmentData.unsubscribe();
7375
}
7476

7577
generateDiagram(): void {
@@ -140,10 +142,7 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
140142
}
141143

142144
prepareDiagramData(alignmentData: AlignmentLists): void {
143-
if (alignmentData.alignmentObjectDtoList.length == 0) {
144-
this.noAlignmentData = true;
145-
} else {
146-
this.noAlignmentData = false;
145+
if (alignmentData.alignmentObjectDtoList.length != 0) {
147146
this.generateNodes(alignmentData);
148147
}
149148
}
@@ -153,24 +152,20 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
153152
let diagramElements: any[] = [];
154153
alignmentData.alignmentObjectDtoList.forEach((alignmentObject: AlignmentObject) => {
155154
if (alignmentObject.objectType == 'objective') {
156-
let observable: Observable<any> = new Observable((observer) => {
157-
let node = {
158-
data: {
159-
id: 'Ob' + alignmentObject.objectId,
160-
},
161-
style: {
162-
'background-image': this.generateObjectiveSVG(
163-
alignmentObject.objectTitle,
164-
alignmentObject.objectTeamName,
165-
alignmentObject.objectState!,
166-
),
167-
},
168-
};
169-
diagramElements.push(node);
170-
observer.next(node);
171-
observer.complete();
172-
});
173-
observableArray.push(observable);
155+
let node = {
156+
data: {
157+
id: 'Ob' + alignmentObject.objectId,
158+
},
159+
style: {
160+
'background-image': this.generateObjectiveSVG(
161+
alignmentObject.objectTitle,
162+
alignmentObject.objectTeamName,
163+
alignmentObject.objectState!,
164+
),
165+
},
166+
};
167+
diagramElements.push(node);
168+
observableArray.push(of(node));
174169
} else {
175170
let observable: Observable<void> = this.keyResultService.getFullKeyResult(alignmentObject.objectId).pipe(
176171
map((keyResult: KeyResult) => {
@@ -248,11 +243,11 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
248243

249244
generateObjectiveSVG(title: string, teamName: string, state: string): string {
250245
switch (state) {
251-
case 'ONGOING':
246+
case ObjectiveState.ONGOING:
252247
return generateObjectiveSVG(title, teamName, getOnGoingIcon);
253-
case 'SUCCESSFUL':
248+
case ObjectiveState.SUCCESSFUL:
254249
return generateObjectiveSVG(title, teamName, getSuccessfulIcon);
255-
case 'NOTSUCCESSFUL':
250+
case ObjectiveState.NOTSUCCESSFUL:
256251
return generateObjectiveSVG(title, teamName, getNotSuccessfulIcon);
257252
default:
258253
return generateObjectiveSVG(title, teamName, getDraftIcon);
@@ -261,13 +256,13 @@ export class DiagramComponent implements AfterViewInit, OnDestroy {
261256

262257
generateKeyResultSVG(title: string, teamName: string, state: string | undefined): string {
263258
switch (state) {
264-
case 'FAIL':
259+
case Zone.FAIL:
265260
return generateKeyResultSVG(title, teamName, '#BA3838', 'white');
266-
case 'COMMIT':
261+
case Zone.COMMIT:
267262
return generateKeyResultSVG(title, teamName, '#FFD600', 'black');
268-
case 'TARGET':
263+
case Zone.TARGET:
269264
return generateKeyResultSVG(title, teamName, '#1E8A29', 'black');
270-
case 'STRETCH':
265+
case Zone.STRETCH:
271266
return generateKeyResultSVG(title, teamName, '#1E5A96', 'white');
272267
default:
273268
return generateNeutralKeyResultSVG(title, teamName);

frontend/src/app/objective-detail/objective-detail.component.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,9 @@ export class ObjectiveDetailComponent {
6565
.subscribe((result) => {
6666
if (result?.openNew) {
6767
this.openAddKeyResultDialog();
68-
} else if (result == '' || result == undefined) {
6968
return;
70-
} else {
71-
this.refreshDataService.markDataRefresh();
7269
}
70+
this.refreshDataService.markDataRefresh();
7371
});
7472
}
7573

frontend/src/app/overview/overview.component.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
22

33
import { OverviewComponent } from './overview.component';
44
import { HttpClientTestingModule } from '@angular/common/http/testing';
5-
import { overViewEntity1 } from '../shared/testData';
5+
import { alignmentLists, overViewEntity1 } from '../shared/testData';
66
import { BehaviorSubject, of, Subject } from 'rxjs';
77
import { OverviewService } from '../shared/services/overview.service';
88
import { AppRoutingModule } from '../app-routing.module';
@@ -16,11 +16,16 @@ import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
1616
import { MatIconModule } from '@angular/material/icon';
1717
import { MatMenuModule } from '@angular/material/menu';
1818
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
19+
import { AlignmentService } from '../shared/services/alignment.service';
1920

2021
const overviewService = {
2122
getOverview: jest.fn(),
2223
};
2324

25+
const alignmentService = {
26+
getAlignmentByFilter: jest.fn(),
27+
};
28+
2429
const authGuardMock = () => {
2530
return Promise.resolve(true);
2631
};
@@ -53,6 +58,10 @@ describe('OverviewComponent', () => {
5358
provide: OverviewService,
5459
useValue: overviewService,
5560
},
61+
{
62+
provide: AlignmentService,
63+
useValue: alignmentService,
64+
},
5665
{
5766
provide: authGuard,
5867
useValue: authGuardMock,
@@ -132,6 +141,23 @@ describe('OverviewComponent', () => {
132141
expect(component.loadOverview).toHaveBeenLastCalledWith();
133142
});
134143

144+
it('should call overviewService on overview', async () => {
145+
jest.spyOn(overviewService, 'getOverview');
146+
component.isOverview = true;
147+
148+
component.loadOverview(3, [5, 6], '', null);
149+
expect(overviewService.getOverview).toHaveBeenCalled();
150+
});
151+
152+
it('should call alignmentService on diagram', async () => {
153+
jest.spyOn(alignmentService, 'getAlignmentByFilter').mockReturnValue(of(alignmentLists));
154+
component.isOverview = false;
155+
fixture.detectChanges();
156+
157+
component.loadOverview(3, [5, 6], '', null);
158+
expect(alignmentService.getAlignmentByFilter).toHaveBeenCalled();
159+
});
160+
135161
function markFiltersAsReady() {
136162
refreshDataServiceMock.quarterFilterReady.next(null);
137163
refreshDataServiceMock.teamFilterReady.next(null);

frontend/src/app/overview/overview.component.ts

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -69,45 +69,53 @@ export class OverviewComponent implements OnInit, OnDestroy {
6969
this.loadOverview(quarterId, teamIds, objectiveQueryString, reload);
7070
}
7171

72-
loadOverview(quarterId?: number, teamIds?: number[], objectiveQuery?: string, reload?: boolean | null) {
72+
loadOverview(quarterId?: number, teamIds?: number[], objectiveQuery?: string, reload?: boolean | null): void {
7373
if (this.isOverview) {
74-
this.overviewService
75-
.getOverview(quarterId, teamIds, objectiveQuery)
76-
.pipe(
77-
catchError(() => {
78-
this.loadOverview();
79-
return EMPTY;
80-
}),
81-
)
82-
.subscribe((dashboard) => {
83-
this.hasAdminAccess.next(dashboard.adminAccess);
84-
this.overviewEntities$.next(dashboard.overviews);
85-
});
74+
this.loadOverviewData(quarterId, teamIds, objectiveQuery);
8675
} else {
87-
this.alignmentService
88-
.getAlignmentByFilter(quarterId, teamIds, objectiveQuery)
89-
.pipe(
90-
catchError(() => {
91-
this.loadOverview();
92-
return EMPTY;
93-
}),
94-
)
95-
.subscribe((alignmentLists: AlignmentLists) => {
96-
if (reload != null) {
97-
let alignmentObjectReload: AlignmentObject = {
98-
objectId: 0,
99-
objectTitle: 'reload',
100-
objectType: reload.toString(),
101-
objectTeamName: '',
102-
objectState: null,
103-
};
104-
alignmentLists.alignmentObjectDtoList.push(alignmentObjectReload);
105-
}
106-
this.alignmentLists$.next(alignmentLists);
107-
});
76+
this.loadAlignmentData(quarterId, teamIds, objectiveQuery, reload);
10877
}
10978
}
11079

80+
loadOverviewData(quarterId?: number, teamIds?: number[], objectiveQuery?: string): void {
81+
this.overviewService
82+
.getOverview(quarterId, teamIds, objectiveQuery)
83+
.pipe(
84+
catchError(() => {
85+
this.loadOverview();
86+
return EMPTY;
87+
}),
88+
)
89+
.subscribe((dashboard) => {
90+
this.hasAdminAccess.next(dashboard.adminAccess);
91+
this.overviewEntities$.next(dashboard.overviews);
92+
});
93+
}
94+
95+
loadAlignmentData(quarterId?: number, teamIds?: number[], objectiveQuery?: string, reload?: boolean | null): void {
96+
this.alignmentService
97+
.getAlignmentByFilter(quarterId, teamIds, objectiveQuery)
98+
.pipe(
99+
catchError(() => {
100+
this.loadOverview();
101+
return EMPTY;
102+
}),
103+
)
104+
.subscribe((alignmentLists: AlignmentLists) => {
105+
if (reload != null) {
106+
let alignmentObjectReload: AlignmentObject = {
107+
objectId: 0,
108+
objectTitle: 'reload',
109+
objectType: reload.toString(),
110+
objectTeamName: '',
111+
objectState: null,
112+
};
113+
alignmentLists.alignmentObjectDtoList.push(alignmentObjectReload);
114+
}
115+
this.alignmentLists$.next(alignmentLists);
116+
});
117+
}
118+
111119
ngOnDestroy(): void {
112120
this.destroyed$.next(true);
113121
this.destroyed$.complete();
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export enum ObjectiveState {
2+
DRAFT = 'DRAFT',
3+
ONGOING = 'ONGOING',
4+
SUCCESSFUL = 'SUCCESSFUL',
5+
NOTSUCCESSFUL = 'NOTSUCCESSFUL',
6+
}

0 commit comments

Comments
 (0)