From b698eaa09a1959097cb8859e1b2baa43018894a4 Mon Sep 17 00:00:00 2001 From: GODrums Date: Fri, 4 Oct 2024 23:01:08 +0200 Subject: [PATCH] Support for repository leaderboards --- server/application-server/openapi.yaml | 21 ++--- .../codereview/user/UserRepository.java | 4 +- .../codereview/user/UserService.java | 7 +- .../leaderboard/LeaderboardController.java | 5 +- .../leaderboard/LeaderboardService.java | 5 +- .../openapi/api/leaderboard.service.ts | 13 ++- .../api/leaderboard.serviceInterface.ts | 3 +- .../modules/openapi/model/pull-request.ts | 2 +- .../app/core/modules/openapi/model/user.ts | 4 +- webapp/src/app/home/home.component.html | 4 +- webapp/src/app/home/home.component.ts | 21 +++-- .../leaderboard/filter/filter.component.html | 15 +--- .../leaderboard/filter/filter.component.ts | 79 +---------------- .../repository/repository.component.html | 11 +++ .../filter/repository/repository.component.ts | 72 +++++++++++++++ .../filter/timeframe/timeframe.component.html | 11 +++ .../filter/timeframe/timeframe.component.ts | 87 +++++++++++++++++++ 17 files changed, 245 insertions(+), 119 deletions(-) create mode 100644 webapp/src/app/home/leaderboard/filter/repository/repository.component.html create mode 100644 webapp/src/app/home/leaderboard/filter/repository/repository.component.ts create mode 100644 webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html create mode 100644 webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts diff --git a/server/application-server/openapi.yaml b/server/application-server/openapi.yaml index 48453c67..f360ada8 100644 --- a/server/application-server/openapi.yaml +++ b/server/application-server/openapi.yaml @@ -107,6 +107,11 @@ paths: schema: type: string format: date + - name: repository + in: query + required: false + schema: + type: string responses: "200": description: OK @@ -254,9 +259,8 @@ components: type: string state: type: string - description: |- - State of the PullRequest. - Does not include the state of the merge. + description: "State of the PullRequest.\r\n Does not include the state of\ + \ the merge." enum: - CLOSED - OPEN @@ -422,15 +426,12 @@ components: description: Display name of the user. url: type: string - description: |- - Unique URL to the user's profile. - Not the website a user can set in their profile. + description: "Unique URL to the user's profile.\r\n Not the website a user\ + \ can set in their profile." avatarUrl: type: string - description: |- - URL to the user's avatar. - If unavailable, a fallback can be generated from the login, e.g. on Github: - https://github.com/{login}.png + description: "URL to the user's avatar.\r\n If unavailable, a fallback can\ + \ be generated from the login, e.g. on Github:\r\n https://github.com/{login}.png" type: type: string description: Type of the user. Used to distinguish between users and bots. diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserRepository.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserRepository.java index ba998f9d..d671a475 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserRepository.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserRepository.java @@ -46,6 +46,8 @@ SELECT new UserDTO(u.id, u.login, u.email, u.name, u.url) FROM User u JOIN FETCH u.reviews re WHERE re.createdAt BETWEEN :after AND :before + AND (:repository IS NULL OR re.pullRequest.repository.nameWithOwner = :repository) """) - List findAllInTimeframe(@Param("after") OffsetDateTime after, @Param("before") OffsetDateTime before); + List findAllInTimeframe(@Param("after") OffsetDateTime after, @Param("before") OffsetDateTime before, + @Param("repository") Optional repository); } diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserService.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserService.java index 1a5f3e9b..245baa36 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserService.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/codereview/user/UserService.java @@ -33,8 +33,9 @@ public List getAllUsers() { return userRepository.findAll().stream().toList(); } - public List getAllUsersInTimeframe(OffsetDateTime after, OffsetDateTime before) { - logger.info("Getting all users in timeframe between " + after + " and " + before); - return userRepository.findAllInTimeframe(after, before); + public List getAllUsersInTimeframe(OffsetDateTime after, OffsetDateTime before, Optional repository) { + logger.info("Getting all users in timeframe between " + after + " and " + before + " for repository: " + + repository.orElse("all")); + return userRepository.findAllInTimeframe(after, before, repository); } } diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardController.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardController.java index 12d7d922..5ced3e6a 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardController.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardController.java @@ -24,7 +24,8 @@ public LeaderboardController(LeaderboardService leaderboardService) { @GetMapping public ResponseEntity> getLeaderboard( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Optional after, - @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Optional before) { - return ResponseEntity.ok(leaderboardService.createLeaderboard(after, before)); + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Optional before, + @RequestParam Optional repository) { + return ResponseEntity.ok(leaderboardService.createLeaderboard(after, before, repository)); } } diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java index a031c407..4b7668b9 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java @@ -38,7 +38,8 @@ public LeaderboardService(UserService userService) { this.userService = userService; } - public List createLeaderboard(Optional after, Optional before) { + public List createLeaderboard(Optional after, Optional before, + Optional repository) { logger.info("Creating leaderboard dataset"); LocalDateTime afterCutOff = after.isPresent() ? after.get().atStartOfDay() @@ -46,7 +47,7 @@ public List createLeaderboard(Optional after, Optio Optional beforeCutOff = before.map(date -> date.plusDays(1).atStartOfDay()); List users = userService.getAllUsersInTimeframe(afterCutOff.atOffset(ZoneOffset.UTC), - beforeCutOff.map(b -> b.atOffset(ZoneOffset.UTC)).orElse(OffsetDateTime.now())); + beforeCutOff.map(b -> b.atOffset(ZoneOffset.UTC)).orElse(OffsetDateTime.now()), repository); logger.info("Found " + users.size() + " users for the leaderboard"); diff --git a/webapp/src/app/core/modules/openapi/api/leaderboard.service.ts b/webapp/src/app/core/modules/openapi/api/leaderboard.service.ts index 34a2c7cd..7cc7ccc9 100644 --- a/webapp/src/app/core/modules/openapi/api/leaderboard.service.ts +++ b/webapp/src/app/core/modules/openapi/api/leaderboard.service.ts @@ -98,13 +98,14 @@ export class LeaderboardService implements LeaderboardServiceInterface { /** * @param after * @param before + * @param repository * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public getLeaderboard(after?: string, before?: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; - public getLeaderboard(after?: string, before?: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>>; - public getLeaderboard(after?: string, before?: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>>; - public getLeaderboard(after?: string, before?: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { + public getLeaderboard(after?: string, before?: string, repository?: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public getLeaderboard(after?: string, before?: string, repository?: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>>; + public getLeaderboard(after?: string, before?: string, repository?: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>>; + public getLeaderboard(after?: string, before?: string, repository?: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { let localVarQueryParameters = new HttpParams({encoder: this.encoder}); if (after !== undefined && after !== null) { @@ -115,6 +116,10 @@ export class LeaderboardService implements LeaderboardServiceInterface { localVarQueryParameters = this.addToHttpParams(localVarQueryParameters, before, 'before'); } + if (repository !== undefined && repository !== null) { + localVarQueryParameters = this.addToHttpParams(localVarQueryParameters, + repository, 'repository'); + } let localVarHeaders = this.defaultHeaders; diff --git a/webapp/src/app/core/modules/openapi/api/leaderboard.serviceInterface.ts b/webapp/src/app/core/modules/openapi/api/leaderboard.serviceInterface.ts index 19a131c7..54aadd9a 100644 --- a/webapp/src/app/core/modules/openapi/api/leaderboard.serviceInterface.ts +++ b/webapp/src/app/core/modules/openapi/api/leaderboard.serviceInterface.ts @@ -29,7 +29,8 @@ export interface LeaderboardServiceInterface { * * @param after * @param before + * @param repository */ - getLeaderboard(after?: string, before?: string, extraHttpRequestParams?: any): Observable>; + getLeaderboard(after?: string, before?: string, repository?: string, extraHttpRequestParams?: any): Observable>; } diff --git a/webapp/src/app/core/modules/openapi/model/pull-request.ts b/webapp/src/app/core/modules/openapi/model/pull-request.ts index 98c19061..7676c134 100644 --- a/webapp/src/app/core/modules/openapi/model/pull-request.ts +++ b/webapp/src/app/core/modules/openapi/model/pull-request.ts @@ -24,7 +24,7 @@ export interface PullRequest { title: string; url: string; /** - * State of the PullRequest. Does not include the state of the merge. + * State of the PullRequest. Does not include the state of the merge. */ state: PullRequest.StateEnum; additions?: number; diff --git a/webapp/src/app/core/modules/openapi/model/user.ts b/webapp/src/app/core/modules/openapi/model/user.ts index 8e8311bd..371ca15c 100644 --- a/webapp/src/app/core/modules/openapi/model/user.ts +++ b/webapp/src/app/core/modules/openapi/model/user.ts @@ -29,11 +29,11 @@ export interface User { */ name?: string; /** - * Unique URL to the user\'s profile. Not the website a user can set in their profile. + * Unique URL to the user\'s profile. Not the website a user can set in their profile. */ url: string; /** - * URL to the user\'s avatar. If unavailable, a fallback can be generated from the login, e.g. on Github: https://github.com/{login}.png + * URL to the user\'s avatar. If unavailable, a fallback can be generated from the login, e.g. on Github: https://github.com/{login}.png */ avatarUrl?: string; /** diff --git a/webapp/src/app/home/home.component.html b/webapp/src/app/home/home.component.html index dad94add..be8be815 100644 --- a/webapp/src/app/home/home.component.html +++ b/webapp/src/app/home/home.component.html @@ -1,7 +1,9 @@

Artemis Leaderboard

- +
+ +
@if (query.error()) { An error has occurred diff --git a/webapp/src/app/home/home.component.ts b/webapp/src/app/home/home.component.ts index 938d2a9c..db66317c 100644 --- a/webapp/src/app/home/home.component.ts +++ b/webapp/src/app/home/home.component.ts @@ -1,4 +1,4 @@ -import { Component, computed, inject } from '@angular/core'; +import { Component, computed, effect, inject } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { injectQuery } from '@tanstack/angular-query-experimental'; import { LeaderboardService } from 'app/core/modules/openapi/api/leaderboard.service'; @@ -17,15 +17,26 @@ import dayjs from 'dayjs'; export class HomeComponent { leaderboardService = inject(LeaderboardService); - // timeframe for leaderboard - // example: 2024-09-19 private readonly route = inject(ActivatedRoute); private queryParams = toSignal(this.route.queryParamMap, { requireSync: true }); + // leaderboard filter protected after = computed(() => this.queryParams().get('after') ?? dayjs().day(1).format('YYYY-MM-DD')); protected before = computed(() => this.queryParams().get('before') ?? dayjs().format('YYYY-MM-DD')); + protected repository = computed(() => this.queryParams().get('repository') ?? 'all'); + + constructor() { + effect(() => { + console.log('HomeComponent: effect: ', this.repository()); + }); + } query = injectQuery(() => ({ - queryKey: ['leaderboard', { after: this.after(), before: this.before() }], - queryFn: async () => lastValueFrom(combineLatest([this.leaderboardService.getLeaderboard(this.after(), this.before()), timer(500)]).pipe(map(([leaderboard]) => leaderboard))) + queryKey: ['leaderboard', { after: this.after(), before: this.before(), repository: this.repository() }], + queryFn: async () => + lastValueFrom( + combineLatest([this.leaderboardService.getLeaderboard(this.after(), this.before(), this.repository() !== 'all' ? this.repository() : undefined), timer(500)]).pipe( + map(([leaderboard]) => leaderboard) + ) + ) })); } diff --git a/webapp/src/app/home/leaderboard/filter/filter.component.html b/webapp/src/app/home/leaderboard/filter/filter.component.html index e0acb284..bc0c909c 100644 --- a/webapp/src/app/home/leaderboard/filter/filter.component.html +++ b/webapp/src/app/home/leaderboard/filter/filter.component.html @@ -3,17 +3,8 @@

Filter

-
- - - - - - - @for (option of options(); track option.id) { - {{ option.label }} - } - - + + +
diff --git a/webapp/src/app/home/leaderboard/filter/filter.component.ts b/webapp/src/app/home/leaderboard/filter/filter.component.ts index c5a7facf..5cfe0cee 100644 --- a/webapp/src/app/home/leaderboard/filter/filter.component.ts +++ b/webapp/src/app/home/leaderboard/filter/filter.component.ts @@ -1,88 +1,17 @@ -import { Component, computed, effect, input, signal } from '@angular/core'; +import { Component, input } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { Router, RouterLink } from '@angular/router'; -import dayjs from 'dayjs'; -import weekOfYear from 'dayjs/plugin/weekOfYear'; -import { BrnSelectModule } from '@spartan-ng/ui-select-brain'; -import { HlmSelectModule } from '@spartan-ng/ui-select-helm'; -import { HlmLabelModule } from '@spartan-ng/ui-label-helm'; import { ListFilter, LucideAngularModule } from 'lucide-angular'; - -interface SelectOption { - id: number; - value: string; - label: string; -} - -dayjs.extend(weekOfYear); - -function formatLabel(startDate: dayjs.Dayjs, endDate: dayjs.Dayjs | undefined) { - const calendarWeek = startDate.week(); - if (!endDate) { - return `CW\xa0${calendarWeek}:\xa0${startDate.format('MMM D')}\xa0-\xa0Today`; - } - - const sameMonth = startDate.month() === endDate.month(); - if (sameMonth) { - return `CW\xa0${calendarWeek}:\xa0${startDate.format('MMM D')}\xa0-\xa0${endDate.format('D')}`; - } else { - return `CW\xa0${calendarWeek}:\xa0${startDate.format('MMM D')}\xa0-\xa0${endDate.format('MMM D')}`; - } -} +import { LeaderboardFilterTimeframeComponent } from './timeframe/timeframe.component'; +import { LeaderboardFilterRepositoryComponent } from './repository/repository.component'; @Component({ selector: 'app-leaderboard-filter', standalone: true, - imports: [RouterLink, LucideAngularModule, BrnSelectModule, HlmSelectModule, HlmLabelModule, FormsModule], + imports: [LucideAngularModule, FormsModule, LeaderboardFilterTimeframeComponent, LeaderboardFilterRepositoryComponent], templateUrl: './filter.component.html' }) export class LeaderboardFilterComponent { protected ListFilter = ListFilter; after = input(''); before = input(''); - - value = signal(`${this.after()}.${this.before()}`); - - placeholder = computed(() => { - return formatLabel(dayjs(this.after()) ?? dayjs().day(1), this.before() === undefined ? undefined : dayjs(this.before())); - }); - - options = computed(() => { - const now = dayjs(); - let currentDate = dayjs().day(1); - const options: SelectOption[] = [ - { - id: now.unix(), - value: `${currentDate.format('YYYY-MM-DD')}.${now.format('YYYY-MM-DD')}`, - label: formatLabel(currentDate, undefined) - } - ]; - - for (let i = 0; i < 4; i++) { - const startDate = currentDate.subtract(7, 'day'); - const endDate = currentDate.subtract(1, 'day'); - options.push({ - id: startDate.unix(), - value: `${startDate.format('YYYY-MM-DD')}.${endDate.format('YYYY-MM-DD')}`, - label: formatLabel(startDate, endDate) - }); - currentDate = startDate; - } - - return options; - }); - - constructor(private router: Router) { - effect(() => { - if (this.value().length === 1) return; - const dates = this.value().split('.'); - // change query params - this.router.navigate([], { - queryParams: { - after: dates[0], - before: dates[1] - } - }); - }); - } } diff --git a/webapp/src/app/home/leaderboard/filter/repository/repository.component.html b/webapp/src/app/home/leaderboard/filter/repository/repository.component.html new file mode 100644 index 00000000..17acd372 --- /dev/null +++ b/webapp/src/app/home/leaderboard/filter/repository/repository.component.html @@ -0,0 +1,11 @@ + + + + + + + @for (option of options(); track option.id) { + {{ option.label }} + } + + diff --git a/webapp/src/app/home/leaderboard/filter/repository/repository.component.ts b/webapp/src/app/home/leaderboard/filter/repository/repository.component.ts new file mode 100644 index 00000000..3d5f0827 --- /dev/null +++ b/webapp/src/app/home/leaderboard/filter/repository/repository.component.ts @@ -0,0 +1,72 @@ +import { Component, computed, effect, input, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { Router, RouterLink } from '@angular/router'; +import { BrnSelectModule } from '@spartan-ng/ui-select-brain'; +import { HlmSelectModule } from '@spartan-ng/ui-select-helm'; +import { HlmLabelModule } from '@spartan-ng/ui-label-helm'; + +// ls1intum/Artemis, ls1intum/Pyris, ls1intum/Athena, ls1intum/Athena-CoFee, ls1intum/artemis-ansible-collection, ls1intum/Ares, ls1intum/Ares2, ls1intum/Aeolus, ls1intum/hades, ls1intum/Apollon, ls1intum/Hephaestus, ls1intum/Apollon_standalone +export const repositoryNames = [ + 'ls1intum/Artemis', + 'ls1intum/Athena', + 'ls1intum/Hephaestus', + 'ls1intum/Pyris', + 'ls1intum/Ares2', + 'ls1intum/Aeolus', + 'ls1intum/hades', + 'ls1intum/Apollon', + 'ls1intum/Apollon_standalone' +]; + +interface SelectOption { + id: number; + value: string; + label: string; +} + +@Component({ + selector: 'app-leaderboard-filter-repository', + standalone: true, + imports: [RouterLink, BrnSelectModule, HlmSelectModule, HlmLabelModule, FormsModule], + templateUrl: './repository.component.html' +}) +export class LeaderboardFilterRepositoryComponent { + value = signal(''); + + placeholder = computed(() => { + return repositoryNames.find((option) => option === this.value()) ?? 'All'; + }); + + options = computed(() => { + const options: SelectOption[] = repositoryNames.map((name, index) => { + return { + id: index + 1, + value: name, + label: name + }; + }); + options.unshift({ + id: 0, + value: 'all', + label: 'All' + }); + return options; + }); + + constructor(private router: Router) { + this.value.set(this.router.parseUrl(this.router.url).queryParams['repository'] ?? 'all'); + effect(() => { + console.log('LeaderboardFilterRepositoryComponent: effect: ', this.value()); + if (!this.value() || this.value() === '') return; + const queryParams = this.router.parseUrl(this.router.url).queryParams; + if (this.value() === 'all') { + delete queryParams['repository']; + } else { + queryParams['repository'] = this.value(); + } + this.router.navigate([], { + queryParams + }); + }); + } +} diff --git a/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html new file mode 100644 index 00000000..0db6bd8e --- /dev/null +++ b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html @@ -0,0 +1,11 @@ + + + + + + + @for (option of options(); track option.id) { + {{ option.label }} + } + + diff --git a/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts new file mode 100644 index 00000000..ed200acc --- /dev/null +++ b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts @@ -0,0 +1,87 @@ +import { Component, computed, effect, input, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { Router, RouterLink } from '@angular/router'; +import dayjs from 'dayjs'; +import weekOfYear from 'dayjs/plugin/weekOfYear'; +import { BrnSelectModule } from '@spartan-ng/ui-select-brain'; +import { HlmSelectModule } from '@spartan-ng/ui-select-helm'; +import { HlmLabelModule } from '@spartan-ng/ui-label-helm'; + +interface SelectOption { + id: number; + value: string; + label: string; +} + +dayjs.extend(weekOfYear); + +function formatLabel(startDate: dayjs.Dayjs, endDate: dayjs.Dayjs | undefined) { + const calendarWeek = startDate.week(); + if (!endDate) { + return `CW\xa0${calendarWeek}:\xa0${startDate.format('MMM D')}\xa0-\xa0Today`; + } + + const sameMonth = startDate.month() === endDate.month(); + if (sameMonth) { + return `CW\xa0${calendarWeek}:\xa0${startDate.format('MMM D')}\xa0-\xa0${endDate.format('D')}`; + } else { + return `CW\xa0${calendarWeek}:\xa0${startDate.format('MMM D')}\xa0-\xa0${endDate.format('MMM D')}`; + } +} + +@Component({ + selector: 'app-leaderboard-filter-timeframe', + standalone: true, + imports: [RouterLink, BrnSelectModule, HlmSelectModule, HlmLabelModule, FormsModule], + templateUrl: './timeframe.component.html' +}) +export class LeaderboardFilterTimeframeComponent { + after = input(''); + before = input(''); + + value = signal(`${this.after()}.${this.before()}`); + + placeholder = computed(() => { + return formatLabel(dayjs(this.after()) ?? dayjs().day(1), this.before() === undefined ? undefined : dayjs(this.before())); + }); + + options = computed(() => { + const now = dayjs(); + let currentDate = dayjs().day(1); + const options: SelectOption[] = [ + { + id: now.unix(), + value: `${currentDate.format('YYYY-MM-DD')}.${now.format('YYYY-MM-DD')}`, + label: formatLabel(currentDate, undefined) + } + ]; + + for (let i = 0; i < 4; i++) { + const startDate = currentDate.subtract(7, 'day'); + const endDate = currentDate.subtract(1, 'day'); + options.push({ + id: startDate.unix(), + value: `${startDate.format('YYYY-MM-DD')}.${endDate.format('YYYY-MM-DD')}`, + label: formatLabel(startDate, endDate) + }); + currentDate = startDate; + } + + return options; + }); + + constructor(private router: Router) { + effect(() => { + if (this.value().length === 1) return; + + const queryParams = this.router.parseUrl(this.router.url).queryParams; + const dates = this.value().split('.'); + queryParams['after'] = dates[0]; + queryParams['before'] = dates[1]; + + this.router.navigate([], { + queryParams + }); + }); + } +}