diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index 667c85e..8265759 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -208,4 +208,8 @@ public class TaskScheduleService { } return activatedSchedules; } + + public void deleteSchedules(List taskSchedules) { + scheduleRepository.deleteAll(taskSchedules); + } } diff --git a/backend/src/main/java/core/services/TaskService.java b/backend/src/main/java/core/services/TaskService.java index d80c784..c3bf170 100644 --- a/backend/src/main/java/core/services/TaskService.java +++ b/backend/src/main/java/core/services/TaskService.java @@ -2,6 +2,7 @@ package core.services; import core.api.models.timemanager.tasks.TaskFieldInfo; import core.api.models.timemanager.tasks.TaskScope; +import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.Task; import core.entities.timemanager.Taskgroup; import core.repositories.timemanager.TaskRepository; @@ -103,21 +104,20 @@ public class TaskService { task.finish(); taskRepository.save(task); - /*List removedBasicTaskSchedules = new LinkedList<>(); - for(BasicTaskSchedule basicTaskSchedule : task.getBasicTaskSchedules()) { + + List removedBasicTaskSchedules = new LinkedList<>(); + for(AbstractSchedule basicTaskSchedule : task.getBasicTaskSchedules()) { if(basicTaskSchedule.getStartTime() == null) { removedBasicTaskSchedules.add(basicTaskSchedule); - } else if(basicTaskSchedule.getFinishedTime() == null) { + } else if(basicTaskSchedule.getStopTime() == null) { ServiceResult result = taskScheduleService.stopSchedule(basicTaskSchedule, true); System.out.println(result); } } - for(BasicTaskSchedule deletedTaskSchedule: removedBasicTaskSchedules) { - task.getBasicTaskSchedules().remove(deletedTaskSchedule); - taskRepository.save(task); - taskScheduleService.deleteBasicSchedule(deletedTaskSchedule); - }*/ + task.getBasicTaskSchedules().removeAll(removedBasicTaskSchedules); + taskRepository.save(task); + taskScheduleService.deleteSchedules(removedBasicTaskSchedules); } public List loadAllTasks(String username, TaskScope scope) { diff --git a/backend/src/test/java/core/tasks/TaskServiceTest.java b/backend/src/test/java/core/tasks/TaskServiceTest.java index 0d30d8c..ede0e93 100644 --- a/backend/src/test/java/core/tasks/TaskServiceTest.java +++ b/backend/src/test/java/core/tasks/TaskServiceTest.java @@ -2,6 +2,7 @@ package core.tasks; import core.api.models.timemanager.tasks.TaskFieldInfo; import core.api.models.timemanager.tasks.TaskScope; +import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.Task; import core.entities.timemanager.Taskgroup; import core.repositories.timemanager.TaskRepository; @@ -43,7 +44,8 @@ public class TaskServiceTest { @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void createTask() { //Situation 1: Task with that name already exists in a taskgroup @@ -85,7 +87,8 @@ public class TaskServiceTest { @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void getTaskPermissions() { //Situation 1: correct task and username @@ -110,7 +113,8 @@ public class TaskServiceTest { @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void editTask() { //Situation 1: Nothing is updated @@ -182,7 +186,8 @@ public class TaskServiceTest { @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void deleteTask() { for(long i=1; i<=15; i++) { @@ -194,7 +199,8 @@ public class TaskServiceTest { @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void clearTasks() { //Situation 1: Delete from taskgroup with no tasks @@ -212,7 +218,8 @@ public class TaskServiceTest { @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void finishTask() { taskService.finishTask(entityManager.find(Task.class, 1L)); @@ -220,12 +227,14 @@ public class TaskServiceTest { taskService.finishTask(entityManager.find(Task.class, 2L)); assertTrue(entityManager.find(Task.class, 1L).isFinished()); + assertThat(entityManager.find(BasicTaskSchedule.class, 2L)).isNull(); } @Test @SqlGroup({ @Sql("classpath:taskgroupRepositoryTestEntries.sql"), - @Sql("classpath:taskRepositoryEntries.sql") + @Sql("classpath:taskRepositoryEntries.sql"), + @Sql("classpath:basicScheduleEntries.sql") }) void loadAllTasks() { //Situation 1: No tasks existing diff --git a/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts b/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts index 2acf67c..5378df5 100644 --- a/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts +++ b/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts @@ -5,6 +5,12 @@ import {TaskOverviewComponent} from "../task-overview/task-overview.component"; import {MatDialog} from "@angular/material/dialog"; import {ForgottenTaskStartDialogComponent} from "../forgotten-task-start-dialog/forgotten-task-start-dialog.component"; +export interface StopActiveScheduleEmitterInfo { + stopactiveScheduleResponse: StopActiveScheduleInfo, + finish: boolean, + taskID: number +} + @Component({ selector: 'app-active-schedule', templateUrl: './active-schedule.component.html', @@ -17,7 +23,7 @@ export class ActiveScheduleComponent implements OnInit{ currentTime: number = 0; displayTime: string = "00:00:00" - @Output('onStopTask') scheduleStopEmitter = new EventEmitter; + @Output('onStopTask') scheduleStopEmitter = new EventEmitter; @Output('registerForgotten') registerForgottenEmitter = new EventEmitter constructor(private scheduleService: ScheduleService, @@ -60,8 +66,12 @@ export class ActiveScheduleComponent implements OnInit{ this.scheduleService.schedulesScheduleIDStopFinishPost(this.activeSchedule!.scheduleID, finish).subscribe({ next: resp => { this.scheduleStopEmitter.emit({ - schedule: this.activeSchedule!, - workedMinutes: resp.workTime + stopactiveScheduleResponse: { + schedule: this.activeSchedule!, + workedMinutes: resp.workTime + }, + finish: finish, + taskID: this.activeSchedule!.task.taskID }) console.log(resp.workTime) this.activeSchedule = undefined diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 1e110fb..206f37c 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -39,12 +39,12 @@
- +
- +
diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 0fec900..6bb25cf 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -6,10 +6,10 @@ import { TaskOverviewInfo, TaskScheduleStopResponse } from "../../api"; -import {ActiveScheduleComponent} from "./active-schedule/active-schedule.component"; +import {ActiveScheduleComponent, StopActiveScheduleEmitterInfo} from "./active-schedule/active-schedule.component"; import {StopActiveScheduleInfo} from "./active-schedule/StopActiveScheduleInfo"; -import {TaskOverviewComponent} from "./task-overview/task-overview.component"; -import {TaskOverviewData} from "./taskgroup-overview/taskgroup-overview.component"; +import {TaskCreationEmitterInfo, TaskOverviewComponent} from "./task-overview/task-overview.component"; +import {TaskgroupOverviewComponent, TaskOverviewData} from "./taskgroup-overview/taskgroup-overview.component"; @Component({ selector: 'app-dashboard', @@ -26,6 +26,7 @@ export class DashboardComponent implements OnInit{ selectedTaskgroupID: number | undefined @ViewChild('activeSchedule') activeScheduleComponent: ActiveScheduleComponent | undefined + @ViewChild('taskgroupOverview') taskroupOverviewComponent: TaskgroupOverviewComponent | undefined constructor(private scheduleService: ScheduleService, private historyService: HistoryService) { } @@ -59,9 +60,13 @@ export class DashboardComponent implements OnInit{ } - stopedTask(stopActiveScheduleInfo: StopActiveScheduleInfo) { - this.workedMinutesToday += stopActiveScheduleInfo.workedMinutes; - this.schedules = this.schedules.filter(schedule => schedule.scheduleID !== stopActiveScheduleInfo.schedule.scheduleID); + stopedTask(stopActiveScheduleInfo: StopActiveScheduleEmitterInfo) { + this.workedMinutesToday += stopActiveScheduleInfo.stopactiveScheduleResponse.workedMinutes; + this.schedules = this.schedules.filter(schedule => schedule.scheduleID !== stopActiveScheduleInfo.stopactiveScheduleResponse.schedule.scheduleID); + + if(stopActiveScheduleInfo.finish) { + this.taskroupOverviewComponent!.finishTask(stopActiveScheduleInfo.taskID); + } } @@ -73,16 +78,24 @@ export class DashboardComponent implements OnInit{ } onStartTaskNow(schedule: ScheduleInfo) { - this.activeScheduleComponent?.activateSchedule(schedule) + this.activeScheduleComponent?.activateSchedule(schedule); + this.selectedTaskgroupID = undefined } onFinishTask(task: TaskOverviewInfo) { this.activeScheduleComponent?.finishTaskByOverview(task); this.schedules = this.schedules.filter(schedule => schedule.task.taskID !== task.taskID) + this.taskroupOverviewComponent!.finishTask(task.taskID); + this.tasks = []; + this.selectedTaskgroupID = undefined; } registerForgotten(taskScheduleStopResponse: TaskScheduleStopResponse) { this.workedMinutesToday += taskScheduleStopResponse.workTime } + + onCreatedTask(taskCreationInfo: TaskCreationEmitterInfo) { + this.taskroupOverviewComponent!.onCreateTask(taskCreationInfo); + } } diff --git a/frontend/src/app/dashboard/task-overview/task-overview.component.html b/frontend/src/app/dashboard/task-overview/task-overview.component.html index 8ed063e..f91fe12 100644 --- a/frontend/src/app/dashboard/task-overview/task-overview.component.html +++ b/frontend/src/app/dashboard/task-overview/task-overview.component.html @@ -1,14 +1,17 @@ - - - -

{{task.taskName}}

- -

ETA: {{task.activeTime}} / {{task.eta}}

-

Limit: {{task.limit}}

-
- - - - - -
+
+ + + +

{{task.taskName}}

+ +

ETA: {{task.activeTime}} / {{task.eta}}

+

Limit: {{task.limit}}

+
+ + + + + +
+ +
diff --git a/frontend/src/app/dashboard/task-overview/task-overview.component.ts b/frontend/src/app/dashboard/task-overview/task-overview.component.ts index c0d491b..1b6ae7d 100644 --- a/frontend/src/app/dashboard/task-overview/task-overview.component.ts +++ b/frontend/src/app/dashboard/task-overview/task-overview.component.ts @@ -1,10 +1,21 @@ import {Component, EventEmitter, Input, Output} from '@angular/core'; -import {BasicScheduleEntityInfo, ScheduleInfo, ScheduleService, TaskOverviewInfo, TaskService} from "../../../api"; +import { + BasicScheduleEntityInfo, + ScheduleInfo, + ScheduleService, + TaskOverviewInfo, + TaskService, + TaskShortInfo +} from "../../../api"; 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"; +export interface TaskCreationEmitterInfo { + taskgroupID: number, + task: TaskOverviewInfo +} @Component({ selector: 'app-task-overview', templateUrl: './task-overview.component.html', @@ -16,6 +27,7 @@ export class TaskOverviewComponent { @Input() taskgroupID: number | undefined @Output('onStartNow') startNowEmitter: EventEmitter = new EventEmitter(); @Output('onFinished') finishedEmitter: EventEmitter = new EventEmitter(); + @Output('onCreated') creationEmitter: EventEmitter = new EventEmitter(); constructor(private scheduleService: ScheduleService, private snackbar: MatSnackBar, @@ -68,14 +80,19 @@ export class TaskOverviewComponent { const dialogRef = this.dialog.open(TaskEditorComponent, {data: editorData, width: "600px"}) dialogRef.afterClosed().subscribe(res => { if(res != undefined) { - this.tasks.push({ + const taskOverviewInfo = { taskID: res.taskID, eta: res.eta, limit: res.deadline, taskName: res.taskName, activeTime: 0, overdue: res.overdue + } + this.creationEmitter.emit({ + task: taskOverviewInfo, + taskgroupID: this.taskgroupID! }) + } }) } diff --git a/frontend/src/app/dashboard/taskgroup-overview/taskgroup-overview.component.ts b/frontend/src/app/dashboard/taskgroup-overview/taskgroup-overview.component.ts index c17aa39..5c9379c 100644 --- a/frontend/src/app/dashboard/taskgroup-overview/taskgroup-overview.component.ts +++ b/frontend/src/app/dashboard/taskgroup-overview/taskgroup-overview.component.ts @@ -3,10 +3,8 @@ import {MatIconModule} from "@angular/material/icon"; import {MatButtonModule} from "@angular/material/button"; import {MatTreeFlatDataSource, MatTreeFlattener, MatTreeModule} from "@angular/material/tree"; import {FlatTreeControl} from "@angular/cdk/tree"; -import {RecursiveTaskgroupInfo, TaskgroupService, TaskOverviewInfo} from "../../../api"; -import {TaskOverviewComponent} from "../task-overview/task-overview.component"; - - +import {RecursiveTaskgroupInfo, TaskgroupService, TaskOverviewInfo, TaskShortInfo} from "../../../api"; +import {TaskCreationEmitterInfo, TaskOverviewComponent} from "../task-overview/task-overview.component"; /** Flat node with expandable and level information */ @@ -24,6 +22,7 @@ export interface TaskOverviewData { tasks: TaskOverviewInfo[], taskgroupID: number } + @Component({ selector: 'app-taskgroup-overview', templateUrl: './taskgroup-overview.component.html', @@ -78,4 +77,39 @@ export class TaskgroupOverviewComponent { taskgroupID: taskgroupID }) } + + finishTask(taskID: number) { + let taskgroupQueue : RecursiveTaskgroupInfo[] = this.dataSource.data.slice(); + while(taskgroupQueue.length > 0) { + const currentTaskgroup = taskgroupQueue.pop()!; + const searchedTask = currentTaskgroup.activeTasks.find(searchedTask => searchedTask.taskID === taskID); + if(searchedTask == undefined) { + currentTaskgroup.childTaskgroups.forEach(childTask => { + taskgroupQueue.push(childTask); + }) + } else { + currentTaskgroup.activeTasks = currentTaskgroup.activeTasks.filter(taskFilter => taskFilter.taskID !== searchedTask.taskID); + } + } + } + + private findTaskgroup(taskgroupID: number) { + let taskgroupQueue : RecursiveTaskgroupInfo[] = this.dataSource.data.slice(); + while(taskgroupQueue.length > 0) { + const currentTaskgroup = taskgroupQueue.pop()!; + if(currentTaskgroup.taskgroupID === taskgroupID) { + return currentTaskgroup; + } else { + currentTaskgroup.childTaskgroups.forEach(childgroup => taskgroupQueue.push(childgroup)); + } + } + return undefined + } + + onCreateTask(taskCreationInfo: TaskCreationEmitterInfo) { + const taskgroup: RecursiveTaskgroupInfo | undefined = this.findTaskgroup(taskCreationInfo.taskgroupID); + if(taskgroup != undefined) { + taskgroup.activeTasks.push(taskCreationInfo.task); + } + } }