diff --git a/backend/.idea/workspace.xml b/backend/.idea/workspace.xml index 8976ff7..a1e3896 100644 --- a/backend/.idea/workspace.xml +++ b/backend/.idea/workspace.xml @@ -5,7 +5,16 @@ - + + + + + + + + + + - { + "keyToString": { + "RequestMappingsPanelOrder0": "0", + "RequestMappingsPanelOrder1": "1", + "RequestMappingsPanelWidth0": "75", + "RequestMappingsPanelWidth1": "75", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "WebServerToolWindowFactoryState": "false", + "extract.method.default.visibility": "private", + "git-widget-placeholder": "issue-11-angular-update", + "last_directory_selection": "D:/Programmierprojekte/TimeManager/backend/src/main/java/core/api/models/timemanager", + "last_opened_file_path": "D:/Programmierprojekte/Dicewars/client", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "swagger", + "ts.external.directory.path": "/snap/intellij-idea-ultimate/459/plugins/javascript-impl/jsLanguageServicesImpl/external", + "vue.rearranger.settings.migration": "true" }, - "keyToStringList": { - "DatabaseDriversLRU": [ - "mariadb" + "keyToStringList": { + "DatabaseDriversLRU": [ + "mariadb" ] } -}]]> +} @@ -320,6 +329,11 @@ 202 diff --git a/backend/src/main/java/core/api/models/timemanager/tasks/TaskScope.java b/backend/src/main/java/core/api/models/timemanager/tasks/TaskScope.java index 8a5dd02..f44e314 100644 --- a/backend/src/main/java/core/api/models/timemanager/tasks/TaskScope.java +++ b/backend/src/main/java/core/api/models/timemanager/tasks/TaskScope.java @@ -4,5 +4,7 @@ public enum TaskScope { FINISHED, UNFINISHED, - OVERDUE; + OVERDUE, + UPCOMING, + ACTIVE; } diff --git a/backend/src/main/java/core/repositories/timemanager/TaskRepository.java b/backend/src/main/java/core/repositories/timemanager/TaskRepository.java index 9764f60..19887b4 100644 --- a/backend/src/main/java/core/repositories/timemanager/TaskRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/TaskRepository.java @@ -29,4 +29,7 @@ public interface TaskRepository extends CrudRepository { @Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND t.deadline is NOT NULL AND t.deadline > ?2 AND t.finished = FALSE") List findAllOverdue(String username, LocalDate now); + + @Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND t.startDate IS NOT NULL AND t.startDate > ?2 AND t.finished = FALSE") + List findAllUpcoming(String username, LocalDate now); } diff --git a/backend/src/main/java/core/services/TaskService.java b/backend/src/main/java/core/services/TaskService.java index d55a9e4..ae003fb 100644 --- a/backend/src/main/java/core/services/TaskService.java +++ b/backend/src/main/java/core/services/TaskService.java @@ -109,6 +109,9 @@ public class TaskService { case OVERDUE -> { return taskRepository.findAllOverdue(username, LocalDate.now()); } + case UPCOMING -> { + return taskRepository.findAllUpcoming(username, LocalDate.now()); + } default -> { return new ArrayList<>(); } diff --git a/frontend/src/api/api/task.service.ts b/frontend/src/api/api/task.service.ts index c523119..862453e 100644 --- a/frontend/src/api/api/task.service.ts +++ b/frontend/src/api/api/task.service.ts @@ -98,10 +98,10 @@ export class TaskService { * @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 tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable | Array>; - public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable | Array>>; - public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable | Array>>; - public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE' | 'UPCOMING' | 'ACTIVE', detailed: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable | Array>; + public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE' | 'UPCOMING' | 'ACTIVE', detailed: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable | Array>>; + public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE' | 'UPCOMING' | 'ACTIVE', detailed: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable | Array>>; + public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE' | 'UPCOMING' | 'ACTIVE', detailed: boolean, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { if (scope === null || scope === undefined) { throw new Error('Required parameter scope was null or undefined when calling tasksAllScopeDetailedGet.'); } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 374891d..3a79afa 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -9,6 +9,7 @@ import {TaskDetailOverviewComponent} from "./tasks/task-detail-overview/task-det import {SchedulerComponent} from "./schedules/scheduler/scheduler.component"; import {MissedSchedulesComponent} from "./missed-schedules/missed-schedules.component"; import {OverdueTaskOverviewComponent} from "./overdue-task-overview/overdue-task-overview.component"; +import {UpcomingTaskOverviewComponent} from "./upcoming-task-overview/upcoming-task-overview.component"; const routes: Routes = [ {path: '', component: MainComponent}, @@ -20,7 +21,8 @@ const routes: Routes = [ {path: 'taskgroups/:taskgroupID/tasks/:taskID/schedule', component: SchedulerComponent}, {path: 'taskgroups/:taskgroupID/tasks/:taskID/schedule/:scheduleID', component: SchedulerComponent}, {path: 'reschedule', component: MissedSchedulesComponent}, - {path: 'overdue', component: OverdueTaskOverviewComponent} + {path: 'overdue', component: OverdueTaskOverviewComponent}, + {path: 'upcoming', component: UpcomingTaskOverviewComponent} ]; @NgModule({ diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index 375a529..5c5ef46 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -4,6 +4,7 @@ + diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index e1b297e..eb37d3d 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -72,6 +72,7 @@ import {MatAutocompleteModule} from "@angular/material/autocomplete"; import { MissedSchedulesComponent } from './missed-schedules/missed-schedules.component'; import { MissedScheduleForgetConfirmationDialogComponent } from './missed-schedules/missed-schedule-forget-confirmation-dialog/missed-schedule-forget-confirmation-dialog.component'; import { OverdueTaskOverviewComponent } from './overdue-task-overview/overdue-task-overview.component'; +import { UpcomingTaskOverviewComponent } from './upcoming-task-overview/upcoming-task-overview.component'; @NgModule({ declarations: [ AppComponent, @@ -106,7 +107,8 @@ import { OverdueTaskOverviewComponent } from './overdue-task-overview/overdue-ta ForgottenTaskStartDialogComponent, MissedSchedulesComponent, MissedScheduleForgetConfirmationDialogComponent, - OverdueTaskOverviewComponent + OverdueTaskOverviewComponent, + UpcomingTaskOverviewComponent ], imports: [ BrowserModule, diff --git a/frontend/src/app/tasks/task-editor/task-editor.component.ts b/frontend/src/app/tasks/task-editor/task-editor.component.ts index dd5d4c6..7752773 100644 --- a/frontend/src/app/tasks/task-editor/task-editor.component.ts +++ b/frontend/src/app/tasks/task-editor/task-editor.component.ts @@ -48,6 +48,8 @@ export class TaskEditorComponent implements OnInit { } createTask() { + console.log(this.startDate.value) + console.log(this.endDate.value) this.taskService.tasksTaskgroupIDPut(this.editorData.taskgroupID, { taskName: this.nameCtrl.value, eta: this.etaCtrl.value, @@ -72,8 +74,8 @@ export class TaskEditorComponent implements OnInit { } editTask() { - const startingDate = this.startDate.value.length == 0? null:this.startDate.value.length - const deadline = this.endDate.value.length == 0? null:this.endDate.value.length + const startingDate = this.startDate.value.length == 0? null:this.startDate.value + const deadline = this.endDate.value.length == 0? null:this.endDate.value this.taskService.tasksTaskIDPost(this.editorData.task!.taskID, { taskName: this.nameCtrl.value, eta: this.etaCtrl.value, diff --git a/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.css b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.css new file mode 100644 index 0000000..f6efecf --- /dev/null +++ b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.css @@ -0,0 +1,77 @@ +.container { + margin: 20px auto; + width: 70%; +} + +.spacer { + margin-bottom: 2.5%; +} + + +@media screen and (max-width: 600px) { + .container { + width: 100%; + margin: 20px 10px; + } +} + + +.undecorated-link { + text-decoration: none; + color: black; +} + +.undecorated-link:hover { + color: #3498db; +} + +.originally-planned-container { + border-style: solid; + border-color: #e1e1e1; + border-width: 1px; + margin-top: 10px; + border-radius: 5px; + padding: 10px; + +} + +.reschedule-actions-container { + display: flex; + justify-content: space-between; + flex-direction: row; +} + +.btn-group { + display: inline-block; +} + + +.yellowBtn { + background-color: #f39c12; + color: white; + border-radius: 0; +} + +.greenBtn { + background-color: #00bc8c; + color: white; +} + +.btn-group-item { + border-radius: 0; +} + +.btn-group-itemleft { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group-itemright { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.grayBtn { + background-color: #444444; + color: white; +} diff --git a/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.html b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.html new file mode 100644 index 0000000..149bab2 --- /dev/null +++ b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.html @@ -0,0 +1,24 @@ +
+ + + +

+ + {{taskgroup.taskgroupName}} / + + {{task.taskName}} +

+

ETA: {{task.eta}} Minutes

+

Deadline: {{task.deadline}}

+
+
+ + +
+
+ +
+
+
+
+
diff --git a/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.spec.ts b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.spec.ts new file mode 100644 index 0000000..a7e0c7d --- /dev/null +++ b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UpcomingTaskOverviewComponent } from './upcoming-task-overview.component'; + +describe('UpcomingTaskOverviewComponent', () => { + let component: UpcomingTaskOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [UpcomingTaskOverviewComponent] + }); + fixture = TestBed.createComponent(UpcomingTaskOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.ts b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.ts new file mode 100644 index 0000000..b022b24 --- /dev/null +++ b/frontend/src/app/upcoming-task-overview/upcoming-task-overview.component.ts @@ -0,0 +1,66 @@ +import {Component, OnInit} from '@angular/core'; +import {TaskService, TaskTaskgroupInfo} from "../../api"; +import {NavigationLink} from "../navigation-link-list/navigation-link-list.component"; +import {MatSnackBar} from "@angular/material/snack-bar"; +import {TaskEditorData} from "../tasks/task-editor/TaskEditorData"; +import {TaskEditorComponent} from "../tasks/task-editor/task-editor.component"; +import {MatDialog} from "@angular/material/dialog"; + +@Component({ + selector: 'app-upcoming-task-overview', + templateUrl: './upcoming-task-overview.component.html', + styleUrls: ['./upcoming-task-overview.component.css'] +}) +export class UpcomingTaskOverviewComponent implements OnInit{ + + upcomingTasks: TaskTaskgroupInfo[] = [] + defaultNavigationLinkPath: NavigationLink[] = [ + { + linkText: "Dashboard", + routerLink: ['/'] + }, + { + linkText: "Upcoming Tasks", + routerLink: ["/upcoming"] + } + ] + + constructor(private taskService: TaskService, + private snackbar: MatSnackBar, + private dialog: MatDialog) { + + } + + ngOnInit(): void { + this.taskService.tasksAllScopeDetailedGet("UPCOMING", true).subscribe({ + next: resp => { + this.upcomingTasks = resp as TaskTaskgroupInfo[]; + } + }) + } + + deleteTask(deletedTask: TaskTaskgroupInfo) { + this.taskService.tasksTaskIDDelete(deletedTask.taskID).subscribe({ + next: resp => { + this.upcomingTasks = this.upcomingTasks.filter(task => task.taskID !== deletedTask.taskID); + }, + error: err => { + if(err.status == 403) { + this.snackbar.open("No permissions", "", {duration: 2000}); + } else if(err.status == 404) { + this.snackbar.open("Not found", "", {duration: 2000}); + } else { + this.snackbar.open("Unexpected error", "", {duration: 2000}); + } + } + }) + } + + editTask(editedTask: TaskTaskgroupInfo) { + const taskEditorInfo: TaskEditorData = { + task: editedTask, + taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID + }; + this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"}) + } +} diff --git a/openapi.yaml b/openapi.yaml index 8eaa491..7137880 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -902,6 +902,8 @@ paths: - FINISHED - UNFINISHED - OVERDUE + - UPCOMING + - ACTIVE - name: detailed in: path description: determines whether an detailed response is required or not