From 1177c6f55164dd852fb828a4104f15629ac23e67 Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Wed, 8 May 2024 16:51:33 +0200 Subject: [PATCH 1/8] Added endpoint for sprint retrieval based on dates --- .../api/sprint/SprintControllerImpl.java | 8 ++++++ .../api/sprint/SprintServiceImpl.java | 25 ++++++++++++++++++- .../sprint/interfaces/SprintController.java | 2 ++ .../api/sprint/interfaces/SprintService.java | 2 ++ .../sprint/interfaces/SprintRepository.java | 11 ++++++++ 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java index 69398e06..15d4af2b 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java @@ -119,4 +119,12 @@ public final Page getSprintsBeforeSprint(@RequestParam long spri return sprintService.getSprintsBeforeSprint(sprintId, pageable, user); } + @Override + public List getSprintsBetweenDates(@RequestParam LocalDate startDate, + @RequestParam LocalDate endDate, + @RequestParam long projectId, + @JwtAuthed User user) { + return sprintService.getSprintsBetweenDates(startDate, endDate, projectId, user); + } + } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java index 28feace9..481c19d5 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java @@ -36,6 +36,7 @@ public class SprintServiceImpl implements SprintService { private static final String FOUND_SPRINT_TO_UPDATE = "Found sprint to update: {}"; private static final String PROJECT_NOT_FOUND = "Project with projectId: %d does not exist"; private static final String SPRINTS_ON_PAGE = "Sprints found on page : {}"; + private static final String FOUND_PROJECT_WITH_ID = "Found project with id: {}"; private final SprintRepository sprintRepository; private final ProjectRepository projectRepository; private final SprintMapper sprintMapper; @@ -202,7 +203,7 @@ public List getCurrentAndFutureSprints(long projectId, User user Project project = resolveProjectForProjectMember(projectId, user); - log.info("Found project with id: {}", project); + log.info(FOUND_PROJECT_WITH_ID, project); Pageable pageable = PageRequest.of(0, FUTURE_SPRINTS_PER_PAGE, Sort.by( Sort.Direction.ASC, SPRINT_START_DATE_FIELD_NAME) @@ -248,6 +249,28 @@ public final Page getSprintsBeforeSprint(long sprintId, Pageable return sprints.map(sprintMapper::toSprintResponse); } + @Override + public final List getSprintsBetweenDates(LocalDate startDate, LocalDate endDate, long projectId, + User user) { + log.info("Getting sprints between dates: {} and {} for project with id: {}", startDate, endDate, projectId); + + if(startDate.isAfter(endDate)) { + throw new SprintEndDateMustBeAfterStartDate(startDate, endDate); + } + + Project project = resolveProjectForProjectMember(projectId, user); + + log.info(FOUND_PROJECT_WITH_ID, project); + + List sprints = sprintRepository.findAllBetweenDates(startDate, endDate, project); + + log.info("Found and returning {} sprints", sprints.size()); + + return sprints.stream() + .map(sprintMapper::toSprintResponse) + .toList(); + } + private Project resolveProjectForProjectMember(long projectId, User user) { return projectRepository.findByIdWithProjectMember(projectId, user) .orElseThrow(() -> new ProjectDoesNotExistException( diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java index 8430ebdc..6b84c1bd 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java @@ -120,4 +120,6 @@ public interface SprintController { * @return Page of sprints occurring before the specified sprint */ Page getSprintsBeforeSprint(long sprintId, Pageable pageable, User user); + + List getSprintsBetweenDates(LocalDate startDate, LocalDate endDate, long projectId, User user); } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java index a9a8ef7d..2cfcdbd0 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java @@ -121,4 +121,6 @@ public interface SprintService { */ Page getSprintsBeforeSprint(long sprintId, Pageable pageable, User user); + List getSprintsBetweenDates(LocalDate startDate, LocalDate endDate, long projectId, User user); + } \ No newline at end of file diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java index 05241751..498bfad0 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Repository; import java.time.LocalDate; +import java.util.List; import java.util.Optional; /** @@ -128,5 +129,15 @@ select count(*) > 0 from Sprint s */ Page findAllByProjectAndEndDateBefore(Project project, LocalDate date, Pageable pageable); + @Query(""" + + SELECT s FROM Sprint s + WHERE s.project = :project AND + ((s.startDate <= :startDate AND s.endDate >= :startDate) OR + (s.startDate <= :endDate AND s.endDate >= :endDate) OR + (s.startDate >= :startDate AND s.endDate <= :endDate)) + """) + List findAllBetweenDates(LocalDate startDate, LocalDate endDate, Project project); + } From b75b8f6832898323a526f3d29f2132534b49db94 Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Wed, 8 May 2024 18:51:29 +0200 Subject: [PATCH 2/8] Basic timeline view, no sprints yet --- corn-frontend/package-lock.json | 37 ++++-- corn-frontend/package.json | 2 + corn-frontend/src/app/app.config.ts | 3 + .../boards/timeline/day/day.component.html | 10 ++ .../boards/timeline/day/day.component.scss | 0 .../boards/timeline/day/day.component.spec.ts | 23 ++++ .../boards/timeline/day/day.component.ts | 13 ++ .../boards/timeline/timeline.component.html | 59 +++++++++- .../boards/timeline/timeline.component.scss | 6 + .../boards/timeline/timeline.component.ts | 111 ++++++++++++++++-- package-lock.json | 6 - 11 files changed, 249 insertions(+), 21 deletions(-) create mode 100644 corn-frontend/src/app/pages/boards/timeline/day/day.component.html create mode 100644 corn-frontend/src/app/pages/boards/timeline/day/day.component.scss create mode 100644 corn-frontend/src/app/pages/boards/timeline/day/day.component.spec.ts create mode 100644 corn-frontend/src/app/pages/boards/timeline/day/day.component.ts create mode 100644 corn-frontend/src/app/pages/boards/timeline/timeline.component.scss delete mode 100644 package-lock.json diff --git a/corn-frontend/package-lock.json b/corn-frontend/package-lock.json index 874cc17c..bd44b1ec 100644 --- a/corn-frontend/package-lock.json +++ b/corn-frontend/package-lock.json @@ -15,6 +15,7 @@ "@angular/core": "^17.1.0", "@angular/forms": "^17.1.0", "@angular/material": "^17.1.1", + "@angular/material-moment-adapter": "^17.3.7", "@angular/platform-browser": "^17.1.0", "@angular/platform-browser-dynamic": "^17.1.0", "@angular/router": "^17.1.0", @@ -31,6 +32,7 @@ "@ng-icons/ux-aspects": "^26.3.0", "keycloak-angular": "^15.1.0", "keycloak-js": "^23.0.5", + "moment": "^2.30.1", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" @@ -366,9 +368,9 @@ } }, "node_modules/@angular/cdk": { - "version": "17.3.4", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.3.4.tgz", - "integrity": "sha512-/wbKUbc0YC3HGE2TCgW7D07Q99PZ/5uoRvMyWw0/wHa8VLNavXZPecbvtyLs//3HnqoCMSUFE7E2Mrd7jAWfcA==", + "version": "17.3.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.3.7.tgz", + "integrity": "sha512-aFEh8tzKFOwini6aNEp57S54Ocp9T7YIJfBVMESptu2TCPdMTlJ1HJTg5XS8NcQO+vwi9cFPGVwGF1frOx4LXA==", "dependencies": { "tslib": "^2.3.0" }, @@ -555,9 +557,9 @@ } }, "node_modules/@angular/material": { - "version": "17.3.4", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-17.3.4.tgz", - "integrity": "sha512-SgCroIlHKt3s9pTEYlhW4ww6Gm1sIzJKuk0wlputPZvQS5PTJ8YY8vDg4QohpQcltlaXCbutt4qw+CBNU9W9iA==", + "version": "17.3.7", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-17.3.7.tgz", + "integrity": "sha512-wjSKkk9KZE8QiBPkMd5axh5u/3pUSxoLKNO7OasFhEagMmSv5oYTLm40cErhtb4UdkSmbC19WuuluS6P3leoPA==", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/auto-init": "15.0.0-canary.7f224ddd4.0", @@ -610,7 +612,7 @@ }, "peerDependencies": { "@angular/animations": "^17.0.0 || ^18.0.0", - "@angular/cdk": "17.3.4", + "@angular/cdk": "17.3.7", "@angular/common": "^17.0.0 || ^18.0.0", "@angular/core": "^17.0.0 || ^18.0.0", "@angular/forms": "^17.0.0 || ^18.0.0", @@ -618,6 +620,19 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@angular/material-moment-adapter": { + "version": "17.3.7", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-17.3.7.tgz", + "integrity": "sha512-CwKB7kiVz9NOP9qaUksn4H8Un6VvAktp5uTPxa5QF186Ll1tMDPMGQ3B24le3tfUCUFZx7Jv2jA045pQ+8n/jA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^17.0.0 || ^18.0.0", + "@angular/material": "17.3.7", + "moment": "^2.18.1" + } + }, "node_modules/@angular/platform-browser": { "version": "17.3.4", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.4.tgz", @@ -9518,6 +9533,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/mrmime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", diff --git a/corn-frontend/package.json b/corn-frontend/package.json index 3946599c..c6a5e8d7 100644 --- a/corn-frontend/package.json +++ b/corn-frontend/package.json @@ -18,6 +18,7 @@ "@angular/core": "^17.1.0", "@angular/forms": "^17.1.0", "@angular/material": "^17.1.1", + "@angular/material-moment-adapter": "^17.3.7", "@angular/platform-browser": "^17.1.0", "@angular/platform-browser-dynamic": "^17.1.0", "@angular/router": "^17.1.0", @@ -34,6 +35,7 @@ "@ng-icons/ux-aspects": "^26.3.0", "keycloak-angular": "^15.1.0", "keycloak-js": "^23.0.5", + "moment": "^2.30.1", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" diff --git a/corn-frontend/src/app/app.config.ts b/corn-frontend/src/app/app.config.ts index c7f53e87..1a7fa42f 100644 --- a/corn-frontend/src/app/app.config.ts +++ b/corn-frontend/src/app/app.config.ts @@ -7,6 +7,8 @@ import { provideAnimations } from '@angular/platform-browser/animations'; import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { ErrorInterceptor } from '@core/interceptors/error.interceptor'; import { KeycloakAngularModule, KeycloakBearerInterceptor, KeycloakService } from 'keycloak-angular'; +import { provideMomentDateAdapter } from "@angular/material-moment-adapter"; +import { MY_FORMATS } from "@pages/boards/timeline/timeline.component"; function initializeKeycloak(keycloak: KeycloakService) { return () => @@ -50,5 +52,6 @@ export const appConfig: ApplicationConfig = { deps: [KeycloakService] }, KeycloakService, + provideMomentDateAdapter(MY_FORMATS) ] }; diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html new file mode 100644 index 00000000..e5ac9b2d --- /dev/null +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html @@ -0,0 +1,10 @@ +
+
+ @if(day > 0) { +

{{day}}

+ } +
+
+ +
+
diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss b/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.spec.ts b/corn-frontend/src/app/pages/boards/timeline/day/day.component.spec.ts new file mode 100644 index 00000000..af5579b7 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DayComponent } from './day.component'; + +describe('DayComponent', () => { + let component: DayComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DayComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DayComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts new file mode 100644 index 00000000..36a53e74 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'app-day', + standalone: true, + imports: [], + templateUrl: './day.component.html', + styleUrl: './day.component.scss' +}) +export class DayComponent { + + @Input() day: number = 0; +} diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html index 97b9ee7d..334aa515 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html @@ -1 +1,58 @@ -

Timeline

+
+ + + + + Month and Year + + + + + + + + +
+ + + @for(day of days; track day) { + +
+

{{ day }}

+
+
+ } +
+ + + @for(day of getArrayFromDays(previousMonthDays[0], previousMonthDays[1]); track day) { + +
+ +
+
+ } + + @for(day of getArrayFromDays(1, currentMonthDays); track day) { + +
+ +
+
+ } + + @for(day of getArrayFromDays(1, nextMonthDays); track day) { + +
+ +
+
+ } +
diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.scss b/corn-frontend/src/app/pages/boards/timeline/timeline.component.scss new file mode 100644 index 00000000..aebd0216 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.scss @@ -0,0 +1,6 @@ +.arrow-button { + display: flex; + align-items: center; + justify-content: center; + width: max-content; +} \ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts index 9505c29e..d034d7da 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts @@ -1,10 +1,107 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker'; +import _moment from 'moment'; +import { default as _rollupMoment, Moment } from 'moment'; +import { MatInputModule } from '@angular/material/input'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { NgIcon, provideIcons } from "@ng-icons/core"; +import { matArrowLeft, matArrowRight } from "@ng-icons/material-icons/baseline"; +import { MatIconButton } from "@angular/material/button"; +import { MatIcon } from "@angular/material/icon"; +import { MatGridList, MatGridTile } from "@angular/material/grid-list"; +import { DayComponent } from "@pages/boards/timeline/day/day.component"; + +const moment = _rollupMoment || _moment; + +export const MY_FORMATS = { + parse: { + dateInput: 'MM/YYYY', + }, + display: { + dateInput: 'MM/YYYY', + monthYearLabel: 'MMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + }, +}; + +/** @title Datepicker emulating a Year and month picker */ @Component({ - selector: 'app-timeline', - standalone: true, - imports: [], - templateUrl: './timeline.component.html', + selector: 'app-timeline-component', + templateUrl: 'timeline.component.html', + standalone: true, + imports: [ + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + FormsModule, + ReactiveFormsModule, + MatIconButton, + NgIcon, + MatIcon, + MatGridList, + MatGridTile, + DayComponent, + ], + providers: [provideIcons({matArrowLeft, matArrowRight})] }) -export class TimelineComponent { -} +export class TimelineComponent implements OnInit{ + + days: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; + + previousMonthDays: number[] = [0, 0]; + currentMonthDays: number = 0; + nextMonthDays: number = 0; + + date: FormControl<_moment.Moment | null> = new FormControl(moment()); + + setMonthAndYear(normalizedMonthAndYear: Moment, datepicker: MatDatepicker): void { + datepicker.close(); + + const ctrlValue: Moment = this.date.value ?? moment(); + ctrlValue.month(normalizedMonthAndYear.month()); + ctrlValue.year(normalizedMonthAndYear.year()); + this.date.setValue(ctrlValue); + + this.setMonthDays(ctrlValue); + } + + changeMonth(numberOfMonths: number): void { + const ctrlValue: Moment = this.date.value!; + ctrlValue.add(numberOfMonths, 'months'); + this.date.setValue(ctrlValue); + + this.setMonthDays(ctrlValue); + } + + setMonthDays(value: Moment): void { + const firstDayOfMonth = value.clone().startOf('month'); + + const daysInCurrentMonth = value.daysInMonth(); + + const daysFromPreviousMonth = firstDayOfMonth.day() === 0 ? 6 : firstDayOfMonth.day() - 1; + + const daysFromNextMonth = 7*6 - daysInCurrentMonth - daysFromPreviousMonth; + + if(daysFromPreviousMonth == 0) { + this.previousMonthDays = [0, 0]; + } else { + this.previousMonthDays = [firstDayOfMonth.clone().subtract(daysFromPreviousMonth, 'days').date(), firstDayOfMonth.clone().subtract(1, 'days').date()]; + } + this.currentMonthDays = daysInCurrentMonth; + this.nextMonthDays = daysFromNextMonth; + } + + getArrayFromDays(firstDay: number, lastDay: number): number[] { + if(firstDay == 0) { + return []; + } + return Array.from({length: lastDay - firstDay + 1}, (_, i) => firstDay + i); + } + + ngOnInit(): void { + this.setMonthDays(this.date.value!); + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e3072efb..00000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Corn", - "lockfileVersion": 2, - "requires": true, - "packages": {} -} From dcb28f4ee4c1fc63a60f3b5a7685eb919983ea83 Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Sat, 11 May 2024 14:08:29 +0200 Subject: [PATCH 3/8] Added mapping and ordering in backend and sprints to timeline view --- .../api/sprint/SprintControllerImpl.java | 4 +- .../api/sprint/constants/SprintMappings.java | 2 + .../sprint/interfaces/SprintRepository.java | 2 +- corn-frontend/src/app/core/enum/api-url.ts | 1 + .../boards/backlog/sprint/sprint.service.ts | 11 + .../boards/timeline/day/day.component.html | 19 +- .../boards/timeline/day/day.component.ts | 20 +- .../boards/timeline/timeline.component.html | 99 ++++---- .../boards/timeline/timeline.component.ts | 227 +++++++++++++----- 9 files changed, 259 insertions(+), 126 deletions(-) diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java index 15d4af2b..cae68d92 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java @@ -28,6 +28,7 @@ import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.GET_SPRINT_BY_ID; import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.SPRINTS_AFTER_SPRINT; import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.SPRINTS_BEFORE_SPRINT; +import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.SPRINTS_BETWEEN_DATES; import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.SPRINT_API_ENDPOINT; import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.UPDATE_SPRINTS_DESCRIPTION; import static dev.corn.cornbackend.api.sprint.constants.SprintMappings.UPDATE_SPRINTS_END_DATE; @@ -120,7 +121,8 @@ public final Page getSprintsBeforeSprint(@RequestParam long spri } @Override - public List getSprintsBetweenDates(@RequestParam LocalDate startDate, + @GetMapping(value = SPRINTS_BETWEEN_DATES) + public final List getSprintsBetweenDates(@RequestParam LocalDate startDate, @RequestParam LocalDate endDate, @RequestParam long projectId, @JwtAuthed User user) { diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/constants/SprintMappings.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/constants/SprintMappings.java index 104d86ee..1b0b38be 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/constants/SprintMappings.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/constants/SprintMappings.java @@ -25,6 +25,8 @@ public final class SprintMappings { public static final String SPRINTS_BEFORE_SPRINT = "/getSprintsBeforeSprint"; + public static final String SPRINTS_BETWEEN_DATES = "/getSprintsBetweenDates"; + private SprintMappings() { } } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java index 498bfad0..692b7b16 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/interfaces/SprintRepository.java @@ -130,12 +130,12 @@ select count(*) > 0 from Sprint s Page findAllByProjectAndEndDateBefore(Project project, LocalDate date, Pageable pageable); @Query(""" - SELECT s FROM Sprint s WHERE s.project = :project AND ((s.startDate <= :startDate AND s.endDate >= :startDate) OR (s.startDate <= :endDate AND s.endDate >= :endDate) OR (s.startDate >= :startDate AND s.endDate <= :endDate)) + ORDER BY s.startDate ASC """) List findAllBetweenDates(LocalDate startDate, LocalDate endDate, Project project); diff --git a/corn-frontend/src/app/core/enum/api-url.ts b/corn-frontend/src/app/core/enum/api-url.ts index fc5247c7..032e6807 100644 --- a/corn-frontend/src/app/core/enum/api-url.ts +++ b/corn-frontend/src/app/core/enum/api-url.ts @@ -12,6 +12,7 @@ export enum ApiUrl { GET_SPRINTS_ON_PAGE = SPRINT_API_URL + '/getSprintsOnPage', GET_CURRENT_AND_FUTURE_SPRINTS = SPRINT_API_URL + '/currentAndFuture', + GET_SPRINTS_BETWEEN_DATES = SPRINT_API_URL + '/getSprintsBetweenDates', GET_PROJECT_MEMBERS = PROJECT_MEMBER_API_URL + '/getMembers', diff --git a/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts b/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts index eb9c67bc..3f20dd59 100644 --- a/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts +++ b/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts @@ -5,6 +5,7 @@ import { Sprint } from "@interfaces/boards/backlog/sprint"; import { ApiUrl } from "@core/enum/api-url"; import { StorageService } from "@core/services/storage.service"; import { StorageKey } from "@core/enum/storage-key.enum"; +import { Moment } from "moment"; @Injectable({ providedIn: 'root' @@ -32,4 +33,14 @@ export class SprintService { } }); } + + getSprintsBetweenDates(startDate: Moment, endDate: Moment): Observable { + return this.http.get(ApiUrl.GET_SPRINTS_BETWEEN_DATES, { + params: { + startDate: startDate.format('YYYY-MM-DD'), + endDate: endDate.format('YYYY-MM-DD'), + projectId: this.storage.getValueFromStorage(StorageKey.PROJECT_ID) + } + }); + } } \ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html index e5ac9b2d..f8f8f424 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html @@ -1,10 +1,23 @@
- @if(day > 0) { -

{{day}}

+ @if (day > 0) { +

{{ day }}

}
-
+
+ @if (sprintName !== '') { + @if(isFirst) { +
+
+

{{ sprintName }}

+
+
+ } @else if(isLast) { +
+ } @else { +
+ } + }
diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts index 36a53e74..6fc2933a 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts @@ -1,13 +1,21 @@ import { Component, Input } from '@angular/core'; +import { MatGridList } from "@angular/material/grid-list"; + @Component({ - selector: 'app-day', - standalone: true, - imports: [], - templateUrl: './day.component.html', - styleUrl: './day.component.scss' + selector: 'app-day', + standalone: true, + imports: [ + MatGridList + ], + templateUrl: './day.component.html', + styleUrl: './day.component.scss' }) export class DayComponent { - @Input() day: number = 0; + @Input() day: number = 0; + @Input() isFirst: boolean = false; + @Input() isLast: boolean = false; + @Input() sprintName: string = ''; + } diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html index 334aa515..65cb91c5 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html @@ -1,58 +1,53 @@ -
- - - - - Month and Year - - - - - - - +
+
+
+
+ + + + Month and Year + + + + + + + -
- - - @for(day of days; track day) { - -
-

{{ day }}

-
- } -
- - - @for(day of getArrayFromDays(previousMonthDays[0], previousMonthDays[1]); track day) { - -
- -
-
- } - @for(day of getArrayFromDays(1, currentMonthDays); track day) { - -
- +
+ @for (day of days; track day) { +
+

{{ day }}

+
+ }
- - } - @for(day of getArrayFromDays(1, nextMonthDays); track day) { - -
- +
+ @for (day of daysArray; track day; let i = $index) { +
+ +
+ }
- - } - +
+
+
+ + + + diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts index d034d7da..cf145c83 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts @@ -12,96 +12,197 @@ import { MatIconButton } from "@angular/material/button"; import { MatIcon } from "@angular/material/icon"; import { MatGridList, MatGridTile } from "@angular/material/grid-list"; import { DayComponent } from "@pages/boards/timeline/day/day.component"; +import { SprintService } from "@core/services/boards/backlog/sprint/sprint.service"; +import { last, take } from "rxjs"; +import { Sprint } from "@interfaces/boards/backlog/sprint"; const moment = _rollupMoment || _moment; export const MY_FORMATS = { - parse: { - dateInput: 'MM/YYYY', - }, - display: { - dateInput: 'MM/YYYY', - monthYearLabel: 'MMM YYYY', - dateA11yLabel: 'LL', - monthYearA11yLabel: 'MMMM YYYY', - }, + parse: { + dateInput: 'MM/YYYY', + }, + display: { + dateInput: 'MM/YYYY', + monthYearLabel: 'MMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + }, }; /** @title Datepicker emulating a Year and month picker */ @Component({ - selector: 'app-timeline-component', - templateUrl: 'timeline.component.html', - standalone: true, - imports: [ - MatFormFieldModule, - MatInputModule, - MatDatepickerModule, - FormsModule, - ReactiveFormsModule, - MatIconButton, - NgIcon, - MatIcon, - MatGridList, - MatGridTile, - DayComponent, - ], - providers: [provideIcons({matArrowLeft, matArrowRight})] + selector: 'app-timeline-component', + templateUrl: 'timeline.component.html', + standalone: true, + imports: [ + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + FormsModule, + ReactiveFormsModule, + MatIconButton, + NgIcon, + MatIcon, + MatGridList, + MatGridTile, + DayComponent, + ], + providers: [provideIcons({matArrowLeft, matArrowRight})] }) -export class TimelineComponent implements OnInit{ +export class TimelineComponent implements OnInit { - days: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; + days: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; - previousMonthDays: number[] = [0, 0]; - currentMonthDays: number = 0; - nextMonthDays: number = 0; + previousMonthDays: number[] = [0, 0]; + currentMonthDays: number = 0; + nextMonthDays: number = 0; + firstDay: Moment = moment().startOf('month'); + lastDay: Moment = moment().endOf('month'); - date: FormControl<_moment.Moment | null> = new FormControl(moment()); + date: FormControl<_moment.Moment | null> = new FormControl(moment()); - setMonthAndYear(normalizedMonthAndYear: Moment, datepicker: MatDatepicker): void { - datepicker.close(); + sprints: Sprint[] = []; + daysArray: number[] = []; + indexArray: number[] = []; - const ctrlValue: Moment = this.date.value ?? moment(); - ctrlValue.month(normalizedMonthAndYear.month()); - ctrlValue.year(normalizedMonthAndYear.year()); - this.date.setValue(ctrlValue); + constructor(private sprintService: SprintService) { + } - this.setMonthDays(ctrlValue); - } + setMonthAndYear(normalizedMonthAndYear: Moment, datepicker: MatDatepicker): void { + datepicker.close(); + + const ctrlValue: Moment = this.date.value ?? moment(); + ctrlValue.month(normalizedMonthAndYear.month()); + ctrlValue.year(normalizedMonthAndYear.year()); + this.date.setValue(ctrlValue); + + this.setMonthDays(ctrlValue); + + this.getSprints(); + } + + changeMonth(numberOfMonths: number): void { + const ctrlValue: Moment = this.date.value!; + ctrlValue.add(numberOfMonths, 'months'); + this.date.setValue(ctrlValue); + + this.setMonthDays(ctrlValue); + + this.getSprints(); + } + + setMonthDays(value: Moment): void { + const firstDayOfMonth: Moment = value.clone().startOf('month'); - changeMonth(numberOfMonths: number): void { - const ctrlValue: Moment = this.date.value!; - ctrlValue.add(numberOfMonths, 'months'); - this.date.setValue(ctrlValue); + const daysInCurrentMonth: number = value.daysInMonth(); - this.setMonthDays(ctrlValue); + const daysFromPreviousMonth: number = firstDayOfMonth.day() === 0 ? 6 : firstDayOfMonth.day() - 1; + + const daysFromNextMonth: number = 7 * 6 - daysInCurrentMonth - daysFromPreviousMonth; + + if (daysFromPreviousMonth == 0) { + this.previousMonthDays = [0, 0]; + this.firstDay = firstDayOfMonth.clone(); + } else { + this.firstDay = firstDayOfMonth.clone().subtract(daysFromPreviousMonth, 'days'); + this.previousMonthDays = [this.firstDay.date(), firstDayOfMonth.clone().subtract(1, 'days').date()]; + } + this.currentMonthDays = daysInCurrentMonth; + this.lastDay = firstDayOfMonth.clone().endOf('month').add(daysFromNextMonth, 'days'); + this.nextMonthDays = daysFromNextMonth; + } + + getArrayFromDays(firstDay: number, lastDay: number): number[] { + if(firstDay == 0) { + return []; } - setMonthDays(value: Moment): void { - const firstDayOfMonth = value.clone().startOf('month'); + return Array.from({length: lastDay - firstDay + 1}, (_, i) => firstDay + i); + } - const daysInCurrentMonth = value.daysInMonth(); + ngOnInit(): void { + this.setMonthDays(this.date.value!); - const daysFromPreviousMonth = firstDayOfMonth.day() === 0 ? 6 : firstDayOfMonth.day() - 1; + this.getSprints(); + } - const daysFromNextMonth = 7*6 - daysInCurrentMonth - daysFromPreviousMonth; + getSprints(): void { + this.sprintService.getSprintsBetweenDates(this.firstDay, this.lastDay) + .pipe(take(1)) + .subscribe(sprints => { + this.sprints = sprints; + this.createDayArray(); + this.createIndexArray(); + }); + } - if(daysFromPreviousMonth == 0) { - this.previousMonthDays = [0, 0]; - } else { - this.previousMonthDays = [firstDayOfMonth.clone().subtract(daysFromPreviousMonth, 'days').date(), firstDayOfMonth.clone().subtract(1, 'days').date()]; - } - this.currentMonthDays = daysInCurrentMonth; - this.nextMonthDays = daysFromNextMonth; + createDayArray(): void { + let days: number[] = []; + + days = [...days, ...this.getArrayFromDays(this.previousMonthDays[0], this.previousMonthDays[1])] + days = [...days, ...this.getArrayFromDays(1, this.currentMonthDays)]; + days = [...days, ...this.getArrayFromDays(1, this.nextMonthDays)]; + + this.daysArray = days; + } + + createIndexArray(): void { + let days: number[] = []; + + if(this.sprints.length == 0) { + days = Array.from({length: 42}, (_, i) => -1); + this.indexArray = days; + return; } - getArrayFromDays(firstDay: number, lastDay: number): number[] { - if(firstDay == 0) { - return []; + let difference: number = moment(this.sprints[0].startDate).diff(this.firstDay, 'days'); + + for(let i = 0; i < difference; i++) { + days.push(-1); + } + + let previousSprintLastDay: Moment | null = null; + + for(let j = 0; j < this.sprints.length; j++) { + let sprint: Sprint = this.sprints[j]; + let startDate: Moment = moment(sprint.startDate); + + if(startDate.isBefore(this.firstDay)) { + startDate = this.firstDay; + } + + if(previousSprintLastDay) { + difference = startDate.diff(previousSprintLastDay, 'days'); + difference -= 1; + + for (let i = 0; i < difference; i++) { + days.push(-1); } - return Array.from({length: lastDay - firstDay + 1}, (_, i) => firstDay + i); + } + + let endDate: Moment = moment(sprint.endDate); + + if(endDate.isAfter(this.lastDay)) { + endDate = this.lastDay; + } + + difference = endDate.diff(startDate, 'days'); + + for(let i = 0; i <= difference; i++) { + days.push(j); + } + + previousSprintLastDay = endDate; } - ngOnInit(): void { - this.setMonthDays(this.date.value!); + difference = this.lastDay.diff(previousSprintLastDay, 'days'); + + for(let i = 0; i < difference; i++) { + days.push(-1); } + + this.indexArray = days; + } + } \ No newline at end of file From 705bdb896601fb9e4aa3b3d08e7b62ff4ae276a5 Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Sat, 11 May 2024 15:01:57 +0200 Subject: [PATCH 4/8] Moved Moment, added black background and colors to sprints --- corn-frontend/src/app/app.config.ts | 3 -- .../boards/timeline/day/day.component.html | 6 ++-- .../boards/timeline/day/day.component.scss | 35 +++++++++++++++++++ .../boards/timeline/day/day.component.ts | 1 + .../boards/timeline/timeline.component.html | 3 +- .../boards/timeline/timeline.component.ts | 18 ++++++++-- 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/corn-frontend/src/app/app.config.ts b/corn-frontend/src/app/app.config.ts index ccdda833..ac884646 100644 --- a/corn-frontend/src/app/app.config.ts +++ b/corn-frontend/src/app/app.config.ts @@ -6,8 +6,6 @@ import { provideAnimations } from '@angular/platform-browser/animations'; import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { ErrorInterceptor } from '@core/interceptors/error.interceptor'; import { KeycloakAngularModule, KeycloakBearerInterceptor, KeycloakService } from 'keycloak-angular'; -import { provideMomentDateAdapter } from "@angular/material-moment-adapter"; -import { MY_FORMATS } from "@pages/boards/timeline/timeline.component"; import { DatePipe } from "@angular/common"; import { provideNativeDateAdapter } from "@angular/material/core"; @@ -53,7 +51,6 @@ export const appConfig: ApplicationConfig = { deps: [KeycloakService] }, KeycloakService, - provideMomentDateAdapter(MY_FORMATS), provideNativeDateAdapter(), DatePipe ] diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html index f8f8f424..27db54bc 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html @@ -7,15 +7,15 @@

{{ day }}

@if (sprintName !== '') { @if(isFirst) { -
+

{{ sprintName }}

} @else if(isLast) { -
+
} @else { -
+
} } diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss b/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss index e69de29b..899b0e9e 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss @@ -0,0 +1,35 @@ +.bg-red-500 { + @apply bg-red-500/50; +} + +.bg-orange-500 { + @apply bg-orange-500/50; +} + +.bg-yellow-500 { + @apply bg-yellow-500/50; +} + +.bg-lime-500 { + @apply bg-lime-500/50; +} + +.bg-green-500 { + @apply bg-green-500/50; +} + +.bg-cyan-500 { + @apply bg-cyan-500/50; +} + +.bg-blue-500 { + @apply bg-blue-500/50; +} + +.bg-purple-500 { + @apply bg-purple-500/50; +} + +.bg-pink-500 { + @apply bg-pink-500/50; +} \ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts index 6fc2933a..789e3266 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts @@ -17,5 +17,6 @@ export class DayComponent { @Input() isFirst: boolean = false; @Input() isLast: boolean = false; @Input() sprintName: string = ''; + @Input() backgroundColor: string = 'cyan-400'; } diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html index 65cb91c5..abf28b31 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html @@ -1,6 +1,6 @@
-
+
} diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts index cf145c83..81ca55f9 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts @@ -13,8 +13,9 @@ import { MatIcon } from "@angular/material/icon"; import { MatGridList, MatGridTile } from "@angular/material/grid-list"; import { DayComponent } from "@pages/boards/timeline/day/day.component"; import { SprintService } from "@core/services/boards/backlog/sprint/sprint.service"; -import { last, take } from "rxjs"; +import { take } from "rxjs"; import { Sprint } from "@interfaces/boards/backlog/sprint"; +import { provideMomentDateAdapter } from "@angular/material-moment-adapter"; const moment = _rollupMoment || _moment; @@ -48,7 +49,7 @@ export const MY_FORMATS = { MatGridTile, DayComponent, ], - providers: [provideIcons({matArrowLeft, matArrowRight})] + providers: [provideIcons({matArrowLeft, matArrowRight}), provideMomentDateAdapter(MY_FORMATS)] }) export class TimelineComponent implements OnInit { @@ -66,10 +67,23 @@ export class TimelineComponent implements OnInit { daysArray: number[] = []; indexArray: number[] = []; + colors: string[] = [ + 'red', + 'orange', + 'yellow', + 'lime', + 'green', + 'cyan', + 'blue', + 'purple', + 'pink' + ] + constructor(private sprintService: SprintService) { } setMonthAndYear(normalizedMonthAndYear: Moment, datepicker: MatDatepicker): void { + console.log(normalizedMonthAndYear); datepicker.close(); const ctrlValue: Moment = this.date.value ?? moment(); From d457d4c034bfbe91b4a2888210c8bcb23ec8b032 Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Sat, 11 May 2024 17:31:43 +0200 Subject: [PATCH 5/8] Added hover and sprint edition --- .../boards/timeline/day/day.component.html | 16 ++- .../boards/timeline/day/day.component.scss | 36 ++++++ .../boards/timeline/day/day.component.ts | 118 +++++++++++++++++- .../boards/timeline/timeline.component.html | 12 +- .../boards/timeline/timeline.component.ts | 15 ++- 5 files changed, 182 insertions(+), 15 deletions(-) diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html index 27db54bc..d5e95195 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.html @@ -5,19 +5,23 @@

{{ day }}

}
- @if (sprintName !== '') { + @if (sprint) { @if(isFirst) { -
+
-

{{ sprintName }}

+

{{ sprint.sprintName }}

} @else if(isLast) { -
+
+
} @else { -
+
+
} - }
diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss b/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss index 899b0e9e..83f9815c 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.scss @@ -32,4 +32,40 @@ .bg-pink-500 { @apply bg-pink-500/50; +} + +.bg-red-300 { + @apply bg-red-300/50; +} + +.bg-orange-300 { + @apply bg-orange-300/50; +} + +.bg-yellow-300 { + @apply bg-yellow-300/50; +} + +.bg-lime-300 { + @apply bg-lime-300/50; +} + +.bg-green-300 { + @apply bg-green-300/50; +} + +.bg-cyan-300 { + @apply bg-cyan-300/50; +} + +.bg-blue-300 { + @apply bg-blue-300/50; +} + +.bg-purple-300 { + @apply bg-purple-300/50; +} + +.bg-pink-300 { + @apply bg-pink-300/50; } \ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts index 789e3266..9ddbce39 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts @@ -1,22 +1,130 @@ -import { Component, Input } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; import { MatGridList } from "@angular/material/grid-list"; +import { Subject, take, takeUntil } from "rxjs"; +import { Sprint } from "@interfaces/boards/backlog/sprint"; +import { MatDialog } from "@angular/material/dialog"; +import { BacklogEditFormComponent } from "@pages/boards/backlog/backlog-edit-form/backlog-edit-form.component"; +import { SprintEditData } from "@interfaces/boards/backlog/sprint-edit-data.interfaces"; +import { SprintService } from "@core/services/boards/backlog/sprint/sprint.service"; @Component({ selector: 'app-day', standalone: true, imports: [ - MatGridList + MatGridList ], templateUrl: './day.component.html', styleUrl: './day.component.scss' }) -export class DayComponent { +export class DayComponent implements OnDestroy { @Input() day: number = 0; @Input() isFirst: boolean = false; @Input() isLast: boolean = false; - @Input() sprintName: string = ''; - @Input() backgroundColor: string = 'cyan-400'; + @Input() sprint: Sprint | null = null; + @Input() backgroundColor: string = 'cyan'; + + @Output() changeEmitter: EventEmitter = new EventEmitter(); + + color_value: string = '500'; + + constructor(private dialog: MatDialog, + private sprintService: SprintService) { + + } + + + private _eventEmitter: EventEmitter = new EventEmitter(); + + hovered = false; + + $destroy: Subject = new Subject(); + + @Input() + set eventEmitter(emitter: EventEmitter | null) { + if (!emitter) { + return; + } + + this._eventEmitter = emitter; + + this._eventEmitter + .pipe(takeUntil(this.$destroy)) + .subscribe(value => { + this.hovered = value; + if (value) { + this.color_value = '300'; + } else { + this.color_value = '500'; + } + }); + } + + ngOnDestroy(): void { + this.$destroy.next(); + this.$destroy.complete(); + } + + mouseOut(): void { + this._eventEmitter.emit(false); + } + + mouseOver(): void { + this._eventEmitter.emit(true); + } + + openSprint(): void { + const dialogRef = this.dialog.open(BacklogEditFormComponent, { + enterAnimationDuration: '300ms', + exitAnimationDuration: '100ms', + data: this.sprint + }) + + dialogRef.afterClosed() + .pipe(take(1)) + .subscribe((data: SprintEditData) => { + if (!data || !this.sprint) { + return; + } + + let changed: boolean = false; + + if (data.sprintName !== this.sprint.sprintName) { + changed = true; + this.sprintService.editSprintName(data.sprintName, this.sprint.sprintId) + .pipe(take(1)) + .subscribe() + } + + if (data.goal !== this.sprint.sprintDescription) { + changed = true; + this.sprintService.editSprintDescription(data.goal, this.sprint.sprintId) + .pipe(take(1)) + .subscribe() + } + + if (data.startDate !== this.sprint.startDate) { + changed = true; + this.sprintService.editSprintStartDate(data.startDate, this.sprint.sprintId) + .pipe(take(1)) + .subscribe() + } + + if (data.endDate !== this.sprint.endDate) { + changed = true; + this.sprintService.editSprintEndDate(data.endDate, this.sprint.sprintId) + .pipe(take(1)) + .subscribe() + } + + if (changed) { + this.changeEmitter.emit(); + } + + + }) + } + } diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html index abf28b31..873d5904 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.html +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.html @@ -1,4 +1,8 @@ -
+
+
+

Timeline

+
+
@@ -9,7 +13,7 @@ Month and Year - + {{ day }} @for (day of daysArray; track day; let i = $index) {
} diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts index 81ca55f9..7c85f4dd 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, EventEmitter, OnInit } from '@angular/core'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker'; @@ -79,6 +79,8 @@ export class TimelineComponent implements OnInit { 'pink' ] + emitters: EventEmitter[] = []; + constructor(private sprintService: SprintService) { } @@ -148,9 +150,20 @@ export class TimelineComponent implements OnInit { this.sprints = sprints; this.createDayArray(); this.createIndexArray(); + this.createEmittersArray(); }); } + createEmittersArray(): void { + let emitters: EventEmitter[] = []; + + for(let i = 0; i < this.sprints.length; i++) { + emitters.push(new EventEmitter()); + } + + this.emitters = emitters; + } + createDayArray(): void { let days: number[] = []; From 253b2712d3aa371519336c5ed2a59b509033d56c Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Sat, 11 May 2024 17:32:29 +0200 Subject: [PATCH 6/8] Optimized imports --- .../src/app/pages/boards/timeline/timeline.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts index 7c85f4dd..e1882ce1 100644 --- a/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/timeline.component.ts @@ -2,8 +2,7 @@ import { Component, EventEmitter, OnInit } from '@angular/core'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker'; -import _moment from 'moment'; -import { default as _rollupMoment, Moment } from 'moment'; +import _moment, { default as _rollupMoment, Moment } from 'moment'; import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material/form-field'; import { NgIcon, provideIcons } from "@ng-icons/core"; From 05e45f98c319117a5e4d5c444f5482f15cc05a91 Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Sat, 11 May 2024 17:53:30 +0200 Subject: [PATCH 7/8] Removed weird file and added it to .gitignore --- .gitignore | 4 + .../corn/login/resources/css/styles.css | 1268 ----------------- 2 files changed, 4 insertions(+), 1268 deletions(-) delete mode 100644 auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css diff --git a/.gitignore b/.gitignore index 67f0bfbc..e1ab93ab 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,7 @@ generated #Files from development builds .cache/ + +#Other files + +auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css diff --git a/auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css b/auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css deleted file mode 100644 index b53db571..00000000 --- a/auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css +++ /dev/null @@ -1,1268 +0,0 @@ -/* -! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com -*/ - -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -7. Disable tap highlights on iOS -*/ - -html, -:host { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ - -webkit-tap-highlight-color: transparent; - /* 7 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font-family by default. -2. Use the user's configured `mono` font-feature-settings by default. -3. Use the user's configured `mono` font-variation-settings by default. -4. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - /* 1 */ - font-feature-settings: normal; - /* 2 */ - font-variation-settings: normal; - /* 3 */ - font-size: 1em; - /* 4 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-feature-settings: inherit; - /* 1 */ - font-variation-settings: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -[type='button'], -[type='reset'], -[type='submit'] { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Reset default styling for dialogs. -*/ - -dialog { - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden] { - display: none; -} - -[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - border-radius: 0px; - padding-top: 0.5rem; - padding-right: 0.75rem; - padding-bottom: 0.5rem; - padding-left: 0.75rem; - font-size: 1rem; - line-height: 1.5rem; - --tw-shadow: 0 0 #0000; -} - -[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - border-color: #2563eb; -} - -input::-moz-placeholder, textarea::-moz-placeholder { - color: #6b7280; - opacity: 1; -} - -input::placeholder,textarea::placeholder { - color: #6b7280; - opacity: 1; -} - -::-webkit-datetime-edit-fields-wrapper { - padding: 0; -} - -::-webkit-date-and-time-value { - min-height: 1.5em; -} - -::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { - padding-top: 0; - padding-bottom: 0; -} - -select { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); - background-position: right 0.5rem center; - background-repeat: no-repeat; - background-size: 1.5em 1.5em; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; - color-adjust: exact; -} - -[multiple] { - background-image: initial; - background-position: initial; - background-repeat: unset; - background-size: initial; - padding-right: 0.75rem; - -webkit-print-color-adjust: unset; - color-adjust: unset; -} - -[type='checkbox'],[type='radio'] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - -webkit-print-color-adjust: exact; - color-adjust: exact; - display: inline-block; - vertical-align: middle; - background-origin: border-box; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - color: #2563eb; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - --tw-shadow: 0 0 #0000; -} - -[type='checkbox'] { - border-radius: 0px; -} - -[type='radio'] { - border-radius: 100%; -} - -[type='checkbox']:focus,[type='radio']:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 2px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); -} - -[type='checkbox']:checked,[type='radio']:checked { - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); -} - -[type='radio']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); -} - -[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='checkbox']:indeterminate { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='file'] { - background: unset; - border-color: inherit; - border-width: 0; - border-radius: 0; - padding: 0; - font-size: unset; - line-height: inherit; -} - -[type='file']:focus { - outline: 1px auto -webkit-focus-ring-color; -} - -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -.relative { - position: relative; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -.mb-\[12px\] { - margin-bottom: 12px; -} - -.ml-\[-352px\] { - margin-left: -352px; -} - -.ml-\[2px\] { - margin-left: 2px; -} - -.ml-\[4px\] { - margin-left: 4px; -} - -.ml-auto { - margin-left: auto; -} - -.mr-2 { - margin-right: 0.5rem; -} - -.mt-\[12px\] { - margin-top: 12px; -} - -.mt-\[2px\] { - margin-top: 2px; -} - -.inline-block { - display: inline-block; -} - -.flex { - display: flex; -} - -.inline-flex { - display: inline-flex; -} - -.table { - display: table; -} - -.grid { - display: grid; -} - -.hidden { - display: none; -} - -.h-4 { - height: 1rem; -} - -.h-5 { - height: 1.25rem; -} - -.h-8 { - height: 2rem; -} - -.h-full { - height: 100%; -} - -.h-px { - height: 1px; -} - -.h-screen { - height: 100vh; -} - -.max-h-\[0px\] { - max-height: 0px; -} - -.min-h-\[512px\] { - min-height: 512px; -} - -.min-h-screen { - min-height: 100vh; -} - -.w-5 { - width: 1.25rem; -} - -.w-\[160px\] { - width: 160px; -} - -.w-\[50\%\] { - width: 50%; -} - -.w-full { - width: 100%; -} - -.min-w-\[512px\] { - min-width: 512px; -} - -.min-w-full { - min-width: 100%; -} - -.max-w-\[0px\] { - max-width: 0px; -} - -.max-w-\[968px\] { - max-width: 968px; -} - -.flex-1 { - flex: 1 1 0%; -} - -.flex-grow { - flex-grow: 1; -} - -.cursor-not-allowed { - cursor: not-allowed; -} - -.grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); -} - -.grid-cols-\[196px\2c 1fr\] { - grid-template-columns: 196px 1fr; -} - -.flex-col { - flex-direction: column; -} - -.items-center { - align-items: center; -} - -.justify-center { - justify-content: center; -} - -.justify-between { - justify-content: space-between; -} - -.gap-2 { - gap: 0.5rem; -} - -.gap-4 { - gap: 1rem; -} - -.gap-\[12px\] { - gap: 12px; -} - -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); -} - -.space-y-1 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); -} - -.space-y-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); -} - -.divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); -} - -.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-divide-opacity)); -} - -.whitespace-nowrap { - white-space: nowrap; -} - -.rounded { - border-radius: 0.25rem; -} - -.rounded-full { - border-radius: 9999px; -} - -.rounded-lg { - border-radius: 0.5rem; -} - -.rounded-md { - border-radius: 0.375rem; -} - -.rounded-l-\[32px\] { - border-top-left-radius: 32px; - border-bottom-left-radius: 32px; -} - -.border { - border-width: 1px; -} - -.border-2 { - border-width: 2px; -} - -.border-b { - border-bottom-width: 1px; -} - -.border-solid { - border-style: solid; -} - -.border-corn-accent-600 { - --tw-border-opacity: 1; - border-color: rgb(19 144 59 / var(--tw-border-opacity)); -} - -.border-gray-300 { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); -} - -.border-gray-400 { - --tw-border-opacity: 1; - border-color: rgb(156 163 175 / var(--tw-border-opacity)); -} - -.border-gray-600 { - --tw-border-opacity: 1; - border-color: rgb(75 85 99 / var(--tw-border-opacity)); -} - -.border-yellow-600 { - --tw-border-opacity: 1; - border-color: rgb(202 138 4 / var(--tw-border-opacity)); -} - -.bg-corn-accent-500 { - --tw-bg-opacity: 1; - background-color: rgb(20 161 66 / var(--tw-bg-opacity)); -} - -.bg-gray-200 { - --tw-bg-opacity: 1; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)); -} - -.bg-gray-300 { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - -.bg-gray-400 { - --tw-bg-opacity: 1; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)); -} - -.bg-gray-600 { - --tw-bg-opacity: 1; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)); -} - -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - -.bg-yellow-400 { - --tw-bg-opacity: 1; - background-color: rgb(250 204 21 / var(--tw-bg-opacity)); -} - -.bg-yellow-500 { - --tw-bg-opacity: 1; - background-color: rgb(234 179 8 / var(--tw-bg-opacity)); -} - -.bg-yellowishDark { - --tw-bg-opacity: 1; - background-color: rgb(40 39 39 / var(--tw-bg-opacity)); -} - -.bg-yellowishDark100 { - --tw-bg-opacity: 1; - background-color: rgb(73 66 63 / var(--tw-bg-opacity)); -} - -.px-2 { - padding-left: 0.5rem; - padding-right: 0.5rem; -} - -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} - -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} - -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} - -.py-1 { - padding-top: 0.25rem; - padding-bottom: 0.25rem; -} - -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} - -.py-3 { - padding-top: 0.75rem; - padding-bottom: 0.75rem; -} - -.py-4 { - padding-top: 1rem; - padding-bottom: 1rem; -} - -.pb-4 { - padding-bottom: 1rem; -} - -.pl-\[32px\] { - padding-left: 32px; -} - -.pr-\[32px\] { - padding-right: 32px; -} - -.pt-2 { - padding-top: 0.5rem; -} - -.pt-4 { - padding-top: 1rem; -} - -.text-left { - text-align: left; -} - -.text-center { - text-align: center; -} - -.text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; -} - -.text-5xl { - font-size: 3rem; - line-height: 1; -} - -.text-lg { - font-size: 1.125rem; - line-height: 1.75rem; -} - -.text-sm { - font-size: 0.875rem; - line-height: 1.25rem; -} - -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} - -.font-bold { - font-weight: 700; -} - -.font-medium { - font-weight: 500; -} - -.font-semibold { - font-weight: 600; -} - -.uppercase { - text-transform: uppercase; -} - -.tracking-wider { - letter-spacing: 0.05em; -} - -.text-black { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); -} - -.text-gray-200 { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); -} - -.text-gray-300 { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); -} - -.text-gray-500 { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - -.text-gray-700 { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.text-green-500 { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); -} - -.text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); -} - -.text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -.text-yellow-300 { - --tw-text-opacity: 1; - color: rgb(253 224 71 / var(--tw-text-opacity)); -} - -.placeholder-gray-200::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(229 231 235 / var(--tw-placeholder-opacity)); -} - -.placeholder-gray-200::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(229 231 235 / var(--tw-placeholder-opacity)); -} - -.placeholder-gray-500::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(107 114 128 / var(--tw-placeholder-opacity)); -} - -.placeholder-gray-500::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(107 114 128 / var(--tw-placeholder-opacity)); -} - -.transition-colors { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.duration-200 { - transition-duration: 200ms; -} - -.duration-300 { - transition-duration: 300ms; -} - -.hover\:border-corn-accent-700:hover { - --tw-border-opacity: 1; - border-color: rgb(17 128 53 / var(--tw-border-opacity)); -} - -.hover\:border-yellow-700:hover { - --tw-border-opacity: 1; - border-color: rgb(161 98 7 / var(--tw-border-opacity)); -} - -.hover\:bg-corn-accent-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(19 144 59 / var(--tw-bg-opacity)); -} - -.hover\:bg-gray-300:hover { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - -.hover\:bg-yellow-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(202 138 4 / var(--tw-bg-opacity)); -} - -.hover\:text-gray-800:hover { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} - -.focus\:border-blue-500:focus { - --tw-border-opacity: 1; - border-color: rgb(59 130 246 / var(--tw-border-opacity)); -} - -.focus\:outline-none:focus { - outline: 2px solid transparent; - outline-offset: 2px; -} From ca0ae9ed069f64670847303ae2c116084e7a942e Mon Sep 17 00:00:00 2001 From: Higunio320 Date: Sat, 11 May 2024 18:06:17 +0200 Subject: [PATCH 8/8] Fixes --- .../api/sprint/SprintControllerImpl.java | 6 +++--- .../pages/boards/timeline/day/day.component.ts | 15 +++++---------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java index 79bc0ba0..5212021e 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintControllerImpl.java @@ -123,9 +123,9 @@ public final Page getSprintsBeforeSprint(@RequestParam long spri @Override @GetMapping(value = SPRINTS_BETWEEN_DATES) public final List getSprintsBetweenDates(@RequestParam LocalDate startDate, - @RequestParam LocalDate endDate, - @RequestParam long projectId, - @JwtAuthed User user) { + @RequestParam LocalDate endDate, + @RequestParam long projectId, + @JwtAuthed User user) { return sprintService.getSprintsBetweenDates(startDate, endDate, projectId, user); } diff --git a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts index 9ddbce39..d95fa6f3 100644 --- a/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts +++ b/corn-frontend/src/app/pages/boards/timeline/day/day.component.ts @@ -29,18 +29,17 @@ export class DayComponent implements OnDestroy { color_value: string = '500'; - constructor(private dialog: MatDialog, - private sprintService: SprintService) { - - } - - private _eventEmitter: EventEmitter = new EventEmitter(); hovered = false; $destroy: Subject = new Subject(); + constructor(private dialog: MatDialog, + private sprintService: SprintService) { + + } + @Input() set eventEmitter(emitter: EventEmitter | null) { if (!emitter) { @@ -121,10 +120,6 @@ export class DayComponent implements OnDestroy { if (changed) { this.changeEmitter.emit(); } - - }) } - - }