diff --git a/backend/Dockerfile b/backend/Dockerfile index ca6c162..7bb20d7 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,9 +1,15 @@ +FROM maven:3.8.1-openjdk-17-slim AS build +COPY src /home/app/src +COPY pom.xml /home/app +RUN mvn -f /home/app/pom.xml clean test package + + FROM openjdk:17-jdk-alpine RUN addgroup -S spring && adduser -S spring -G spring USER spring:spring -ARG JAR_FILE=target/*.jar -COPY ${JAR_FILE} app.jar - +#ARG JAR_FILE=target/*.jar +#COPY ${JAR_FILE} app.jar +COPY --from=build /home/app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index 8cd2d83..3949347 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -75,10 +75,18 @@ public class ScheduleController { if(scheduleFieldInfo instanceof BasicScheduleFieldInfo) { ServiceResult scheduleResult = taskScheduleService.scheduleBasic(permissionResult.getResult(), (BasicScheduleFieldInfo) scheduleFieldInfo); + if(scheduleResult.getExitCode() == ServiceExitCode.INVALID_OPERATION) { + return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); + } return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); } else if(scheduleFieldInfo instanceof AdvancedScheduleFieldInfo) { ServiceResult scheduleResult = taskScheduleService.scheduleAdvanced(permissionResult.getResult(), (AdvancedScheduleFieldInfo) scheduleFieldInfo); - return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); + if(scheduleResult.getResult() != null) { + return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); + } else { + return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); + } + } else { return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); } diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java index 3c35886..14facaa 100644 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/TaskScheduleStopResponse.java @@ -2,17 +2,17 @@ package core.api.models.timemanager.taskSchedule; public class TaskScheduleStopResponse { - private int activeTime; + private int workTime; public TaskScheduleStopResponse(int activeTime) { - this.activeTime = activeTime; + this.workTime = activeTime; } - public int getActiveTime() { - return activeTime; + public int getWorkTime() { + return workTime; } - public void setActiveTime(int activeTime) { - this.activeTime = activeTime; + public void setWorkTime(int workTime) { + this.workTime = workTime; } } diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java index 636b381..245140e 100644 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/scheduleInfos/BasicScheduleFieldInfo.java @@ -8,6 +8,7 @@ import java.time.LocalDate; public class BasicScheduleFieldInfo extends ScheduleFieldInfo{ @NotNull + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") private LocalDate scheduleDate; public BasicScheduleFieldInfo(LocalDate localDate) { diff --git a/backend/src/main/java/core/api/models/timemanager/tasks/TaskFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/tasks/TaskFieldInfo.java index d4f2cf9..1cf7335 100644 --- a/backend/src/main/java/core/api/models/timemanager/tasks/TaskFieldInfo.java +++ b/backend/src/main/java/core/api/models/timemanager/tasks/TaskFieldInfo.java @@ -1,5 +1,6 @@ package core.api.models.timemanager.tasks; +import com.fasterxml.jackson.annotation.JsonFormat; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotBlank; @@ -11,7 +12,11 @@ public class TaskFieldInfo { @Length(max = 255) private String taskName; private int eta; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") private LocalDate startDate; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") private LocalDate deadline; public TaskFieldInfo() { diff --git a/backend/src/main/java/core/api/models/timemanager/tasks/TaskOverviewInfo.java b/backend/src/main/java/core/api/models/timemanager/tasks/TaskOverviewInfo.java index d4d701b..80a5918 100644 --- a/backend/src/main/java/core/api/models/timemanager/tasks/TaskOverviewInfo.java +++ b/backend/src/main/java/core/api/models/timemanager/tasks/TaskOverviewInfo.java @@ -1,8 +1,11 @@ package core.api.models.timemanager.tasks; +import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.entities.timemanager.Task; +import core.entities.timemanager.Taskgroup; import java.time.LocalDate; +import java.util.List; public class TaskOverviewInfo { @@ -13,6 +16,7 @@ public class TaskOverviewInfo { private LocalDate limit; private boolean overdue; + public TaskOverviewInfo(Task task) { this.taskID = task.getTaskID(); this.taskName = task.getTaskName(); diff --git a/backend/src/main/java/core/entities/timemanager/Taskgroup.java b/backend/src/main/java/core/entities/timemanager/Taskgroup.java index 6fc92e1..bdf42ca 100644 --- a/backend/src/main/java/core/entities/timemanager/Taskgroup.java +++ b/backend/src/main/java/core/entities/timemanager/Taskgroup.java @@ -92,11 +92,13 @@ public class Taskgroup { public static List getAncestorList(Taskgroup taskgroup) { List ancestors = new ArrayList<>(); Taskgroup currentTaskgroup = taskgroup; + ancestors.add(taskgroup); while(currentTaskgroup.parent != null) { ancestors.add(currentTaskgroup.parent); currentTaskgroup = currentTaskgroup.parent; } - //ancestors.add(taskgroup); + + Collections.reverse(ancestors); return ancestors; } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index 3f970a6..667c85e 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -96,6 +96,9 @@ public class TaskScheduleService { } public void deleteSchedule(AbstractSchedule schedule) { + schedule.getTask().getBasicTaskSchedules().remove(schedule); + schedule.setTask(null); + scheduleRepository.save(schedule); scheduleRepository.delete(schedule); } diff --git a/frontend/src/api/model/taskOverviewInfo.ts b/frontend/src/api/model/taskOverviewInfo.ts index 90f3cc1..b8a681c 100644 --- a/frontend/src/api/model/taskOverviewInfo.ts +++ b/frontend/src/api/model/taskOverviewInfo.ts @@ -3,15 +3,16 @@ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * * The version of the OpenAPI document: 1.0 - * + * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech * Do not edit the class manually. */ +import { TaskgroupEntityInfo } from './taskgroupEntityInfo'; -export interface TaskOverviewInfo { +export interface TaskOverviewInfo { /** * internal id of task */ diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 7c0a94c..31b612f 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -11,6 +11,7 @@ import {MissedSchedulesComponent} from "./missed-schedules/missed-schedules.comp import {OverdueTaskOverviewComponent} from "./overdue-task-overview/overdue-task-overview.component"; import {UpcomingTaskOverviewComponent} from "./upcoming-task-overview/upcoming-task-overview.component"; import {ActiveTaskOverviewComponent} from "./active-task-overview/active-task-overview.component"; +import {DraggableSchedulerComponent} from "./schedules/draggable-scheduler/draggable-scheduler.component"; const routes: Routes = [ {path: '', component: MainComponent}, @@ -24,7 +25,8 @@ const routes: Routes = [ {path: 'reschedule', component: MissedSchedulesComponent}, {path: 'overdue', component: OverdueTaskOverviewComponent}, {path: 'upcoming', component: UpcomingTaskOverviewComponent}, - {path: 'active', component: ActiveTaskOverviewComponent} + {path: 'active', component: ActiveTaskOverviewComponent}, + {path: 'scheduler', component: DraggableSchedulerComponent} ]; @NgModule({ diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index c242a74..ab245f6 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 807766c..24254ec 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -79,6 +79,7 @@ import {NgxMaterialTimepickerModule} from "ngx-material-timepicker"; import { DateTimePickerComponent } from './date-time-picker/date-time-picker.component'; import {MatSliderModule} from "@angular/material/slider"; import {MatLegacySliderModule} from "@angular/material/legacy-slider"; +import { DraggableSchedulerComponent } from './schedules/draggable-scheduler/draggable-scheduler.component'; @NgModule({ declarations: [ AppComponent, @@ -117,7 +118,8 @@ import {MatLegacySliderModule} from "@angular/material/legacy-slider"; UpcomingTaskOverviewComponent, ActiveTaskOverviewComponent, AdvancedSchedulerComponent, - DateTimePickerComponent + DateTimePickerComponent, + DraggableSchedulerComponent, ], imports: [ BrowserModule, diff --git a/frontend/src/app/dashboard/active-schedule/active-schedule.component.html b/frontend/src/app/dashboard/active-schedule/active-schedule.component.html index a7d1ee1..ff04003 100644 --- a/frontend/src/app/dashboard/active-schedule/active-schedule.component.html +++ b/frontend/src/app/dashboard/active-schedule/active-schedule.component.html @@ -10,7 +10,7 @@ {{taskgroupPath.taskgroupName}} / -

Running for {{displayTime}}

+

Running for {{displayTime}}

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 cd36f86..2acf67c 100644 --- a/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts +++ b/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts @@ -63,6 +63,7 @@ export class ActiveScheduleComponent implements OnInit{ schedule: this.activeSchedule!, workedMinutes: resp.workTime }) + console.log(resp.workTime) this.activeSchedule = undefined } }) diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index d3a1283..0fec900 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -18,7 +18,7 @@ import {TaskOverviewData} from "./taskgroup-overview/taskgroup-overview.componen }) export class DashboardComponent implements OnInit{ - missedSchedules: boolean = true + missedSchedules: boolean = false schedules: ScheduleInfo[] = [] workedMinutesToday: number = 0 diff --git a/frontend/src/app/navigation-link-list/navigation-link-list.component.ts b/frontend/src/app/navigation-link-list/navigation-link-list.component.ts index 8387aee..21d6d78 100644 --- a/frontend/src/app/navigation-link-list/navigation-link-list.component.ts +++ b/frontend/src/app/navigation-link-list/navigation-link-list.component.ts @@ -11,6 +11,11 @@ export interface NavigationLink { styleUrls: ['./navigation-link-list.component.css'] }) export class NavigationLinkListComponent implements OnInit{ + resetComponent(defaultNavigationLinkPath: NavigationLink[]) { + this.navigationLinks = defaultNavigationLinkPath; + console.log("Navigation Links: ") + console.log(this.navigationLinks) + } @@ -27,7 +32,10 @@ export class NavigationLinkListComponent implements OnInit{ } if(this.navigationLinks.find(searchedLink => searchedLink.linkText === linkText) === undefined) { + console.log("Test") this.navigationLinks.push(navigationLink); + } else { + console.log(linkText) } } diff --git a/frontend/src/app/overdue-task-overview/overdue-task-overview.component.html b/frontend/src/app/overdue-task-overview/overdue-task-overview.component.html index 9fd9445..94a2aab 100644 --- a/frontend/src/app/overdue-task-overview/overdue-task-overview.component.html +++ b/frontend/src/app/overdue-task-overview/overdue-task-overview.component.html @@ -4,9 +4,9 @@

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

diff --git a/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts b/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts index f3c81e7..473ff71 100644 --- a/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts +++ b/frontend/src/app/schedules/basic-scheduler/basic-scheduler.component.ts @@ -9,6 +9,7 @@ import { } from "../../../api"; import {MatSnackBar} from "@angular/material/snack-bar"; import {Router} from "@angular/router"; +import * as moment from "moment"; @Component({ selector: 'app-basic-scheduler', @@ -36,7 +37,7 @@ export class BasicSchedulerComponent implements OnChanges{ if(this.task != undefined) { if(this.scheduleEntityInfo == undefined) { this.scheduleService.schedulesTaskIDBasicPut(this.task.taskID, { - scheduleDate: this.dateCtrl.value + scheduleDate: moment(this.dateCtrl.value).format('YYYY-MM-DDTHH:mm:ss.SSSZ') }).subscribe({ next: resp => { this.scheduleEmitter.emit(resp as BasicScheduleInfo); @@ -44,7 +45,7 @@ export class BasicSchedulerComponent implements OnChanges{ }) } else { this.scheduleService.schedulesScheduleIDBasicPost(this.scheduleEntityInfo!.scheduleID, { - scheduleDate: this.dateCtrl.value + scheduleDate: moment(this.dateCtrl.value).format('YYYY-MM-DDTHH:mm:ss.SSSZ') }).subscribe({ next: resp => { this.router.navigateByUrl("/taskgroups/" + this.taskgroup!.taskgroupID + "/tasks/" + this.task!.taskID); diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.css b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.css new file mode 100644 index 0000000..bbd0712 --- /dev/null +++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.css @@ -0,0 +1,60 @@ +.container { + margin: 20px auto; + width: 80%; +} + +.spacer { + margin-bottom: 2.5%; +} + + +@media screen and (max-width: 600px) { + .container { + width: 100%; + margin: 20px 10px; + } +} + +.schedule-header { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +} + +.long-form { + width: 100%; +} + +.taskgroup-overview { + width: 90%; + display: inline-block; +} + +app-task-overview { + margin-top: 20px; +} + +::ng-deep .mat-mdc-list-base { + --mdc-list-list-item-label-text-color: black +} + +::ng-deep .mat-mdc-list-base .taskgroup-btn, ::ng-deep .mat-mdc-list-base .taskgroup-last-btn { + --mdc-list-list-item-label-text-color: black +} + +.task-card { + background-color: #f3f3f3; + border: 0; + line-height: 4em; +} + + +.lightBlueBtn { + background-color: #3498db; + color: white; +} + +::ng-deep .cal-event-title { + +} diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.html b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.html new file mode 100644 index 0000000..3e1412a --- /dev/null +++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.html @@ -0,0 +1,54 @@ + +
+ + +
+

Monday, {{ viewDate | calendarDate:(view + 'ViewTitle'):'en':1 }}

+ + Schedule Strategy + + Basic + + Advanced + + +
+
+
+ + +
+
+
+ + + +
+ +
+ +
+ +
+ + +
+ + +
diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.spec.ts b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.spec.ts new file mode 100644 index 0000000..786eca5 --- /dev/null +++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DraggableSchedulerComponent } from './draggable-scheduler.component'; + +describe('DraggableSchedulerComponent', () => { + let component: DraggableSchedulerComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [DraggableSchedulerComponent] + }); + fixture = TestBed.createComponent(DraggableSchedulerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.ts b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.ts new file mode 100644 index 0000000..23e6ac5 --- /dev/null +++ b/frontend/src/app/schedules/draggable-scheduler/draggable-scheduler.component.ts @@ -0,0 +1,285 @@ +import {Component, ViewChild} from '@angular/core'; +import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component"; +import { + AdvancedScheduleInfo, + BasicScheduleInfo, + ScheduleInfo, + ScheduleService, + TaskEntityInfo, + TaskgroupEntityInfo, + TaskOverviewInfo, TaskShortInfo +} from "../../../api"; +import {Subject} from "rxjs"; +import {CalendarEvent, CalendarEventAction, CalendarEventTimesChangedEvent, CalendarView} from "angular-calendar"; +import {TaskOverviewData} from "../../dashboard/taskgroup-overview/taskgroup-overview.component"; +import {EventColor} from "calendar-utils"; +import * as moment from "moment"; +import {Router} from "@angular/router"; + +const colors: Record = { + red: { + primary: '#ad2121', + secondary: '#FAE3E3', + }, + blue: { + primary: '#1e90ff', + secondary: '#D1E8FF', + }, + yellow: { + primary: '#e3bc08', + secondary: '#FDF1BA', + }, +}; +@Component({ + selector: 'app-draggable-scheduler', + templateUrl: './draggable-scheduler.component.html', + styleUrls: ['./draggable-scheduler.component.css'], + styles: [ + ` + h3 { + margin: 0 0 10px; + } + + pre { + background-color: #f5f5f5; + padding: 15px; + } + `, + ], +}) +export class DraggableSchedulerComponent { + defaultNavigationLinkPath: NavigationLink[] = [ + { + linkText: "Dashboard", + routerLink: ['/'] + }, + { + linkText: "Taskgroups", + routerLink: ["/taskgroups"] + } + ] + taskgroups: TaskgroupEntityInfo[] = [] + taskgroup: TaskgroupEntityInfo | undefined + taskgroupPath: TaskgroupEntityInfo[] = [] + taskgroupID: number = -1; + scheduleID: number = -1; + editedSchedule: ScheduleInfo | undefined + @ViewChild('navLinkList') navLinkListComponent: NavigationLinkListComponent | undefined + + task: TaskEntityInfo | undefined + scheduleStrategy: number = 1 + + + /**************************************************/ + //Calendar-Stuff + /**************************************************/ + view: CalendarView = CalendarView.Week; + viewDate = new Date(); + daysInWeek = 7; + refresh: Subject = new Subject() + events: CalendarEvent[] = [] + + actions: CalendarEventAction[] = [ + { + label: '', + a11yLabel: 'Edit', + onClick: ({ event }: { event: CalendarEvent }): void => { + this.eventClicked('Edit', event) + }, + }, + { + label: '', + a11yLabel: 'Delete', + onClick: ({ event }: { event: CalendarEvent }): void => { + this.eventClicked('Delete', event); + }, + }, + ] + + tasks: CalendarEvent[] = [] + selectedTaskgroupID: number | undefined + + constructor(private scheduleService: ScheduleService, + private router: Router) { + } + + ngOnInit() { + this.scheduleService.schedulesGet().subscribe({ + next: resp => { + resp.forEach(schedule => { + if(schedule.scheduleType == 'BASIC') { + const basicSchedule = schedule as BasicScheduleInfo + this.events.push({ + title: this.computeTaskPath(schedule.taskgroupPath, schedule.task), + color: colors['red'], + start: new Date(basicSchedule.scheduleDate), + actions: this.actions, + allDay: true, + draggable: true, + resizable: { + beforeStart: true, + afterEnd: true + }, + meta: { + taskID: schedule.task.taskID, + scheduleID: schedule.scheduleID, + taskgroupID: schedule.taskgroupPath[0].taskgroupID + }, + + }) + } else { + const advancedSchedule = schedule as AdvancedScheduleInfo + this.events.push({ + title: this.computeTaskPath(schedule.taskgroupPath, schedule.task), + color: colors['red'], + cssClass: 'test', + start: new Date(advancedSchedule.scheduleStartTime), + end: new Date(advancedSchedule.scheduleStopTime), + actions: this.actions, + draggable: true, + resizable: { + beforeStart: true, + afterEnd: true + }, + meta: { + taskID: schedule.task.taskID, + scheduleID: schedule.scheduleID, + taskgroupID: schedule.taskgroupPath[0].taskgroupID + }, + }) + } + }); + console.log(this.events) + this.refresh.next(); + } + }) + } + + onSelectTaskgroup(taskOverviewData: TaskOverviewData) { + this.tasks = []; + taskOverviewData.tasks.forEach(task => { + this.tasks.push({ + title: task.taskName, + color: colors['yellow'], + start: new Date(), + draggable: true, + cssClass: 'test', + resizable: { + beforeStart: true, + afterEnd: true + }, + meta: { + taskID: task.taskID, + scheduleID: undefined, + taskgroupID: taskOverviewData.taskgroupID + }, + actions: this.actions + }) + }) + this.selectedTaskgroupID = taskOverviewData.taskgroupID; + } + + + externalDrop(event: CalendarEvent) { + if (this.tasks.indexOf(event) === -1) { + this.events = this.events.filter((iEvent) => iEvent !== event); + this.tasks.push(event); + } + } + + eventDropped({ + event, + newStart, + newEnd, + allDay, + }: CalendarEventTimesChangedEvent): void { + const externalIndex = this.tasks.indexOf(event); + if (typeof allDay !== 'undefined') { + event.allDay = allDay; + } + if (externalIndex > -1) { + this.tasks.splice(externalIndex, 1); + this.events.push(event); + } + + event.start = newStart; + if (newEnd) { + event.end = newEnd; + } + this.events = [...this.events]; + + if(externalIndex > -1) { + //Create new schedule as a new event was dropped + if(event.allDay) { + this.scheduleService.schedulesTaskIDBasicPut(event.meta.taskID,{ + scheduleDate: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ') + }).subscribe({ + next: resp => { + event.meta.scheduleID = resp.scheduleID; + event.color = colors['red']; + event.title = this.computeTaskPath(resp.taskgroupPath, resp.task) + } + }) + } else { + console.log("Start: " + event.start); + console.log("End: " + event.end); + if(event.end == undefined) { + event.end = moment(event.start).add(30, 'm').toDate() + } + this.scheduleService.schedulesTaskIDAdvancedPut(event.meta.taskID, { + scheduleStartTime: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + scheduleStopTime: moment(event.end).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + }).subscribe({ + next: resp => { + event.meta.scheduleID = resp.scheduleID; + event.color = colors['red']; + event.title = this.computeTaskPath(resp.taskgroupPath, resp.task) + } + }) + } + } else { + if(event.allDay) { + this.scheduleService.schedulesScheduleIDBasicPost(event.meta.scheduleID,{ + scheduleDate: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ') + }).subscribe({ + next: resp => { + console.log("Updated") + } + }) + } else { + this.scheduleService.schedulesScheduleIDAdvancedPost(event.meta.scheduleID, { + scheduleStartTime: moment(event.start).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + scheduleStopTime: moment(event.end).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + }).subscribe({ + next: resp => { + console.log("Updated") + } + }) + } + } + } + + computeTaskPath(taskgroupPath: TaskgroupEntityInfo[], task: TaskShortInfo | TaskEntityInfo) { + let result = ""; + taskgroupPath.forEach(taskgroupPathPart => { + result += taskgroupPathPart.taskgroupName + "/" + }); + result += task!.taskName + return result; + } + + eventClicked(action: string, event: CalendarEvent): void { + if(action == 'Click') { + this.router.navigateByUrl("/taskgroups/" + event.meta.taskgroupID + "/tasks/" + event.meta.taskID); + } else if(action == 'Edit') { + this.router.navigateByUrl("/taskgroups/" + event.meta.taskgroupID + "/tasks/" + event.meta.taskID + "/schedule/" + event.meta.scheduleID); + } else if(action == 'Delete') { + this.scheduleService.schedulesScheduleIDDelete(event.meta.scheduleID).subscribe({ + next: resp => { + this.events = this.events.filter(calendarEvent => calendarEvent.meta.scheduleID !== event.meta.scheduleID); + } + }) + } + + } +} diff --git a/frontend/src/app/schedules/scheduler/scheduler.component.css b/frontend/src/app/schedules/scheduler/scheduler.component.css index 8793269..abdc086 100644 --- a/frontend/src/app/schedules/scheduler/scheduler.component.css +++ b/frontend/src/app/schedules/scheduler/scheduler.component.css @@ -26,3 +26,6 @@ width: 100%; } +::ng-deep .cal-event-title { + white-space: normal; +} diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts index 5dafbf6..79835b5 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts @@ -40,13 +40,24 @@ export class TaskgroupDashboardComponent implements OnInit { ngOnInit(): void { this.activatedRoute.paramMap.subscribe(params => { if(params.has('taskgroupID')) { + console.log("Update of taskgroup") this.taskgroupID = Number(params.get('taskgroupID')); this.taskgroupService.taskgroupsTaskgroupIDGet(this.taskgroupID).subscribe({ next: resp => { this.taskgroups = resp.children this.taskgroupPath = resp.ancestors this.taskgroup = resp.taskgroupInfo; - this.navLinkListComponent!.addNavigationLink(this.taskgroup.taskgroupName, ['/taskgroups', this.taskgroup.taskgroupID.toString()]) + this.navLinkListComponent!.resetComponent([ + { + linkText: "Dashboard", + routerLink: ['/'] + }, + { + linkText: "Taskgroups", + routerLink: ["/taskgroups"] + } + ]); + console.log(this.taskgroups) this.taskgroupPath.forEach(taskgroupEntity => { this.navLinkListComponent!.addNavigationLink(taskgroupEntity.taskgroupName, ['/taskgroups', taskgroupEntity.taskgroupID.toString()]); }) diff --git a/frontend/src/app/tasks/task-detail-overview/task-detail-overview.component.ts b/frontend/src/app/tasks/task-detail-overview/task-detail-overview.component.ts index 70061af..bacadd5 100644 --- a/frontend/src/app/tasks/task-detail-overview/task-detail-overview.component.ts +++ b/frontend/src/app/tasks/task-detail-overview/task-detail-overview.component.ts @@ -49,7 +49,16 @@ export class TaskDetailOverviewComponent implements OnInit { this.taskgroups = resp.children this.taskgroupPath = resp.ancestors this.taskgroup = resp.taskgroupInfo; - this.navLinkListComponent!.addNavigationLink(this.taskgroup.taskgroupName, ['/taskgroups', this.taskgroup.taskgroupID.toString()]) + this.navLinkListComponent!.resetComponent([ + { + linkText: "Dashboard", + routerLink: ['/'] + }, + { + linkText: "Taskgroups", + routerLink: ["/taskgroups"] + } + ]); this.taskgroupPath.forEach(taskgroupEntity => { this.navLinkListComponent!.addNavigationLink(taskgroupEntity.taskgroupName, ['/taskgroups', taskgroupEntity.taskgroupID.toString()]); }) 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 7752773..ab05b42 100644 --- a/frontend/src/app/tasks/task-editor/task-editor.component.ts +++ b/frontend/src/app/tasks/task-editor/task-editor.component.ts @@ -7,6 +7,7 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; import {TaskService} from "../../../api"; import {TaskEditorData} from "./TaskEditorData"; import {MatSnackBar} from "@angular/material/snack-bar"; +import * as moment from "moment/moment"; @Component({ @@ -53,8 +54,8 @@ export class TaskEditorComponent implements OnInit { this.taskService.tasksTaskgroupIDPut(this.editorData.taskgroupID, { taskName: this.nameCtrl.value, eta: this.etaCtrl.value, - startDate: this.startDate.value, - deadline: this.endDate.value + startDate: moment(this.startDate.value).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + deadline: moment(this.endDate.value).format('YYYY-MM-DDTHH:mm:ss.SSSZ') }).subscribe({ next: resp => { this.dialog.close(resp); diff --git a/frontend/src/index.html b/frontend/src/index.html index 018656c..fecc517 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -11,6 +11,7 @@ + diff --git a/openapi.yaml b/openapi.yaml index a1a74d3..6cc075a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2421,6 +2421,7 @@ components: - eta - limit - overdue + - taskgroupPath additionalProperties: false properties: taskID: @@ -2448,6 +2449,10 @@ components: type: number description: number in minutes that was already worked on this task example: 10 + taskgroupPath: + type: array + items: + $ref: '#/components/schemas/TaskgroupEntityInfo' ScheduleStatus: required: - activeMinutes