Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get current quarter from backend #1039

Merged
merged 30 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
77532df
add auto data-migration
kcinay055679 Oct 15, 2024
98f6295
jar is now debuggable
kcinay055679 Oct 15, 2024
55a164a
add jar debug dev tools only on profile
kcinay055679 Oct 15, 2024
3d430e8
change log levels
kcinay055679 Oct 15, 2024
8198471
try to fix autorestart of spring
kcinay055679 Oct 15, 2024
e9340ed
complete auto restart of container
kcinay055679 Oct 15, 2024
2a5a31b
rename intelij config and change log level of spring to debug in stag…
kcinay055679 Oct 17, 2024
319aa9e
rename folder
kcinay055679 Oct 18, 2024
8c6aa04
update docker compose file
kcinay055679 Oct 18, 2024
dcff765
use external profile to disable formatter
kcinay055679 Oct 18, 2024
7f637c3
clean up
kcinay055679 Oct 18, 2024
858f3ed
add jar debug dev tools only on profile
kcinay055679 Oct 15, 2024
90b8e43
add api endpoint
kcinay055679 Oct 15, 2024
d42387e
use api to get current quarter
kcinay055679 Oct 17, 2024
d876f80
convert quarter to a class instead of an interface
kcinay055679 Oct 17, 2024
cb64b0b
use class syntax
kcinay055679 Oct 17, 2024
1ec4c6e
update specs to use the class syntax for quarters
kcinay055679 Oct 17, 2024
eba27cf
mock new class function in test
kcinay055679 Oct 17, 2024
9419584
add integratin test for current quarter endpoint
kcinay055679 Oct 17, 2024
1bc70e9
fix default quarter for new objective selection
kcinay055679 Oct 21, 2024
f9fe326
use v2 for quarter url and update tests accoridingly
kcinay055679 Oct 21, 2024
c3d3b37
change merhod to fakeAsync
Miguel7373 Oct 21, 2024
8ae8de2
try to override provider mid test
Miguel7373 Oct 22, 2024
a4f83a1
Dispatch change instead of input event in onSubmit create test and ge…
RandomTannenbaum Oct 22, 2024
85c499e
Remove duplicate profile in pom
RandomTannenbaum Oct 22, 2024
7a3a4b9
Update swagger annotations of get current quarter and fix usage of wr…
RandomTannenbaum Oct 23, 2024
4c5e7a4
Remove unused import in common.ts
RandomTannenbaum Oct 23, 2024
c433392
add dependency for hot reload in again
Miguel7373 Oct 28, 2024
429d8d9
[FM] Automated formating frontend
actions-user Oct 28, 2024
2dbbd62
readd local debug run config
kcinay055679 Nov 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import java.util.List;

@RestController
@RequestMapping("api/v1/quarters")
@RequestMapping("api/v2/quarters")
public class QuarterController {

private final QuarterBusinessService quarterBusinessService;
Expand All @@ -28,9 +28,17 @@ public QuarterController(QuarterBusinessService quarterBusinessService) {

@Operation(summary = "Get quarters", description = "Get a List of quarters depending on current date")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Returned a List of quarters", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = TeamDto.class)) }) })
@Content(mediaType = "application/json", schema = @Schema(implementation = Quarter.class)) }) })
@GetMapping("")
public ResponseEntity<List<Quarter>> getCurrentQuarters() {
return ResponseEntity.status(HttpStatus.OK).body(this.quarterBusinessService.getQuarters());
}

@Operation(summary = "Get current quarter", description = "Get the current quarter depending on current date")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Returned the current quarter", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = Quarter.class)) }) })
@GetMapping("/current")
public ResponseEntity<Quarter> getCurrentQuarter() {
return ResponseEntity.status(HttpStatus.OK).body(this.quarterBusinessService.getCurrentQuarter());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.BDDMockito;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
Expand Down Expand Up @@ -48,7 +49,7 @@ class QuarterControllerIT {
void shouldGetAllQuarters() throws Exception {
BDDMockito.given(quarterBusinessService.getQuarters()).willReturn(quaterList);

mvc.perform(get("/api/v1/quarters").contentType(MediaType.APPLICATION_JSON))
mvc.perform(get("/api/v2/quarters").contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isOk()).andExpect(jsonPath("$", Matchers.hasSize(3)))
.andExpect(jsonPath("$[0].id", Is.is(1))).andExpect(jsonPath("$[0].label", Is.is("GJ 22/23-Q2")))
.andExpect(jsonPath("$[0].startDate", Is.is(LocalDate.of(2022, 9, 1).toString())))
Expand All @@ -64,7 +65,14 @@ void shouldGetAllQuarters() throws Exception {
void shouldGetAllTeamsIfNoTeamsExists() throws Exception {
BDDMockito.given(quarterBusinessService.getQuarters()).willReturn(Collections.emptyList());

mvc.perform(get("/api/v1/quarters").contentType(MediaType.APPLICATION_JSON))
mvc.perform(get("/api/v2/quarters").contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isOk()).andExpect(jsonPath("$", Matchers.hasSize(0)));
}
}

@Test
void shouldCallCurrentQuarterAfterRequest() throws Exception {
mvc.perform(get("/api/v2/quarters/current").contentType(MediaType.APPLICATION_JSON));

BDDMockito.verify(quarterBusinessService, Mockito.times(1)).getCurrentQuarter();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { KeyResultMetric } from '../../shared/types/model/KeyResultMetric';
import { KeyResultOrdinal } from '../../shared/types/model/KeyResultOrdinal';
import { TranslateTestingModule } from 'ngx-translate-testing';
import * as de from '../../../assets/i18n/de.json';
import { Quarter } from '../../shared/types/model/Quarter';

describe('KeyResultFormComponent', () => {
let component: KeyResultFormComponent;
Expand Down Expand Up @@ -70,7 +71,7 @@ describe('KeyResultFormComponent', () => {
const keyResultObjective: KeyResultObjective = {
id: 2,
state: State.ONGOING,
quarter: { id: 1, label: 'GJ 22/23-Q2', endDate: new Date(), startDate: new Date() },
quarter: new Quarter(1, 'GJ 22/23-Q2', new Date(), new Date()),
};

const keyResultFormGroup = new FormGroup({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { UserService } from '../../services/user.service';
import { KeyResultFormComponent } from '../key-result-form/key-result-form.component';
import { Quarter } from '../../shared/types/model/Quarter';

describe('KeyresultDialogComponent', () => {
let component: KeyresultDialogComponent;
Expand Down Expand Up @@ -55,7 +56,7 @@ describe('KeyresultDialogComponent', () => {
let keyResultObjective: KeyResultObjective = {
id: 2,
state: State.ONGOING,
quarter: { id: 1, label: 'GJ 22/23-Q2', endDate: new Date(), startDate: new Date() },
quarter: new Quarter(1, 'GJ 22/23-Q2', new Date(), new Date()),
};

let fullKeyResultMetric = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<mat-form-field appearance="outline" class="bg-white header-form-field quarter-filter" subscriptSizing="dynamic">
<mat-select
[(ngModel)]="quarterId"
[(ngModel)]="currentQuarterId"
(ngModelChange)="changeDisplayedQuarter()"
ngDefaultControl
[attr.data-testId]="'quarterFilter'"
>
<mat-option *ngFor="let quarter of quarters | async; let i = index" [value]="quarter.id">
{{ getQuarterLabel(quarter, i) }}
<mat-option *ngFor="let quarter of quarters | async" [value]="quarter.id">
{{ quarter.fullLabel() }}
</mat-option>
</mat-select>
</mat-form-field>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { QuarterFilterComponent } from './quarter-filter.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { OverviewService } from '../../services/overview.service';
import { quarter } from '../../shared/testData';
import { Observable, of } from 'rxjs';
import { Quarter } from '../../shared/types/model/Quarter';
import { QuarterService } from '../../services/quarter.service';
Expand All @@ -21,16 +20,19 @@ const overviewService = {
};

const quarters = [
{ id: 999, label: 'Backlog', startDate: null, endDate: null },
{ ...quarter, id: 2 },
{ ...quarter, id: 5 },
{ ...quarter, id: 7 },
new Quarter(999, 'Backlog', null, null),
new Quarter(2, '23.02.2025', new Date(), new Date()),
new Quarter(5, '23.02.2025', new Date(), new Date()),
new Quarter(7, '23.02.2025', new Date(), new Date()),
];

const quarterService = {
getAllQuarters(): Observable<Quarter[]> {
return of(quarters);
},
getCurrentQuarter(): Observable<Quarter> {
return of(quarters[2]);
},
};

describe('QuarterFilterComponent', () => {
Expand Down Expand Up @@ -68,13 +70,14 @@ describe('QuarterFilterComponent', () => {

it('should set correct default quarter if no route param is defined', async () => {
jest.spyOn(component, 'changeDisplayedQuarter');
jest.spyOn(quarters[2] as any, 'isCurrent').mockReturnValue(true);
const quarterSelect = await loader.getHarness(MatSelectHarness);
expect(quarterSelect).toBeTruthy();
component.ngOnInit();
fixture.detectChanges();
expect(component.quarterId).toBe(quarters[2].id);
expect(component.currentQuarterId).toBe(quarters[2].id);
expect(await quarterSelect.getValueText()).toBe(quarters[2].label + ' Aktuell');
expect(component.changeDisplayedQuarter).toHaveBeenCalledTimes(0);
expect(component.changeDisplayedQuarter).toHaveBeenCalledTimes(1);
});

it('should set correct value in form according to route param', async () => {
Expand All @@ -89,7 +92,7 @@ describe('QuarterFilterComponent', () => {
component.ngOnInit();
fixture.detectChanges();

expect(component.quarterId).toBe(quarters[3].id);
expect(component.currentQuarterId).toBe(quarters[3].id);
expect(await quarterSelect.getValueText()).toBe(quarters[3].label);
expect(component.changeDisplayedQuarter).toHaveBeenCalledTimes(1);
});
Expand All @@ -106,7 +109,7 @@ describe('QuarterFilterComponent', () => {
routerHarness.detectChanges();
component.ngOnInit();
fixture.detectChanges();
expect(component.quarterId).toBe(quarters[2].id);
expect(component.currentQuarterId).toBe(quarters[2].id);
expect(await quarterSelect.getValueText()).toBe(quarters[2].label + ' Aktuell');
expect(component.changeDisplayedQuarter).toHaveBeenCalledTimes(1);
expect(router.url).toBe('/?quarter=' + quarters[2].id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChangeDetectionStrategy, Component, EventEmitter, OnInit, Output } from '@angular/core';
import { QuarterService } from '../../services/quarter.service';
import { Quarter } from '../../shared/types/model/Quarter';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, forkJoin } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { getQuarterLabel, getValueFromQuery } from '../../shared/common';
import { RefreshDataService } from '../../services/refresh-data.service';
import { getValueFromQuery } from '../../shared/common';

@Component({
selector: 'app-quarter-filter',
Expand All @@ -14,7 +14,7 @@ import { RefreshDataService } from '../../services/refresh-data.service';
export class QuarterFilterComponent implements OnInit {
quarters: BehaviorSubject<Quarter[]> = new BehaviorSubject<Quarter[]>([]);
@Output() quarterLabel$ = new EventEmitter<string>();
quarterId: number = -1;
currentQuarterId: number = -1;

constructor(
private quarterService: QuarterService,
Expand All @@ -24,35 +24,35 @@ export class QuarterFilterComponent implements OnInit {
) {}

ngOnInit() {
this.quarterService.getAllQuarters().subscribe((quarters) => {
const allQuarters$ = this.quarterService.getAllQuarters();
const currentQuarter$ = this.quarterService.getCurrentQuarter();
forkJoin([allQuarters$, currentQuarter$]).subscribe(([quarters, currentQuarter]) => {
this.quarters.next(quarters);
const quarterQuery = this.route.snapshot.queryParams['quarter'];
const quarterId: number = getValueFromQuery(quarterQuery)[0];
if (quarters.map((quarter) => quarter.id).includes(quarterId)) {
this.quarterId = quarterId;
this.currentQuarterId = quarterId;
this.changeDisplayedQuarter();
} else {
this.quarterId = quarters[2].id;
if (quarterQuery !== undefined) {
this.changeDisplayedQuarter();
} else {
this.currentQuarterId = currentQuarter.id;
this.changeDisplayedQuarter();

if (quarterQuery === undefined) {
this.refreshDataService.quarterFilterReady.next();
}
}
const quarterLabel = quarters.find((e) => e.id == this.quarterId)?.label || '';
const quarterLabel = quarters.find((e) => e.id == this.currentQuarterId)?.label || '';
this.quarterLabel$.next(quarterLabel);
});
}

changeDisplayedQuarter() {
const id = this.quarterId;
const id = this.currentQuarterId;
const quarterLabel = this.quarters.getValue().find((e) => e.id == id)?.label || '';
this.quarterLabel$.next(quarterLabel);

this.router
.navigate([], { queryParams: { quarter: id } })
.then(() => this.refreshDataService.quarterFilterReady.next());
}

protected readonly getQuarterLabel = getQuarterLabel;
}
14 changes: 12 additions & 2 deletions frontend/src/app/services/quarter.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Quarter } from '../shared/types/model/Quarter';
import { Observable } from 'rxjs';
import { map, Observable } from 'rxjs';

@Injectable({
providedIn: 'root',
Expand All @@ -10,6 +10,16 @@ export class QuarterService {
constructor(private http: HttpClient) {}

getAllQuarters(): Observable<Quarter[]> {
return this.http.get<Quarter[]>('/api/v1/quarters');
return this.http
.get<Quarter[]>('/api/v2/quarters')
.pipe(
map((quarters) =>
quarters.map((quarter) => new Quarter(quarter.id, quarter.label, quarter.startDate, quarter.endDate)),
),
);
}

getCurrentQuarter(): Observable<Quarter> {
return this.http.get<Quarter>('/api/v2/quarters/current');
}
}
4 changes: 0 additions & 4 deletions frontend/src/app/shared/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ export function formInputCheck(form: FormGroup, propertyName: string) {
}
}

export function getQuarterLabel(quarter: any, index: number): string {
return index == 2 ? quarter.label + ' Aktuell' : quarter.label;
}

export function isMobileDevice() {
return window.navigator.userAgent.toLowerCase().includes('mobile');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
>
<ng-container *ngFor="let quarter of quarters$ | async; let i = index">
<option *ngIf="allowedOption(quarter)" [value]="quarter.id">
{{ getQuarterLabel(quarter, i) }}
{{ quarter.fullLabel() }}
</option>
</ng-container>
</select>
Expand Down
Loading
Loading