diff --git a/frontend/src/app/schedules/advanced-scheduler/advanced-scheduler.component.ts b/frontend/src/app/schedules/advanced-scheduler/advanced-scheduler.component.ts
index ca801bd..b4231b0 100644
--- a/frontend/src/app/schedules/advanced-scheduler/advanced-scheduler.component.ts
+++ b/frontend/src/app/schedules/advanced-scheduler/advanced-scheduler.component.ts
@@ -132,6 +132,8 @@ export class AdvancedSchedulerComponent implements OnInit, OnChanges{
schedule() {
if(this.scheduleInfo == undefined) {
+ console.log("Direct Date" + this.selectedStartTime!.toString())
+ console.log("Moment Format" + moment(this.selectedStartTime!).format('YYYY-MM-DDTHH:mm:ss.SSSZ'))
this.scheduleService.schedulesTaskIDAdvancedPut(this.task!.taskID, {
scheduleStartTime: moment(this.selectedStartTime!).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
scheduleStopTime: moment(this.selectedStopTime!).format('YYYY-MM-DDTHH:mm:ss.SSSZ')
@@ -141,6 +143,8 @@ export class AdvancedSchedulerComponent implements OnInit, OnChanges{
}
})
} else {
+ console.log("Direct Date" + this.selectedStartTime!.toString())
+ console.log("Moment Format" + moment(this.selectedStartTime!).format('YYYY-MM-DDTHH:mm:ss.SSSZ'))
this.scheduleService.schedulesScheduleIDAdvancedPost(this.scheduleInfo.scheduleID!, {
scheduleStartTime: moment(this.selectedStartTime!).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
scheduleStopTime: moment(this.selectedStopTime!).format('YYYY-MM-DDTHH:mm:ss.SSSZ')
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 @@
+
+
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/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts
index 3612073..796e0cd 100644
--- a/frontend/src/environments/environment.prod.ts
+++ b/frontend/src/environments/environment.prod.ts
@@ -1,3 +1,4 @@
export const environment = {
- production: true
+ production: true,
+ api: "/api"
};
diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts
index bf9fcf4..43c1478 100644
--- a/frontend/src/environments/environment.ts
+++ b/frontend/src/environments/environment.ts
@@ -4,7 +4,7 @@
export const environment = {
production: false,
- api: "api"
+ api: "http://localhost:8080/api"
};
/*
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 1a2067f..6cc075a 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -3,7 +3,7 @@ info:
title: API Title
version: '1.0'
servers:
- - url: http://localhost:8080/api
+ - url: http://127.0.0.1:8080/api
paths:
/auth/signin:
post:
@@ -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