issue-20 #46

Merged
sebastian merged 15 commits from issue-20 into master 2023-11-12 13:18:53 +01:00
47 changed files with 1635 additions and 272 deletions

View File

@ -4,13 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Basic Reschedule"> <list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Fix wrong date">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/AdvancedTaskSchedule.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/repositories/timemanager/ScheduleRepository.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/repositories/timemanager/ScheduleRepository.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/services/TaskScheduleService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/services/TaskScheduleService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/core/services/TaskScheduleService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/services/TaskScheduleService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/test/java/core/schedules/ScheduleServiceTest.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/test/java/core/schedules/ScheduleServiceTest.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/test/resources/basicScheduleEntries.sql" beforeDir="false" afterPath="$PROJECT_DIR$/src/test/resources/basicScheduleEntries.sql" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -90,22 +87,6 @@
</key> </key>
</component> </component>
<component name="RunManager" selected="Spring Boot.DemoApplication"> <component name="RunManager" selected="Spring Boot.DemoApplication">
<configuration name="ScheduleServiceTest.deleteSchedule" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="demo" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="core.schedules.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="core.schedules" />
<option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" />
<option name="METHOD_NAME" value="deleteSchedule" />
<option name="TEST_OBJECT" value="method" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="ScheduleServiceTest.editBasicSchedule" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <configuration name="ScheduleServiceTest.editBasicSchedule" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="demo" /> <module name="demo" />
<extension name="coverage"> <extension name="coverage">
@ -122,7 +103,7 @@
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
</configuration> </configuration>
<configuration name="ScheduleServiceTest.getAllSchedulesOfUser" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <configuration name="ScheduleServiceTest.editscheduleAdvanced" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="demo" /> <module name="demo" />
<extension name="coverage"> <extension name="coverage">
<pattern> <pattern>
@ -132,13 +113,13 @@
</extension> </extension>
<option name="PACKAGE_NAME" value="core.schedules" /> <option name="PACKAGE_NAME" value="core.schedules" />
<option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" /> <option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" />
<option name="METHOD_NAME" value="getAllSchedulesOfUser" /> <option name="METHOD_NAME" value="editscheduleAdvanced" />
<option name="TEST_OBJECT" value="method" /> <option name="TEST_OBJECT" value="method" />
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
</configuration> </configuration>
<configuration name="ScheduleServiceTest.getFilteredScheduledOfUser" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <configuration name="ScheduleServiceTest.scheduleAdvanced" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="demo" /> <module name="demo" />
<extension name="coverage"> <extension name="coverage">
<pattern> <pattern>
@ -148,13 +129,13 @@
</extension> </extension>
<option name="PACKAGE_NAME" value="core.schedules" /> <option name="PACKAGE_NAME" value="core.schedules" />
<option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" /> <option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" />
<option name="METHOD_NAME" value="getFilteredScheduledOfUser" /> <option name="METHOD_NAME" value="scheduleAdvanced" />
<option name="TEST_OBJECT" value="method" /> <option name="TEST_OBJECT" value="method" />
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
</configuration> </configuration>
<configuration name="ScheduleServiceTest.scheduleBasic" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true"> <configuration name="ScheduleServiceTest.scheduleNow" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="demo" /> <module name="demo" />
<extension name="coverage"> <extension name="coverage">
<pattern> <pattern>
@ -164,12 +145,27 @@
</extension> </extension>
<option name="PACKAGE_NAME" value="core.schedules" /> <option name="PACKAGE_NAME" value="core.schedules" />
<option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" /> <option name="MAIN_CLASS_NAME" value="core.schedules.ScheduleServiceTest" />
<option name="METHOD_NAME" value="scheduleBasic" /> <option name="METHOD_NAME" value="scheduleNow" />
<option name="TEST_OBJECT" value="method" /> <option name="TEST_OBJECT" value="method" />
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>
</configuration> </configuration>
<configuration name="TaskServiceTest" type="JUnit" factoryName="JUnit" temporary="true" nameIsGenerated="true">
<module name="demo" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="core.tasks.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="core.tasks" />
<option name="MAIN_CLASS_NAME" value="core.tasks.TaskServiceTest" />
<option name="TEST_OBJECT" value="class" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="DemoApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true"> <configuration name="DemoApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true">
<module name="demo" /> <module name="demo" />
<option name="SPRING_BOOT_MAIN_CLASS" value="core.DemoApplication" /> <option name="SPRING_BOOT_MAIN_CLASS" value="core.DemoApplication" />
@ -179,11 +175,11 @@
</configuration> </configuration>
<recent_temporary> <recent_temporary>
<list> <list>
<item itemvalue="JUnit.ScheduleServiceTest.getFilteredScheduledOfUser" /> <item itemvalue="JUnit.ScheduleServiceTest.scheduleNow" />
<item itemvalue="JUnit.ScheduleServiceTest.deleteSchedule" />
<item itemvalue="JUnit.ScheduleServiceTest.editBasicSchedule" /> <item itemvalue="JUnit.ScheduleServiceTest.editBasicSchedule" />
<item itemvalue="JUnit.ScheduleServiceTest.scheduleBasic" /> <item itemvalue="JUnit.ScheduleServiceTest.editscheduleAdvanced" />
<item itemvalue="JUnit.ScheduleServiceTest.getAllSchedulesOfUser" /> <item itemvalue="JUnit.ScheduleServiceTest.scheduleAdvanced" />
<item itemvalue="JUnit.TaskServiceTest" />
</list> </list>
</recent_temporary> </recent_temporary>
</component> </component>
@ -222,6 +218,7 @@
<workItem from="1699473376129" duration="1423000" /> <workItem from="1699473376129" duration="1423000" />
<workItem from="1699639316405" duration="9267000" /> <workItem from="1699639316405" duration="9267000" />
<workItem from="1699684493731" duration="1121000" /> <workItem from="1699684493731" duration="1121000" />
<workItem from="1699769541677" duration="7576000" />
</task> </task>
<task id="LOCAL-00001" summary="Structure Taskgroups in Hierarchies"> <task id="LOCAL-00001" summary="Structure Taskgroups in Hierarchies">
<option name="closed" value="true" /> <option name="closed" value="true" />
@ -487,49 +484,77 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1699695051881</updated> <updated>1699695051881</updated>
</task> </task>
<task id="LOCAL-00034" summary="Update gitignore and add Clear ScheduleCode"> <task id="LOCAL-00034" summary="Get Working Status of Today Endpoint">
<option name="closed" value="true" /> <option name="closed" value="true" />
<created>1699705458914</created> <created>1699726166056</created>
<option name="number" value="00034" /> <option name="number" value="00034" />
<option name="presentableId" value="LOCAL-00034" /> <option name="presentableId" value="LOCAL-00034" />
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1699705458914</updated> <updated>1699726166056</updated>
</task> </task>
<task id="LOCAL-00035" summary="Get All Schedules of User"> <task id="LOCAL-00035" summary="Include Working Status in Frontend Dashboard">
<option name="closed" value="true" /> <option name="closed" value="true" />
<created>1699708881009</created> <created>1699726328681</created>
<option name="number" value="00035" /> <option name="number" value="00035" />
<option name="presentableId" value="LOCAL-00035" /> <option name="presentableId" value="LOCAL-00035" />
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1699708881009</updated> <updated>1699726328681</updated>
</task> </task>
<task id="LOCAL-00036" summary="Get All Schedules of Task + create Basic Schedule"> <task id="LOCAL-00036" summary="Create Datastructures for AdvancedSchedules and create schedules for them">
<option name="closed" value="true" /> <option name="closed" value="true" />
<created>1699711238266</created> <created>1699730041496</created>
<option name="number" value="00036" /> <option name="number" value="00036" />
<option name="presentableId" value="LOCAL-00036" /> <option name="presentableId" value="LOCAL-00036" />
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1699711238266</updated> <updated>1699730041496</updated>
</task> </task>
<task id="LOCAL-00037" summary="Basic Reschedule"> <task id="LOCAL-00037" summary="Reschedule Advanced Schedules">
<option name="closed" value="true" /> <option name="closed" value="true" />
<created>1699714216432</created> <created>1699730644743</created>
<option name="number" value="00037" /> <option name="number" value="00037" />
<option name="presentableId" value="LOCAL-00037" /> <option name="presentableId" value="LOCAL-00037" />
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1699714216432</updated> <updated>1699730644743</updated>
</task> </task>
<option name="localTasksCounter" value="38" /> <task id="LOCAL-00038" summary="ScheduleNow test with running advanced Schedule">
<option name="closed" value="true" />
<created>1699730764558</created>
<option name="number" value="00038" />
<option name="presentableId" value="LOCAL-00038" />
<option name="project" value="LOCAL" />
<updated>1699730764558</updated>
</task>
<task id="LOCAL-00039" summary="Update values of datetime picker automatically for editing">
<option name="closed" value="true" />
<created>1699783953060</created>
<option name="number" value="00039" />
<option name="presentableId" value="LOCAL-00039" />
<option name="project" value="LOCAL" />
<updated>1699783953060</updated>
</task>
<task id="LOCAL-00040" summary="Adapt datetime-picker">
<option name="closed" value="true" />
<created>1699783968670</created>
<option name="number" value="00040" />
<option name="presentableId" value="LOCAL-00040" />
<option name="project" value="LOCAL" />
<updated>1699783968670</updated>
</task>
<task id="LOCAL-00041" summary="Fix wrong date">
<option name="closed" value="true" />
<created>1699786723938</created>
<option name="number" value="00041" />
<option name="presentableId" value="LOCAL-00041" />
<option name="project" value="LOCAL" />
<updated>1699786723938</updated>
</task>
<option name="localTasksCounter" value="42" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" /> <option name="version" value="3" />
</component> </component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="Remove update spamming in console" />
<MESSAGE value="Start task now from Taskoverview in Dashboard" />
<MESSAGE value="Load worked minutes when reloading dashboard" />
<MESSAGE value="Check if there is another active schedule when starting task now" />
<MESSAGE value="List missed Schedules" /> <MESSAGE value="List missed Schedules" />
<MESSAGE value="Forget single schedule" /> <MESSAGE value="Forget single schedule" />
<MESSAGE value="Fix marking finished task as overdue" /> <MESSAGE value="Fix marking finished task as overdue" />
@ -547,11 +572,15 @@
<MESSAGE value="Deleting Task test" /> <MESSAGE value="Deleting Task test" />
<MESSAGE value="Consider increased number of tasks" /> <MESSAGE value="Consider increased number of tasks" />
<MESSAGE value="Remove entityManager from TaskService" /> <MESSAGE value="Remove entityManager from TaskService" />
<MESSAGE value="Update gitignore and add Clear ScheduleCode" /> <MESSAGE value="Get Working Status of Today Endpoint" />
<MESSAGE value="Get All Schedules of User" /> <MESSAGE value="Include Working Status in Frontend Dashboard" />
<MESSAGE value="Get All Schedules of Task + create Basic Schedule" /> <MESSAGE value="Create Datastructures for AdvancedSchedules and create schedules for them" />
<MESSAGE value="Basic Reschedule" /> <MESSAGE value="Reschedule Advanced Schedules" />
<option name="LAST_COMMIT_MESSAGE" value="Basic Reschedule" /> <MESSAGE value="ScheduleNow test with running advanced Schedule" />
<MESSAGE value="Update values of datetime picker automatically for editing" />
<MESSAGE value="Adapt datetime-picker" />
<MESSAGE value="Fix wrong date" />
<option name="LAST_COMMIT_MESSAGE" value="Fix wrong date" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>
@ -562,9 +591,14 @@
<option name="timeStamp" value="12" /> <option name="timeStamp" value="12" />
</line-breakpoint> </line-breakpoint>
<line-breakpoint enabled="true" type="java-line"> <line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/java/core/services/TaskScheduleService.java</url> <url>file://$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java</url>
<line>52</line> <line>68</line>
<option name="timeStamp" value="32" /> <option name="timeStamp" value="14" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java</url>
<line>93</line>
<option name="timeStamp" value="16" />
</line-breakpoint> </line-breakpoint>
</breakpoints> </breakpoints>
</breakpoint-manager> </breakpoint-manager>

View File

@ -3,12 +3,16 @@ package core.api.controller;
import core.api.models.auth.SimpleStatusResponse; import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.taskSchedule.*; import core.api.models.timemanager.taskSchedule.*;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleFieldInfo;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.services.*; import core.services.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -37,7 +41,7 @@ public class ScheduleController {
@GetMapping("/schedules/{taskID}") @GetMapping("/schedules/{taskID}")
public ResponseEntity<?> loadAllSchedulesOfTask(@PathVariable long taskID) { public ResponseEntity<?> loadAllSchedulesOfTask(@PathVariable long taskID) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -49,10 +53,19 @@ public class ScheduleController {
return ResponseEntity.ok(taskSchedules.stream().map(AbstractSchedule::toScheduleInfo).toList()); return ResponseEntity.ok(taskSchedules.stream().map(AbstractSchedule::toScheduleInfo).toList());
} }
@PutMapping("/schedules/{taskID}") @PutMapping("/schedules/{taskID}/basic")
public ResponseEntity<?> createSchedule(@PathVariable long taskID, @RequestBody @Valid ScheduleFieldInfo scheduleFieldInfo) { public ResponseEntity<?> createBasicSchedule(@PathVariable long taskID, @RequestBody @Valid BasicScheduleFieldInfo scheduleFieldInfo) {
return createAbstractSchedule(taskID, scheduleFieldInfo);
}
@PutMapping("/schedules/{taskID}/advanced")
public ResponseEntity<?> createAdsvancedSchedule(@PathVariable long taskID, @RequestBody @Valid AdvancedScheduleFieldInfo scheduleFieldInfo) {
return createAbstractSchedule(taskID, scheduleFieldInfo);
}
private ResponseEntity<?> createAbstractSchedule(long taskID, ScheduleFieldInfo scheduleFieldInfo) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -63,15 +76,27 @@ public class ScheduleController {
if(scheduleFieldInfo instanceof BasicScheduleFieldInfo) { if(scheduleFieldInfo instanceof BasicScheduleFieldInfo) {
ServiceResult<AbstractSchedule> scheduleResult = taskScheduleService.scheduleBasic(permissionResult.getResult(), (BasicScheduleFieldInfo) scheduleFieldInfo); ServiceResult<AbstractSchedule> scheduleResult = taskScheduleService.scheduleBasic(permissionResult.getResult(), (BasicScheduleFieldInfo) scheduleFieldInfo);
return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo()); return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
} else if(scheduleFieldInfo instanceof AdvancedScheduleFieldInfo) {
ServiceResult<AbstractSchedule> scheduleResult = taskScheduleService.scheduleAdvanced(permissionResult.getResult(), (AdvancedScheduleFieldInfo) scheduleFieldInfo);
return ResponseEntity.ok(scheduleResult.getResult().toScheduleInfo());
} else { } else {
return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
} }
} }
@PostMapping("/schedules/{scheduleID}") @PostMapping("/schedules/{scheduleID}/basic")
public ResponseEntity<?> editSchedule(@PathVariable long scheduleID, @RequestBody @Valid ScheduleFieldInfo scheduleFieldInfo) { public ResponseEntity<?> editBasicSchedule(@PathVariable long scheduleID, @RequestBody @Valid BasicScheduleFieldInfo scheduleFieldInfo) {
return editAbstractSchedule(scheduleID, scheduleFieldInfo);
}
@PostMapping("/schedules/{scheduleID}/advanced")
public ResponseEntity<?> editAdvancedSchedule(@PathVariable long scheduleID, @RequestBody @Valid AdvancedScheduleFieldInfo scheduleFieldInfo) {
return editAbstractSchedule(scheduleID, scheduleFieldInfo);
}
private ResponseEntity<?> editAbstractSchedule(long scheduleID, ScheduleFieldInfo scheduleFieldInfo) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -86,6 +111,13 @@ public class ScheduleController {
} else { } else {
return ResponseEntity.ok(updatedSchedule.getResult().toScheduleInfo()); return ResponseEntity.ok(updatedSchedule.getResult().toScheduleInfo());
} }
} else if(permissionResult.getResult() instanceof AdvancedTaskSchedule && scheduleFieldInfo instanceof AdvancedScheduleFieldInfo) {
ServiceResult<AbstractSchedule> updatedSchedule = taskScheduleService.editAdvancedSchedule((AdvancedTaskSchedule) permissionResult.getResult(), (AdvancedScheduleFieldInfo) scheduleFieldInfo);
if(updatedSchedule.getExitCode() == ServiceExitCode.INVALID_OPERATION) {
return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
} else {
return ResponseEntity.ok(updatedSchedule.getResult().toScheduleInfo());
}
} }
return ResponseEntity.status(400).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
@ -94,7 +126,7 @@ public class ScheduleController {
@DeleteMapping("/schedules/{scheduleID}") @DeleteMapping("/schedules/{scheduleID}")
public ResponseEntity<?> deleteSchedule(@PathVariable long scheduleID) { public ResponseEntity<?> deleteSchedule(@PathVariable long scheduleID) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -116,7 +148,7 @@ public class ScheduleController {
@PostMapping("/schedules/{taskID}/now") @PostMapping("/schedules/{taskID}/now")
public ResponseEntity<?> scheduleNow(@PathVariable long taskID) { public ResponseEntity<?> scheduleNow(@PathVariable long taskID) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -145,7 +177,7 @@ public class ScheduleController {
@PostMapping("/schedules/{scheduleID}/activate") @PostMapping("/schedules/{scheduleID}/activate")
public ResponseEntity<?> activateSchedule(@PathVariable long scheduleID) { public ResponseEntity<?> activateSchedule(@PathVariable long scheduleID) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -160,7 +192,7 @@ public class ScheduleController {
@PostMapping("/schedules/{scheduleID}/stop/{finish}") @PostMapping("/schedules/{scheduleID}/stop/{finish}")
public ResponseEntity<?> stopSchedule(@PathVariable long scheduleID, @PathVariable boolean finish) { public ResponseEntity<?> stopSchedule(@PathVariable long scheduleID, @PathVariable boolean finish) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -175,7 +207,7 @@ public class ScheduleController {
@PostMapping("/schedules/{taskID}/forgotten") @PostMapping("/schedules/{taskID}/forgotten")
public ResponseEntity<?> registerForgottenSchedule(@PathVariable long taskID, @RequestBody @Valid ForgottenScheduleInfo forgottenScheduleInfo) { public ResponseEntity<?> registerForgottenSchedule(@PathVariable long taskID, @RequestBody @Valid ForgottenScheduleInfo forgottenScheduleInfo) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -202,7 +234,7 @@ public class ScheduleController {
List<PermissionResult<AbstractSchedule>> permissionResults = new ArrayList<>(); List<PermissionResult<AbstractSchedule>> permissionResults = new ArrayList<>();
for(long scheduleID: scheduleIDs) { for(long scheduleID: scheduleIDs) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName()); PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(permissionResult.isHasPermissions()) { if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} }
@ -217,4 +249,18 @@ public class ScheduleController {
} }
return ResponseEntity.ok(new SimpleStatusResponse("success")); return ResponseEntity.ok(new SimpleStatusResponse("success"));
} }
@GetMapping("/schedules/{scheduleID}/details")
public ResponseEntity<?> loadScheduleDetails(@PathVariable long scheduleID) {
PermissionResult<AbstractSchedule> permissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!permissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(permissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
return ResponseEntity.ok(permissionResult.getResult().toScheduleInfo());
}
} }

View File

@ -1,4 +0,0 @@
package core.api.models.timemanager.taskSchedule;
public abstract class ScheduleFieldInfo {
}

View File

@ -0,0 +1,41 @@
package core.api.models.timemanager.taskSchedule.scheduleInfos;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
public class AdvancedScheduleFieldInfo extends ScheduleFieldInfo {
@NotNull
@JsonProperty
private LocalDateTime scheduleStartTime;
@NotNull
@JsonProperty
private LocalDateTime scheduleStopTime;
public AdvancedScheduleFieldInfo(LocalDateTime scheduleStartTime, LocalDateTime scheduleStopTime) {
this.scheduleStartTime = scheduleStartTime;
this.scheduleStopTime = scheduleStopTime;
}
public AdvancedScheduleFieldInfo() {
}
public LocalDateTime getScheduleStartTime() {
return scheduleStartTime;
}
public void setScheduleStartTime(LocalDateTime scheduleStartTime) {
this.scheduleStartTime = scheduleStartTime;
}
public LocalDateTime getScheduleStopTime() {
return scheduleStopTime;
}
public void setScheduleStopTime(LocalDateTime scheduleStopTime) {
this.scheduleStopTime = scheduleStopTime;
}
}

View File

@ -0,0 +1,35 @@
package core.api.models.timemanager.taskSchedule.scheduleInfos;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.Task;
import java.time.LocalDateTime;
import java.util.List;
public class AdvancedScheduleInfo extends ScheduleInfo {
private LocalDateTime scheduleStartTime;
private LocalDateTime scheduleStopTime;
public AdvancedScheduleInfo(long scheduleID, ScheduleType scheduleType, LocalDateTime startTime, LocalDateTime stopTime, int activeMinutes, Task task, List<TaskgroupEntityInfo> taskgroupPath, LocalDateTime plannedStartTime, LocalDateTime plannedStopTime) {
super(scheduleID, scheduleType, startTime, stopTime, activeMinutes, task, taskgroupPath);
this.scheduleStartTime = plannedStartTime;
this.scheduleStopTime = plannedStopTime;
}
public LocalDateTime getScheduleStartTime() {
return scheduleStartTime;
}
public void setScheduleStartTime(LocalDateTime scheduleStartTime) {
this.scheduleStartTime = scheduleStartTime;
}
public LocalDateTime getScheduleStopTime() {
return scheduleStopTime;
}
public void setScheduleStopTime(LocalDateTime scheduleStopTime) {
this.scheduleStopTime = scheduleStopTime;
}
}

View File

@ -1,4 +1,6 @@
package core.api.models.timemanager.taskSchedule; package core.api.models.timemanager.taskSchedule.scheduleInfos;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.time.LocalDate; import java.time.LocalDate;

View File

@ -1,4 +1,4 @@
package core.api.models.timemanager.taskSchedule; package core.api.models.timemanager.taskSchedule.scheduleInfos;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
@ -11,8 +11,10 @@ import java.util.List;
public class BasicScheduleInfo extends ScheduleInfo{ public class BasicScheduleInfo extends ScheduleInfo{
private LocalDate scheduleDate; private LocalDate scheduleDate;
public BasicScheduleInfo(long scheduleID, ScheduleType scheduleType, LocalDateTime startTime, LocalDateTime stopTime, int activeMinutes, Task task, List<TaskgroupEntityInfo> taskgroupPath) {
public BasicScheduleInfo(long scheduleID, ScheduleType scheduleType, LocalDateTime startTime, LocalDateTime stopTime, int activeMinutes, Task task, List<TaskgroupEntityInfo> taskgroupPath, LocalDate scheduleDate) {
super(scheduleID, scheduleType, startTime, stopTime, activeMinutes, task, taskgroupPath); super(scheduleID, scheduleType, startTime, stopTime, activeMinutes, task, taskgroupPath);
this.scheduleDate = scheduleDate;
} }
public BasicScheduleInfo(long scheduleID) { public BasicScheduleInfo(long scheduleID) {

View File

@ -0,0 +1,4 @@
package core.api.models.timemanager.taskSchedule.scheduleInfos;
public abstract class ScheduleFieldInfo {
}

View File

@ -1,10 +1,9 @@
package core.api.models.timemanager.taskSchedule; package core.api.models.timemanager.taskSchedule.scheduleInfos;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.api.models.timemanager.tasks.TaskShortInfo; import core.api.models.timemanager.tasks.TaskShortInfo;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package core.api.models.timemanager.taskSchedule; package core.api.models.timemanager.taskSchedule.scheduleInfos;
public enum ScheduleType { public enum ScheduleType {

View File

@ -1,10 +1,9 @@
package core.entities.timemanager; package core.entities.timemanager;
import core.api.models.timemanager.taskSchedule.ScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleInfo;
import javax.persistence.*; import javax.persistence.*;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Objects; import java.util.Objects;
@ -109,4 +108,16 @@ public abstract class AbstractSchedule {
} }
public abstract boolean isMissed(LocalDateTime timeReference); public abstract boolean isMissed(LocalDateTime timeReference);
public int calcActiveMinutes() {
if(startTime == null) {
return 0;
} else if(stopTime == null) {
Duration duration = Duration.between(startTime, LocalDateTime.now());
return (int) duration.toMinutes();
} else {
Duration duration = Duration.between(startTime, stopTime);
return (int) duration.toMinutes();
}
}
} }

View File

@ -1,10 +1,15 @@
package core.entities.timemanager; package core.entities.timemanager;
import core.api.models.timemanager.taskSchedule.ScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleType;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import javax.persistence.DiscriminatorValue; import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity; import javax.persistence.Entity;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Entity @Entity
@DiscriminatorValue("1") @DiscriminatorValue("1")
public class AdvancedTaskSchedule extends AbstractSchedule { public class AdvancedTaskSchedule extends AbstractSchedule {
@ -12,13 +17,58 @@ public class AdvancedTaskSchedule extends AbstractSchedule {
private LocalDateTime scheduleStart; private LocalDateTime scheduleStart;
private LocalDateTime scheduleEnd; private LocalDateTime scheduleEnd;
public AdvancedTaskSchedule(LocalDateTime scheduleStart, LocalDateTime scheduleEnd) {
this.scheduleStart = scheduleStart;
this.scheduleEnd = scheduleEnd;
}
public AdvancedTaskSchedule(Task task, LocalDateTime startTime, LocalDateTime stopTime, LocalDateTime scheduleStart, LocalDateTime scheduleEnd) {
super(task, startTime, stopTime);
this.scheduleStart = scheduleStart;
this.scheduleEnd = scheduleEnd;
}
public AdvancedTaskSchedule(Task task, LocalDateTime startTime, LocalDateTime scheduleStart, LocalDateTime scheduleEnd) {
super(task, startTime);
this.scheduleStart = scheduleStart;
this.scheduleEnd = scheduleEnd;
}
public AdvancedTaskSchedule(Task task, LocalDateTime scheduleStart, LocalDateTime scheduleEnd) {
super(task);
this.scheduleStart = scheduleStart;
this.scheduleEnd = scheduleEnd;
}
public AdvancedTaskSchedule() {
}
public LocalDateTime getScheduleStart() {
return scheduleStart;
}
public void setScheduleStart(LocalDateTime scheduleStart) {
this.scheduleStart = scheduleStart;
}
public LocalDateTime getScheduleEnd() {
return scheduleEnd;
}
public void setScheduleEnd(LocalDateTime scheduleEnd) {
this.scheduleEnd = scheduleEnd;
}
@Override @Override
public ScheduleInfo toScheduleInfo() { public ScheduleInfo toScheduleInfo() {
return null; int activeMinutes = calcActiveMinutes();
List<TaskgroupEntityInfo> taskgroupEntityInfos = Taskgroup.getAncestorList(task.getTaskgroup()).stream().map(TaskgroupEntityInfo::new).toList();
return new AdvancedScheduleInfo(scheduleID, ScheduleType.ADVANCED, startTime, stopTime, activeMinutes, task, taskgroupEntityInfos, scheduleStart, scheduleEnd);
} }
@Override @Override
public boolean isMissed(LocalDateTime timeReference) { public boolean isMissed(LocalDateTime timeReference) {
return false; return startTime == null && scheduleEnd.toLocalDate().isBefore(timeReference.toLocalDate());
} }
} }

View File

@ -1,17 +1,14 @@
package core.entities.timemanager; package core.entities.timemanager;
import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleInfo;
import core.api.models.timemanager.taskSchedule.ScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleInfo;
import core.api.models.timemanager.taskSchedule.ScheduleType; import core.api.models.timemanager.taskSchedule.scheduleInfos.ScheduleType;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.api.models.timemanager.tasks.TaskEntityInfo;
import javax.persistence.*; import javax.persistence.*;
import java.time.Duration;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Objects;
@Entity @Entity
@DiscriminatorValue("0") @DiscriminatorValue("0")
@ -48,23 +45,11 @@ public class BasicTaskSchedule extends AbstractSchedule{
public ScheduleInfo toScheduleInfo() { public ScheduleInfo toScheduleInfo() {
int activeMinutes = calcActiveMinutes(); int activeMinutes = calcActiveMinutes();
List<TaskgroupEntityInfo> taskgroupEntityInfos = Taskgroup.getAncestorList(task.getTaskgroup()).stream().map(TaskgroupEntityInfo::new).toList(); List<TaskgroupEntityInfo> taskgroupEntityInfos = Taskgroup.getAncestorList(task.getTaskgroup()).stream().map(TaskgroupEntityInfo::new).toList();
return new BasicScheduleInfo(scheduleID, ScheduleType.BASIC, startTime, stopTime, activeMinutes, task, taskgroupEntityInfos); return new BasicScheduleInfo(scheduleID, ScheduleType.BASIC, startTime, stopTime, activeMinutes, task, taskgroupEntityInfos, scheduleDate);
} }
@Override @Override
public boolean isMissed(LocalDateTime timeReference) { public boolean isMissed(LocalDateTime timeReference) {
return startTime == null && scheduleDate.isBefore(timeReference.toLocalDate()); return startTime == null && scheduleDate.isBefore(timeReference.toLocalDate());
} }
public int calcActiveMinutes() {
if(startTime == null) {
return 0;
} else if(stopTime == null) {
Duration duration = Duration.between(startTime, LocalDateTime.now());
return (int) duration.toMinutes();
} else {
Duration duration = Duration.between(startTime, stopTime);
return (int) duration.toMinutes();
}
}
} }

View File

@ -1,8 +1,11 @@
package core.services; package core.services;
import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo; import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.repositories.UserRepository; import core.repositories.UserRepository;
@ -41,13 +44,31 @@ public class TaskScheduleService {
return new ServiceResult<>(basicTaskSchedule); return new ServiceResult<>(basicTaskSchedule);
} }
public ServiceResult<AbstractSchedule> scheduleAdvanced(Task task, AdvancedScheduleFieldInfo scheduleFieldInfo) {
LocalDate startDate = scheduleFieldInfo.getScheduleStartTime().toLocalDate();
LocalDate endDate = scheduleFieldInfo.getScheduleStopTime().toLocalDate();
if(task.isFinished() || startDate.isBefore(LocalDate.now()) || endDate.isBefore(LocalDate.now())) {
return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION);
}
if(scheduleFieldInfo.getScheduleStartTime().isAfter(scheduleFieldInfo.getScheduleStopTime())) {
return new ServiceResult<>(ServiceExitCode.INVALID_PARAMETER);
}
AdvancedTaskSchedule advancedTaskSchedule = new AdvancedTaskSchedule(task, scheduleFieldInfo.getScheduleStartTime(), scheduleFieldInfo.getScheduleStopTime());
scheduleRepository.save(advancedTaskSchedule);
return new ServiceResult<>(advancedTaskSchedule);
}
public PermissionResult<AbstractSchedule> getSchedulePermissions(long scheduleID, String username) { public PermissionResult<AbstractSchedule> getSchedulePermissions(long scheduleID, String username) {
Optional<AbstractSchedule> abstractSchedule = scheduleRepository.findById(scheduleID); Optional<AbstractSchedule> abstractSchedule = scheduleRepository.findById(scheduleID);
return abstractSchedule.map(schedule -> new PermissionResult<>(schedule, schedule.getTask().getTaskgroup().getUser().getUsername().equals(username))).orElseGet(() -> new PermissionResult<>(ServiceExitCode.MISSING_ENTITY)); return abstractSchedule.map(schedule -> new PermissionResult<>(schedule, schedule.getTask().getTaskgroup().getUser().getUsername().equals(username))).orElseGet(() -> new PermissionResult<>(ServiceExitCode.MISSING_ENTITY));
} }
public ServiceResult<AbstractSchedule> editBasicSchedule(BasicTaskSchedule schedule, BasicScheduleFieldInfo scheduleFieldInfo) { public ServiceResult<AbstractSchedule> editBasicSchedule(BasicTaskSchedule schedule, BasicScheduleFieldInfo scheduleFieldInfo) {
if(schedule.getTask().isFinished() || scheduleFieldInfo.getScheduleDate().isBefore(LocalDate.now())) { if(schedule.getTask().isFinished() || scheduleFieldInfo.getScheduleDate().isBefore(LocalDate.now()) || schedule.isActive()) {
return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION); return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION);
} }
@ -56,6 +77,24 @@ public class TaskScheduleService {
return new ServiceResult<>(schedule); return new ServiceResult<>(schedule);
} }
public ServiceResult<AbstractSchedule> editAdvancedSchedule(AdvancedTaskSchedule schedule, AdvancedScheduleFieldInfo scheduleFieldInfo) {
LocalDate startDate = scheduleFieldInfo.getScheduleStartTime().toLocalDate();
LocalDate endDate = scheduleFieldInfo.getScheduleStopTime().toLocalDate();
if(schedule.getTask().isFinished() || startDate.isBefore(LocalDate.now()) || endDate.isBefore(LocalDate.now()) || schedule.isActive()) {
return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION);
}
if(scheduleFieldInfo.getScheduleStartTime().isAfter(scheduleFieldInfo.getScheduleStopTime())) {
return new ServiceResult<>(ServiceExitCode.INVALID_PARAMETER);
}
schedule.setScheduleStart(scheduleFieldInfo.getScheduleStartTime());
schedule.setScheduleEnd(scheduleFieldInfo.getScheduleStopTime());
scheduleRepository.save(schedule);
return new ServiceResult<>(schedule);
}
public void deleteSchedule(AbstractSchedule schedule) { public void deleteSchedule(AbstractSchedule schedule) {
scheduleRepository.delete(schedule); scheduleRepository.delete(schedule);
} }
@ -76,7 +115,16 @@ public class TaskScheduleService {
} }
} }
} else { } else {
//to continue... if(((AdvancedTaskSchedule) abstractSchedule).getScheduleStart().toLocalDate().isEqual(LocalDate.now())) {
//Schedule is today
if(startable && abstractSchedule.getStartTime() == null) {
if(abstractSchedule.getStartTime() == null) {
filteredSchedules.add(abstractSchedule);
}
} else if(!startable) {
filteredSchedules.add(abstractSchedule);
}
}
} }
} }
return filteredSchedules; return filteredSchedules;

View File

@ -41,3 +41,4 @@ spring.servlet.multipart.max-request-size=4196KB
demo.webapp.jwtSecret=demoWebappSecretKey demo.webapp.jwtSecret=demoWebappSecretKey
demo.webapp.jwtExpirationMS=86400000 demo.webapp.jwtExpirationMS=86400000
spring.jackson.time-zone=UTC

View File

@ -1,16 +1,16 @@
package core.schedules; package core.schedules;
import core.api.models.timemanager.taskSchedule.BasicScheduleFieldInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.BasicScheduleInfo; import core.api.models.timemanager.taskSchedule.scheduleInfos.AdvancedScheduleInfo;
import core.api.models.timemanager.taskSchedule.scheduleInfos.BasicScheduleFieldInfo;
import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo; import core.api.models.timemanager.taskSchedule.ForgottenScheduleInfo;
import core.entities.timemanager.AbstractSchedule; import core.entities.timemanager.AbstractSchedule;
import core.entities.timemanager.AdvancedTaskSchedule;
import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.repositories.timemanager.TaskgroupRepository;
import core.services.ServiceExitCode; import core.services.ServiceExitCode;
import core.services.ServiceResult; import core.services.ServiceResult;
import core.services.TaskScheduleService; import core.services.TaskScheduleService;
import core.services.TaskgroupService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@ -97,6 +97,11 @@ public class ScheduleServiceTest {
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 1L), new BasicScheduleFieldInfo(LocalDate.now())); ServiceResult<AbstractSchedule> result_3 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 1L), new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.OK, result_3.getExitCode()); assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertNotEquals(((BasicTaskSchedule) result_3.getResult()).getScheduleDate(), oldDate); assertNotEquals(((BasicTaskSchedule) result_3.getResult()).getScheduleDate(), oldDate);
//Situation 4: Reschedule already running schedule
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.editBasicSchedule(entityManager.find(BasicTaskSchedule.class, 4L),
new BasicScheduleFieldInfo(LocalDate.now()));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_4.getExitCode());
} }
@Test @Test
@ -156,6 +161,10 @@ public class ScheduleServiceTest {
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 5L)); ServiceResult<AbstractSchedule> result_3 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 5L));
assertEquals(ServiceExitCode.OK, result_3.getExitCode()); assertEquals(ServiceExitCode.OK, result_3.getExitCode());
assertThat(entityManager.find(BasicTaskSchedule.class, result_3.getResult().getScheduleID())).isNotNull(); assertThat(entityManager.find(BasicTaskSchedule.class, result_3.getResult().getScheduleID())).isNotNull();
//Situation 4: Running Advanced Schedule
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.scheduleNow(entityManager.find(Task.class, 17L));
assertEquals(ServiceExitCode.ENTITY_ALREADY_EXIST, result_4.getExitCode());
} }
@Test @Test
@ -234,4 +243,79 @@ public class ScheduleServiceTest {
void getAllMissedSchedulesOfUser() { void getAllMissedSchedulesOfUser() {
assertEquals(1, taskScheduleService.getAllMissedSchedulesOfUser(username).size()); assertEquals(1, taskScheduleService.getAllMissedSchedulesOfUser(username).size());
} }
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void scheduleAdvanced() {
//Situation 1: Schedule finished Task
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 18L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
//Situation 2: Schedule Start is before today
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Schedule End is before today
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(2L), LocalDateTime.now().minusDays(1L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_3.getExitCode());
//Situation 4: Start after stop
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(2L), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.INVALID_PARAMETER, result_4.getExitCode());
//Situation 5: Valid schedule
ServiceResult<AbstractSchedule> result_5 = taskScheduleService.scheduleAdvanced(entityManager.find(Task.class, 17L),
new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.OK, result_5.getExitCode());
assertThat(entityManager.find(AdvancedTaskSchedule.class, result_5.getResult().getScheduleID())).isNotNull();
}
@Test
@SqlGroup({
@Sql("classpath:taskgroupRepositoryTestEntries.sql"),
@Sql("classpath:taskRepositoryEntries.sql"),
@Sql("classpath:basicScheduleEntries.sql")
})
void editscheduleAdvanced() {
//Situation 1: Schedule finished Task
ServiceResult<AbstractSchedule> result_1 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 12L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_1.getExitCode());
//Situation 2: Schedule Start is before today
ServiceResult<AbstractSchedule> result_2 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(1L), LocalDateTime.now().plusHours(2L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_2.getExitCode());
//Situation 3: Schedule End is before today
ServiceResult<AbstractSchedule> result_3 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().minusDays(2L), LocalDateTime.now().minusDays(1L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_3.getExitCode());
//Situation 4: Start after stop
ServiceResult<AbstractSchedule> result_4 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now().plusHours(2L), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.INVALID_PARAMETER, result_4.getExitCode());
//Situation 5: Valid schedule
ServiceResult<AbstractSchedule> result_5 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 11L),
new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.OK, result_5.getExitCode());
assertThat(entityManager.find(AdvancedTaskSchedule.class, result_5.getResult().getScheduleID())).isNotNull();
//Situation 6: reschedule already running schedule
ServiceResult<AbstractSchedule> result_6 = taskScheduleService.editAdvancedSchedule(entityManager.find(AdvancedTaskSchedule.class, 9L),
new AdvancedScheduleFieldInfo(LocalDateTime.now(), LocalDateTime.now().plusHours(1L)));
assertEquals(ServiceExitCode.INVALID_OPERATION, result_6.getExitCode());
}
} }

View File

@ -6,3 +6,10 @@ VALUES (0, 1, null, null, '2010-11-11', 1, null, null),
(0, 5, null, null, '2024-11-11', 5, null, null), (0, 5, null, null, '2024-11-11', 5, null, null),
(0, 6, '2023-10-10', null, '2024-11-11', 16, null, null), (0, 6, '2023-10-10', null, '2024-11-11', 16, null, null),
(0, 7, '2023-10-10', null, '2024-11-11', 16, null, null); (0, 7, '2023-10-10', null, '2024-11-11', 16, null, null);
INSERT INTO abstract_schedule (schedule_type, scheduleid, start_time, stop_time, schedule_date, task, schedule_end, schedule_start)
VALUES (1, 8, null, null, null, 16, '2023-11-15 12:30:00.000', '2023-11-15 14:45:30.500'),
(1, 9, '2023-11-16 12:35:00.000', null, null, 17, '2023-11-16 12:30:00.000', '2023-11-16 14:45:30.500'),
(1, 10, '2023-11-17 12:35:00.000', '2023-11-17 12:45:00.000', null, 17, '2023-11-16 12:30:00.000', '2023-11-16 14:45:30.500'),
(1, 11, null, null, null, 17, '2010-11-16 12:30:00.000', '2010-11-16 14:45:30.500'),
(1, 12, null, null, null, 18, '2010-11-16 12:30:00.000', '2010-11-16 14:45:30.500');

View File

@ -19,3 +19,5 @@ INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, f
INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, finished, work_time) VALUES (15, NULL, 0, NULL, 'Task 15', 2, false, 0); INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, finished, work_time) VALUES (15, NULL, 0, NULL, 'Task 15', 2, false, 0);
INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, finished, work_time) VALUES (16, NULL, 0, NULL, 'Task 15', 9, false, 0); INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, finished, work_time) VALUES (16, NULL, 0, NULL, 'Task 15', 9, false, 0);
INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, finished, work_time) VALUES (17, NULL, 0, NULL, 'Task 17', 9, false, 0);
INSERT INTO tasks (taskid, deadline, eta, start_date, task_name, taskgroup_id, finished, work_time) VALUES (18, NULL, 0, NULL, 'Task 17', 10, true, 0);

View File

@ -13,3 +13,4 @@ INSERT INTO taskgroups (taskgroupid, name, parent_id, taskgroupuser) VALUES (7,
INSERT INTO taskgroups (taskgroupid, name, parent_id, taskgroupuser) VALUES (8, 'Taskgroup 2.1.2', 6, 1); INSERT INTO taskgroups (taskgroupid, name, parent_id, taskgroupuser) VALUES (8, 'Taskgroup 2.1.2', 6, 1);
INSERT INTO taskgroups (taskgroupid, name, parent_id, taskgroupuser) VALUES (9, 'Taskgroup 1', null, 3); INSERT INTO taskgroups (taskgroupid, name, parent_id, taskgroupuser) VALUES (9, 'Taskgroup 1', null, 3);
INSERT INTO taskgroups (taskgroupid, name, parent_id, taskgroupuser) VALUES (10, 'Taskgroup 2', null, 3);

View File

@ -23,7 +23,9 @@
"@angular/router": "^16.2.7", "@angular/router": "^16.2.7",
"angular-calendar": "^0.31.0", "angular-calendar": "^0.31.0",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"luxon": "^3.4.3",
"moment": "^2.29.4", "moment": "^2.29.4",
"ngx-material-timepicker": "^13.1.1",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.13.3" "zone.js": "~0.13.3"
@ -4395,6 +4397,12 @@
"integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==",
"dev": true "dev": true
}, },
"node_modules/@types/luxon": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.4.tgz",
"integrity": "sha512-H9OXxv4EzJwE75aTPKpiGXJq+y4LFxjpsdgKwSmr503P5DkWc3AG7VAFYrFNVvqemT5DfgZJV9itYhqBHSGujA==",
"peer": true
},
"node_modules/@types/mime": { "node_modules/@types/mime": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz",
@ -9170,6 +9178,14 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/luxon": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
"integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==",
"engines": {
"node": ">=12"
}
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.1", "version": "0.30.1",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
@ -9737,6 +9753,18 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true "dev": true
}, },
"node_modules/ngx-material-timepicker": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/ngx-material-timepicker/-/ngx-material-timepicker-13.1.1.tgz",
"integrity": "sha512-GST4IBFXrPSBB5VP5LVxoOk1yHbdSnaB293tjuyu+vusg+pQ/3+AtcxQEIadk6Nmsdt8zKsbXNgvLrI4nbYRKQ==",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"@types/luxon": ">= 1.11.1",
"luxon": ">= 1.24.0"
}
},
"node_modules/nice-napi": { "node_modules/nice-napi": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",

View File

@ -25,7 +25,9 @@
"@angular/router": "^16.2.7", "@angular/router": "^16.2.7",
"angular-calendar": "^0.31.0", "angular-calendar": "^0.31.0",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"luxon": "^3.4.3",
"moment": "^2.29.4", "moment": "^2.29.4",
"ngx-material-timepicker": "^13.1.1",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.13.3" "zone.js": "~0.13.3"

View File

@ -15,6 +15,9 @@ encoder.ts
git_push.sh git_push.sh
index.ts index.ts
model/accountDeleteRequest.ts model/accountDeleteRequest.ts
model/advancedScheduleFieldInfo.ts
model/advancedScheduleInfo.ts
model/advancedScheduleInfoAllOf.ts
model/basicScheduleEntityInfo.ts model/basicScheduleEntityInfo.ts
model/basicScheduleFieldInfo.ts model/basicScheduleFieldInfo.ts
model/basicScheduleInfo.ts model/basicScheduleInfo.ts

View File

@ -18,6 +18,7 @@ import { HttpClient, HttpHeaders, HttpParams,
import { CustomHttpParameterCodec } from '../encoder'; import { CustomHttpParameterCodec } from '../encoder';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AdvancedScheduleFieldInfo } from '../model/models';
import { BasicScheduleFieldInfo } from '../model/models'; import { BasicScheduleFieldInfo } from '../model/models';
import { ForgottenActivityRequest } from '../model/models'; import { ForgottenActivityRequest } from '../model/models';
import { ScheduleActivateInfo } from '../model/models'; import { ScheduleActivateInfo } from '../model/models';
@ -378,6 +379,146 @@ export class ScheduleService {
); );
} }
/**
* reschedules task
* reschedules a task
* @param scheduleID internal id of schedule
* @param advancedScheduleFieldInfo
* @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 schedulesScheduleIDAdvancedPost(scheduleID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesScheduleIDAdvancedPost(scheduleID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesScheduleIDAdvancedPost(scheduleID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesScheduleIDAdvancedPost(scheduleID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (scheduleID === null || scheduleID === undefined) {
throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDAdvancedPost.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/advanced`,
advancedScheduleFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* reschedules task
* reschedules a task
* @param scheduleID internal id of schedule
* @param basicScheduleFieldInfo
* @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 schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (scheduleID === null || scheduleID === undefined) {
throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDBasicPost.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/basic`,
basicScheduleFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/** /**
* deletes schedule * deletes schedule
* deletes a schedule * deletes a schedule
@ -438,19 +579,18 @@ export class ScheduleService {
} }
/** /**
* reschedules task * load schedule
* reschedules a task * gets details of schedule
* @param scheduleID internal id of schedule * @param scheduleID internal id of schedule
* @param basicScheduleFieldInfo
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @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. * @param reportProgress flag to report request and response progress.
*/ */
public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>; public schedulesScheduleIDDetailsGet(scheduleID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>; public schedulesScheduleIDDetailsGet(scheduleID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>; public schedulesScheduleIDDetailsGet(scheduleID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesScheduleIDPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> { public schedulesScheduleIDDetailsGet(scheduleID: number, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (scheduleID === null || scheduleID === undefined) { if (scheduleID === null || scheduleID === undefined) {
throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDPost.'); throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDDetailsGet.');
} }
let localVarHeaders = this.defaultHeaders; let localVarHeaders = this.defaultHeaders;
@ -480,22 +620,12 @@ export class ScheduleService {
} }
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json'; let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text'; responseType_ = 'text';
} }
return this.httpClient.post<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}`, return this.httpClient.get<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/details`,
basicScheduleFieldInfo,
{ {
context: localVarHttpContext, context: localVarHttpContext,
responseType: <any>responseType_, responseType: <any>responseType_,
@ -628,6 +758,146 @@ export class ScheduleService {
); );
} }
/**
* creates advanced schedule for task
* creates a advanced schedule for a task
* @param taskID internal id of task
* @param advancedScheduleFieldInfo
* @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 schedulesTaskIDAdvancedPut(taskID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesTaskIDAdvancedPut(taskID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesTaskIDAdvancedPut(taskID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesTaskIDAdvancedPut(taskID: number, advancedScheduleFieldInfo?: AdvancedScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDAdvancedPut.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.put<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/advanced`,
advancedScheduleFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* creates basic schedule for task
* creates a basic schedule for a task
* @param taskID internal id of task
* @param basicScheduleFieldInfo
* @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 schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDBasicPut.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.put<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/basic`,
basicScheduleFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/** /**
* registers forgotten schedule * registers forgotten schedule
* Registers forgotten schedule * Registers forgotten schedule
@ -817,74 +1087,4 @@ export class ScheduleService {
); );
} }
/**
* creates basic schedule for task
* creates a basic schedule for a task
* @param taskID internal id of task
* @param basicScheduleFieldInfo
* @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 schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesTaskIDPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (taskID === null || taskID === undefined) {
throw new Error('Required parameter taskID was null or undefined when calling schedulesTaskIDPut.');
}
let localVarHeaders = this.defaultHeaders;
let localVarCredential: string | undefined;
// authentication (API_TOKEN) required
localVarCredential = this.configuration.lookupCredential('API_TOKEN');
if (localVarCredential) {
localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential);
}
let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (localVarHttpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}
let localVarHttpContext: HttpContext | undefined = options && options.context;
if (localVarHttpContext === undefined) {
localVarHttpContext = new HttpContext();
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.put<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}`,
basicScheduleFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
} }

View File

@ -0,0 +1,18 @@
/**
* API Title
* 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.
*/
export interface AdvancedScheduleFieldInfo {
scheduleStartTime: string;
scheduleStopTime: string;
}

View File

@ -0,0 +1,53 @@
/**
* API Title
* 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 { AdvancedScheduleInfoAllOf } from './advancedScheduleInfoAllOf';
import { TaskgroupEntityInfo } from './taskgroupEntityInfo';
import { TaskShortInfo } from './taskShortInfo';
import { ScheduleInfo } from './scheduleInfo';
export interface AdvancedScheduleInfo {
/**
* internal id of schedule
*/
scheduleID: number;
/**
* type of schedule
*/
scheduleType: AdvancedScheduleInfo.ScheduleTypeEnum;
/**
* date on which the task schedule was started
*/
startTime: string;
/**
* date on which the tasks schedule was finished
*/
finishedTime?: string;
/**
* number in minutes that the schedule was active
*/
activeMinutes: number;
task: TaskShortInfo;
taskgroupPath: Array<TaskgroupEntityInfo>;
scheduleStartTime: string;
scheduleStopTime: string;
}
export namespace AdvancedScheduleInfo {
export type ScheduleTypeEnum = 'BASIC' | 'MODERATE' | 'ADVANCED';
export const ScheduleTypeEnum = {
Basic: 'BASIC' as ScheduleTypeEnum,
Moderate: 'MODERATE' as ScheduleTypeEnum,
Advanced: 'ADVANCED' as ScheduleTypeEnum
};
}

View File

@ -0,0 +1,18 @@
/**
* API Title
* 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.
*/
export interface AdvancedScheduleInfoAllOf {
scheduleStartTime: string;
scheduleStopTime: string;
}

View File

@ -1,4 +1,7 @@
export * from './accountDeleteRequest'; export * from './accountDeleteRequest';
export * from './advancedScheduleFieldInfo';
export * from './advancedScheduleInfo';
export * from './advancedScheduleInfoAllOf';
export * from './basicScheduleEntityInfo'; export * from './basicScheduleEntityInfo';
export * from './basicScheduleFieldInfo'; export * from './basicScheduleFieldInfo';
export * from './basicScheduleInfo'; export * from './basicScheduleInfo';

View File

@ -74,6 +74,11 @@ import { MissedScheduleForgetConfirmationDialogComponent } from './missed-schedu
import { OverdueTaskOverviewComponent } from './overdue-task-overview/overdue-task-overview.component'; import { OverdueTaskOverviewComponent } from './overdue-task-overview/overdue-task-overview.component';
import { UpcomingTaskOverviewComponent } from './upcoming-task-overview/upcoming-task-overview.component'; import { UpcomingTaskOverviewComponent } from './upcoming-task-overview/upcoming-task-overview.component';
import { ActiveTaskOverviewComponent } from './active-task-overview/active-task-overview.component'; import { ActiveTaskOverviewComponent } from './active-task-overview/active-task-overview.component';
import { AdvancedSchedulerComponent } from './schedules/advanced-scheduler/advanced-scheduler.component';
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";
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
@ -110,7 +115,9 @@ import { ActiveTaskOverviewComponent } from './active-task-overview/active-task-
MissedScheduleForgetConfirmationDialogComponent, MissedScheduleForgetConfirmationDialogComponent,
OverdueTaskOverviewComponent, OverdueTaskOverviewComponent,
UpcomingTaskOverviewComponent, UpcomingTaskOverviewComponent,
ActiveTaskOverviewComponent ActiveTaskOverviewComponent,
AdvancedSchedulerComponent,
DateTimePickerComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -147,7 +154,9 @@ import { ActiveTaskOverviewComponent } from './active-task-overview/active-task-
CalendarModule.forRoot({provide: DateAdapter, useFactory: adapterFactory}), CalendarModule.forRoot({provide: DateAdapter, useFactory: adapterFactory}),
MatSelectModule, MatSelectModule,
MatTreeModule, MatTreeModule,
MatAutocompleteModule MatAutocompleteModule,
NgxMaterialTimepickerModule,
MatSliderModule
], ],
providers: [ providers: [
HttpClientModule, HttpClientModule,

View File

@ -0,0 +1,3 @@
mat-form-field {
width: 50%;
}

View File

@ -0,0 +1,10 @@
<mat-form-field appearance="fill">
<input matInput readonly [matDatepicker]="picker" (dateChange)="openTimePicker()" [formControl]="dateControl">
<mat-datepicker #picker></mat-datepicker>
<mat-datepicker-toggle matIconSuffix [for]="picker" ></mat-datepicker-toggle>
</mat-form-field>
<mat-form-field appearance="fill">
<input [ngxTimepicker]="toggleTimepicker" [disableClick]="true" readonly matInput [format]="24" [formControl]="timeControl" >
<ngx-material-timepicker-toggle matSuffix [for]="toggleTimepicker"></ngx-material-timepicker-toggle>
<ngx-material-timepicker #toggleTimepicker (timeSet)="onTimeSet($event)"></ngx-material-timepicker>
</mat-form-field>

View File

@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DateTimePickerComponent } from './date-time-picker.component';
describe('DateTimePickerComponent', () => {
let component: DateTimePickerComponent;
let fixture: ComponentFixture<DateTimePickerComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DateTimePickerComponent]
});
fixture = TestBed.createComponent(DateTimePickerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,53 @@
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild} from "@angular/core";
import {MatDatepicker} from "@angular/material/datepicker";
import {NgxMaterialTimepickerComponent, NgxMaterialTimepickerToggleComponent} from "ngx-material-timepicker";
import {FormControl, Validators} from "@angular/forms";
import * as moment from "moment";
@Component({
selector: 'app-date-time-picker',
templateUrl: './date-time-picker.component.html',
styleUrls: ['./date-time-picker.component.css']
})
export class DateTimePickerComponent implements OnInit, OnChanges{
@ViewChild('picker') picker?: MatDatepicker<any>;
@ViewChild('toggleTimepicker') toggleTimepicker?: NgxMaterialTimepickerComponent
@Output('onTimeSet') timeSet: EventEmitter<Date> = new EventEmitter<Date>();
@Input('date') date: Date | undefined
dateControl: FormControl = new FormControl('', [Validators.required])
timeControl: FormControl = new FormControl('', [Validators.required])
constructor() { }
ngOnInit() {
}
ngOnChanges() {
if(this.date != undefined) {
this.setDateTime(this.date);
}
}
setDateTime(date: Date) {
console.log(date)
this.dateControl.setValue(date);
const timeString = date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });
this.timeControl.setValue(timeString);
}
openTimePicker() {
this.toggleTimepicker!.open();
}
onTimeSet(time: string) {
let selectedDate = new Date(this.dateControl.value)
const [hours, minutes] = time.split(":")
selectedDate.setHours(parseInt(hours, 10));
selectedDate.setMinutes(parseInt(minutes, 10));
this.timeSet.emit(selectedDate);
}
}

View File

@ -13,7 +13,14 @@
<mat-progress-bar mode="determinate" [value]="schedule.activeMinutes"></mat-progress-bar> <mat-progress-bar mode="determinate" [value]="schedule.activeMinutes"></mat-progress-bar>
<div class="originally-planned-container"> <div class="originally-planned-container">
<div style="width: 100%"> <div style="width: 100%">
<p style="display: inline-block"><i>Originally planned:</i> {{toBasicSchedule(schedule).scheduleDate}}</p> <p style="display: inline-block"><i>Originally planned:</i>
<span *ngIf="schedule.scheduleType == 'BASIC'">{{toBasicSchedule(schedule).scheduleDate}}</span>
<span *ngIf="schedule.scheduleType == 'ADVANCED'">
<span> {{toAdvancedSchedule(schedule).scheduleStartTime | date:'EEEE, d MMM. y'}}</span>
<span> to </span>
<span>{{toAdvancedSchedule(schedule).scheduleStopTime | date: 'd MMM. y'}} </span>
</span>
</p>
</div> </div>
<div style="width: 100%" class="reschedule-actions-container"> <div style="width: 100%" class="reschedule-actions-container">
<button mat-raised-button color="primary" class="rescheduleBtn" <button mat-raised-button color="primary" class="rescheduleBtn"

View File

@ -1,5 +1,5 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {BasicScheduleInfo, ScheduleInfo, ScheduleService} from "../../api"; import {AdvancedScheduleInfo, BasicScheduleInfo, ScheduleInfo, ScheduleService} from "../../api";
import {NavigationLink} from "../navigation-link-list/navigation-link-list.component"; import {NavigationLink} from "../navigation-link-list/navigation-link-list.component";
import {MatSnackBar} from "@angular/material/snack-bar"; import {MatSnackBar} from "@angular/material/snack-bar";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
@ -67,4 +67,8 @@ export class MissedSchedulesComponent implements OnInit{
toBasicSchedule(schedule: ScheduleInfo) { toBasicSchedule(schedule: ScheduleInfo) {
return schedule as BasicScheduleInfo return schedule as BasicScheduleInfo
} }
toAdvancedSchedule(schedule: ScheduleInfo) {
return schedule as AdvancedScheduleInfo
}
} }

View File

@ -0,0 +1,14 @@
app-date-time-picker {
margin-right: 20px;
}
.example-label-container {
display: flex;
justify-content: space-between;
margin: 0;
}
.scheduleBtn {
margin-top: 20px;
}

View File

@ -0,0 +1,35 @@
<div class="scheduler-container">
<!--<input [ngxTimepicker]="picker" [format]="24">
<ngx-material-timepicker #picker ></ngx-material-timepicker>-->
<!---->
<div>
<app-date-time-picker #startTimePicker (onTimeSet)="onStartTimeSet($event)" [date]="selectedStartTime"></app-date-time-picker>
<app-date-time-picker #stopTimePicker (onTimeSet)="onStopTimeSet($event)" [date]="selectedStopTime"></app-date-time-picker>
</div>
<div style="width: 100%; display: flex; align-items: center; justify-content: space-between" >
<div style="width: 90%;">
<div class="example-label-container">
<label id="example-name-label" class="example-name-label">0</label>
<label class="example-value-label">{{task!.eta}}</label>
</div>
<mat-slider min="0" [max]="task!.eta" step="15" style="width: 100%;" [discrete]="true" [showTickMarks]="true" #slider >
<input matSliderThumb [(ngModel)]="slideMinutes">
</mat-slider>
</div>
<button style="margin-left: 20px" mat-raised-button color="primary" (click)="addSlideMinutes()">Add</button>
</div>
<div class="progress-stacked" >
<div class="progress" role="progressbar" aria-label="Segment one" aria-valuenow="15" aria-valuemin="0" aria-valuemax="100" [style.width]=currentProgress>
<div class="progress-bar">{{currentProgress}}</div>
</div>
<div class="progress" role="progressbar" aria-label="Segment two" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100" [style.width]=futureProgress>
<div class="progress-bar bg-success">{{futureProgress}}</div>
</div>
</div>
<button class="scheduleBtn" mat-raised-button color="primary" (click)="schedule()">Schedule</button>
</div>

View File

@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdvancedSchedulerComponent } from './advanced-scheduler.component';
describe('AdvancedSchedulerComponent', () => {
let component: AdvancedSchedulerComponent;
let fixture: ComponentFixture<AdvancedSchedulerComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AdvancedSchedulerComponent]
});
fixture = TestBed.createComponent(AdvancedSchedulerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,166 @@
import {
AfterContentInit,
AfterViewInit,
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
ViewChild
} from '@angular/core';
import {
AdvancedScheduleFieldInfo, AdvancedScheduleInfo,
ScheduleInfo,
ScheduleService,
TaskEntityInfo,
TaskgroupEntityInfo
} from "../../../api";
import {DateTimePickerComponent} from "../../date-time-picker/date-time-picker.component";
import * as moment from "moment";
@Component({
selector: 'app-advanced-scheduler',
templateUrl: './advanced-scheduler.component.html',
styleUrls: ['./advanced-scheduler.component.css']
})
export class AdvancedSchedulerComponent implements OnInit, OnChanges{
@Input() task: TaskEntityInfo | undefined;
@Input() taskgroup: TaskgroupEntityInfo | undefined
@Input() scheduleInfo: ScheduleInfo | undefined
@ViewChild('startTimePicker') startTimePicker?: DateTimePickerComponent;
@ViewChild('stopTimePicker') stopTimePicker?: DateTimePickerComponent;
slideMinutes: number = 0;
@Output('onStartTimeSet') startTimeEmitter : EventEmitter<Date> = new EventEmitter<Date>();
@Output('onEndTimeSet') endTimeEmitter : EventEmitter<Date> = new EventEmitter<Date>();
@Output('onSchedule') onSchedule: EventEmitter<AdvancedScheduleInfo> = new EventEmitter<AdvancedScheduleInfo>();
selectedStartTime: Date | undefined
selectedStopTime: Date | undefined
currentProgress: string = "30%";
futureProgress: string = "60%"
constructor(private scheduleService: ScheduleService) {
}
ngOnInit() {
this.calcFutureProgress();
this.calcCurrentProgress();
if(this.scheduleInfo != undefined) {
const schedule = this.scheduleInfo as AdvancedScheduleInfo
this.selectedStartTime = new Date(schedule.scheduleStartTime);
this.selectedStopTime = new Date(schedule.scheduleStopTime);
this.calcFutureProgress();
this.calcCurrentProgress();
}
}
ngOnChanges() {
}
setDate(clickedDate: Date) {
if(this.selectedStartTime == undefined) {
this.startTimePicker!.setDateTime(clickedDate);
this.selectedStartTime = clickedDate;
} else {
this.stopTimePicker!.setDateTime(clickedDate);
this.selectedStopTime = clickedDate;
}
this.calcFutureProgress();
}
setStopTime(selectedDate: Date) {
this.selectedStopTime = selectedDate
this.stopTimePicker!.setDateTime(selectedDate);
this.calcFutureProgress();
}
setStartTime(selectedDate: Date) {
this.selectedStartTime = selectedDate;
this.startTimePicker!.setDateTime(selectedDate);
this.calcFutureProgress();
}
onStartTimeSet(selectedDate: Date) {
this.selectedStartTime = selectedDate;
this.startTimeEmitter.emit(selectedDate)
this.calcFutureProgress();
}
onStopTimeSet(selectedDate: Date) {
this.selectedStopTime = selectedDate;
this.endTimeEmitter.emit(selectedDate);
this.calcFutureProgress();
}
calcCurrentProgress() {
if(this.task!.eta == 0) {
this.currentProgress = "0%";
} else {
const fraction = this.task!.workTime / this.task!.eta * 100;
this.currentProgress = fraction + "%";
}
}
calcFutureProgress() {
//const currentProgressNumber = parseFloat(this.currentProgress.slice(0, -1)) / 100;
if(this.selectedStartTime != undefined && this.selectedStopTime != undefined) {
const fraction = this.dateDiffInDays(this.selectedStartTime, this.selectedStopTime) / this.task!.eta * 100
this.futureProgress = fraction + "%";
} else {
this.futureProgress = "0%";
}
}
dateDiffInDays(a: Date, b: Date) {
const diffMs = b.getTime() - a.getTime();
return Math.floor((diffMs / 1000) / 60);
}
schedule() {
if(this.scheduleInfo == undefined) {
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')
}).subscribe({
next: resp => {
this.onSchedule.emit(resp as AdvancedScheduleInfo);
}
})
} else {
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')
}).subscribe({
next: resp => {
this.onSchedule.emit(resp as AdvancedScheduleInfo);
console.log("Rescheduled")
}
})
}
}
addSlideMinutes() {
if(this.selectedStartTime != undefined) {
const updatedStopTime = moment(this.selectedStartTime);
updatedStopTime.add(this.slideMinutes, 'm');
if(updatedStopTime.isAfter(moment(this.selectedStopTime))) {
this.setStopTime(updatedStopTime.toDate());
}
}
}
}

View File

@ -2,7 +2,7 @@ import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges
import {FormControl, Validators} from "@angular/forms"; import {FormControl, Validators} from "@angular/forms";
import { import {
BasicScheduleEntityInfo, BasicScheduleEntityInfo,
BasicScheduleInfo, BasicScheduleInfo, ScheduleInfo,
ScheduleService, ScheduleService,
TaskEntityInfo, TaskEntityInfo,
TaskgroupEntityInfo TaskgroupEntityInfo
@ -20,7 +20,7 @@ export class BasicSchedulerComponent implements OnChanges{
dateCtrl: FormControl = new FormControl('', [Validators.required]) dateCtrl: FormControl = new FormControl('', [Validators.required])
@Input('taskgroup') taskgroup: TaskgroupEntityInfo | undefined @Input('taskgroup') taskgroup: TaskgroupEntityInfo | undefined
@Input('task') task: TaskEntityInfo | undefined @Input('task') task: TaskEntityInfo | undefined
@Input('scheduleInfo') scheduleEntityInfo: BasicScheduleEntityInfo | undefined @Input('scheduleInfo') scheduleEntityInfo: ScheduleInfo | undefined
@Output('onSchedule') scheduleEmitter: EventEmitter<BasicScheduleEntityInfo> = new EventEmitter<BasicScheduleEntityInfo>(); @Output('onSchedule') scheduleEmitter: EventEmitter<BasicScheduleEntityInfo> = new EventEmitter<BasicScheduleEntityInfo>();
constructor(private scheduleService: ScheduleService, constructor(private scheduleService: ScheduleService,
@ -35,7 +35,7 @@ export class BasicSchedulerComponent implements OnChanges{
schedule() { schedule() {
if(this.task != undefined) { if(this.task != undefined) {
if(this.scheduleEntityInfo == undefined) { if(this.scheduleEntityInfo == undefined) {
this.scheduleService.schedulesTaskIDPut(this.task.taskID, { this.scheduleService.schedulesTaskIDBasicPut(this.task.taskID, {
scheduleDate: this.dateCtrl.value scheduleDate: this.dateCtrl.value
}).subscribe({ }).subscribe({
next: resp => { next: resp => {
@ -43,7 +43,7 @@ export class BasicSchedulerComponent implements OnChanges{
} }
}) })
} else { } else {
this.scheduleService.schedulesScheduleIDPost(this.scheduleEntityInfo!.scheduleID, { this.scheduleService.schedulesScheduleIDBasicPost(this.scheduleEntityInfo!.scheduleID, {
scheduleDate: this.dateCtrl.value scheduleDate: this.dateCtrl.value
}).subscribe({ }).subscribe({
next: resp => { next: resp => {
@ -72,13 +72,10 @@ export class BasicSchedulerComponent implements OnChanges{
ngOnChanges(): void { ngOnChanges(): void {
if(this.scheduleEntityInfo != undefined) { if(this.scheduleEntityInfo != undefined) {
this.dateCtrl.setValue(this.scheduleEntityInfo!.scheduleID) const schedule = this.scheduleEntityInfo as BasicScheduleInfo
this.dateCtrl.setValue(schedule.scheduleDate)
} }
} }
setEditedBasicSchedule(basicSchedule: BasicScheduleEntityInfo) {
this.dateCtrl.setValue(basicSchedule.scheduleDate)
this.scheduleEntityInfo = basicSchedule;
console.log(this.dateCtrl.value)
}
} }

View File

@ -12,3 +12,7 @@
.scheduleContainer { .scheduleContainer {
margin-bottom: 5px; margin-bottom: 5px;
} }
.advanced-info {
color: #6e6e6e;
}

View File

@ -1,6 +1,6 @@
<mat-card *ngFor="let schedule of schedules" class="scheduleContainer"> <mat-card *ngFor="let schedule of schedules" class="scheduleContainer">
<mat-card-content> <mat-card-content>
<ng-container *ngIf="schedule.scheduleType == 'BASIC'"> <div *ngIf="schedule.scheduleType == 'BASIC'">
<div class="basicScheduleContainer"> <div class="basicScheduleContainer">
<p class="basicScheduleContent">{{ toBasicSchedule(schedule).scheduleDate | date:'EEEE, d MMM. y'}}</p> <p class="basicScheduleContent">{{ toBasicSchedule(schedule).scheduleDate | date:'EEEE, d MMM. y'}}</p>
<div class="basicScheduleContent"> <div class="basicScheduleContent">
@ -8,8 +8,23 @@
<button mat-icon-button color="warn" (click)="deleteSchedule(schedule)"><mat-icon>delete</mat-icon></button> <button mat-icon-button color="warn" (click)="deleteSchedule(schedule)"><mat-icon>delete</mat-icon></button>
</div> </div>
</div> </div>
</div>
</ng-container> <div *ngIf="schedule.scheduleType == 'ADVANCED'">
<div class="basicScheduleContainer">
<div class="basicScheduleContent">
<p>
<span>{{ toAdvancedSchedule(schedule).scheduleStartTime | date:'EEEE, d MMM. y'}}</span>
<span> to </span>
<span>{{ toAdvancedSchedule(schedule).scheduleStopTime | date:'EEEE, d MMM. y'}}</span>
</p>
<p class="advanced-info">Minutes: {{calcDurationOfAdvancedSchedule(schedule)}}</p>
</div>
<div class="basicScheduleContent">
<button mat-icon-button color="primary" [routerLink]="['/taskgroups', taskgroup!.taskgroupID, 'tasks', task!.taskID, 'schedule', schedule.scheduleID]"><mat-icon>edit</mat-icon></button>
<button mat-icon-button color="warn" (click)="deleteSchedule(schedule)"><mat-icon>delete</mat-icon></button>
</div>
</div>
</div>

View File

@ -1,5 +1,6 @@
import {Component, Input, OnInit} from '@angular/core'; import {Component, Input, OnInit} from '@angular/core';
import { import {
AdvancedScheduleInfo,
BasicScheduleEntityInfo, BasicScheduleInfo, BasicScheduleEntityInfo, BasicScheduleInfo,
ScheduleInfo, ScheduleInfo,
ScheduleService, ScheduleService,
@ -7,6 +8,7 @@ import {
TaskgroupEntityInfo TaskgroupEntityInfo
} from "../../../api"; } from "../../../api";
import {MatSnackBar} from "@angular/material/snack-bar"; import {MatSnackBar} from "@angular/material/snack-bar";
import {AdvancedSchedulerComponent} from "../advanced-scheduler/advanced-scheduler.component";
@Component({ @Component({
selector: 'app-schedule-dashboard', selector: 'app-schedule-dashboard',
@ -57,4 +59,14 @@ export class ScheduleDashboardComponent implements OnInit{
toBasicSchedule(schedule: ScheduleInfo) { toBasicSchedule(schedule: ScheduleInfo) {
return schedule as BasicScheduleInfo return schedule as BasicScheduleInfo
} }
toAdvancedSchedule(schedule: ScheduleInfo) {
return schedule as AdvancedScheduleInfo
}
calcDurationOfAdvancedSchedule(schedule: ScheduleInfo) {
const advancedSchedule = schedule as AdvancedScheduleInfo
const diffMs = new Date(advancedSchedule.scheduleStopTime).getTime() - new Date(advancedSchedule.scheduleStartTime).getTime();
return Math.floor((diffMs / 1000) / 60);
}
} }

View File

@ -25,3 +25,4 @@
.long-form { .long-form {
width: 100%; width: 100%;
} }

View File

@ -16,9 +16,15 @@
<mwl-calendar-week-view [viewDate]="viewDate" [daysInWeek]="daysInWeek" [dayStartHour]="7" [dayEndHour]="21" [refresh]="refresh" <mwl-calendar-week-view [viewDate]="viewDate" [daysInWeek]="daysInWeek" [dayStartHour]="7" [dayEndHour]="21" [refresh]="refresh"
(dayHeaderClicked)="timeClick($event.day.date)" (dayHeaderClicked)="timeClick($event.day.date)"
(hourSegmentClicked)="timeClick($event.date)" [events]="events" (eventClicked)="eventClicked($event)" (hourSegmentClicked)="timeClick($event.date)" [events]="events" (eventClicked)="eventClicked($event)"
(eventTimesChanged)="eventTimesChanged($event)"
> >
</mwl-calendar-week-view> </mwl-calendar-week-view>
<app-basic-scheduler *ngIf="scheduleStrategy === 1" #basicScheduler [task]="task" [taskgroup]="taskgroup" (onSchedule)="onBasicSchedule($event)"></app-basic-scheduler> <app-basic-scheduler *ngIf="scheduleStrategy === 1" #basicScheduler [task]="task" [taskgroup]="taskgroup" (onSchedule)="onBasicSchedule($event)"
[scheduleInfo]="editedSchedule"
></app-basic-scheduler>
<app-advanced-scheduler *ngIf="scheduleStrategy === 3" #advancedScheduler [task]="task" [taskgroup]="taskgroup"
(onStartTimeSet)="eventTimesExternalChange($event, true)" (onEndTimeSet)="eventTimesExternalChange($event, false)"
(onSchedule)="onAdvancedSchedule($event)" [scheduleInfo]="editedSchedule"
></app-advanced-scheduler>
</div> </div>

View File

@ -1,19 +1,22 @@
import {Component, OnInit, ViewChild} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component"; import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component";
import { import {
BasicScheduleEntityInfo, BasicScheduleInfo, ScheduleService, AdvancedScheduleInfo,
BasicScheduleEntityInfo, BasicScheduleInfo, ScheduleInfo, ScheduleService,
TaskEntityInfo, TaskEntityInfo,
TaskgroupEntityInfo, TaskgroupEntityInfo,
TaskgroupService, TaskgroupService,
TaskService, TaskShortInfo TaskService, TaskShortInfo
} from "../../../api"; } from "../../../api";
import {ActivatedRoute, Router} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {CalendarDateFormatter, CalendarEvent, CalendarView} from "angular-calendar"; import {CalendarDateFormatter, CalendarEvent, CalendarEventTimesChangedEvent, CalendarView} from "angular-calendar";
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import {CalendarDatePipe} from "angular-calendar/modules/common/calendar-date/calendar-date.pipe"; import {CalendarDatePipe} from "angular-calendar/modules/common/calendar-date/calendar-date.pipe";
import {BasicSchedulerComponent} from "../basic-scheduler/basic-scheduler.component"; import {BasicSchedulerComponent} from "../basic-scheduler/basic-scheduler.component";
import * as events from "events"; import * as events from "events";
import { EventColor } from 'calendar-utils'; import { EventColor } from 'calendar-utils';
import {AdvancedSchedulerComponent} from "../advanced-scheduler/advanced-scheduler.component";
import * as moment from "moment";
const colors: Record<string, EventColor> = { const colors: Record<string, EventColor> = {
red: { red: {
@ -50,6 +53,7 @@ export class SchedulerComponent implements OnInit{
taskgroupPath: TaskgroupEntityInfo[] = [] taskgroupPath: TaskgroupEntityInfo[] = []
taskgroupID: number = -1; taskgroupID: number = -1;
scheduleID: number = -1; scheduleID: number = -1;
editedSchedule: ScheduleInfo | undefined
@ViewChild('navLinkList') navLinkListComponent: NavigationLinkListComponent | undefined @ViewChild('navLinkList') navLinkListComponent: NavigationLinkListComponent | undefined
task: TaskEntityInfo | undefined task: TaskEntityInfo | undefined
@ -66,6 +70,7 @@ export class SchedulerComponent implements OnInit{
events: CalendarEvent[] = [] events: CalendarEvent[] = []
@ViewChild('basicScheduler') basicScheduler: BasicSchedulerComponent | undefined @ViewChild('basicScheduler') basicScheduler: BasicSchedulerComponent | undefined
@ViewChild('advancedScheduler') advancedScheduler: AdvancedSchedulerComponent | undefined
constructor(private activatedRoute: ActivatedRoute, constructor(private activatedRoute: ActivatedRoute,
private taskgroupService: TaskgroupService, private taskgroupService: TaskgroupService,
@ -99,7 +104,15 @@ export class SchedulerComponent implements OnInit{
} }
if(params.has('scheduleID')) { if(params.has('scheduleID')) {
this.scheduleID = Number(params.get('scheduleID')); this.scheduleService.schedulesScheduleIDDetailsGet(parseInt(params.get('scheduleID')!)).subscribe({
next: resp => {
this.editedSchedule = resp;
this.scheduleID = resp.scheduleID;
if(resp.scheduleType == 'ADVANCED') {
this.scheduleStrategy = 3;
}
}
})
} }
}); });
} }
@ -118,9 +131,39 @@ export class SchedulerComponent implements OnInit{
protected readonly CalendarView = CalendarView; protected readonly CalendarView = CalendarView;
timeClick(clickedDate: Date) { timeClick(clickedDate: Date) {
if(this.basicScheduler != undefined) {
console.log(clickedDate)
if(this.basicScheduler != undefined && this.scheduleStrategy === 1) {
this.basicScheduler.setDate(clickedDate) this.basicScheduler.setDate(clickedDate)
} else if(this.advancedScheduler != undefined && this.scheduleStrategy === 3) {
this.advancedScheduler.setDate(clickedDate)
const endDate: Date = moment(clickedDate).add(30, 'm').toDate();
this.advancedScheduler.setDate(endDate);
this.events.push({
title: this.computeTaskPath(this.taskgroupPath, this.task!),
start: clickedDate,
end: endDate,
color: colors['yellow'],
resizable: {
beforeStart: true,
afterEnd: true
} }
})
this.refresh.next();
}
}
eventTimesChanged({
event,
newStart,
newEnd,
}: CalendarEventTimesChangedEvent): void {
event.start = newStart;
event.end = newEnd;
this.refresh.next();
this.advancedScheduler!.setStartTime(event.start);
this.advancedScheduler!.setStopTime(event.end!);
} }
onBasicSchedule(scheduleInfo: BasicScheduleEntityInfo) { onBasicSchedule(scheduleInfo: BasicScheduleEntityInfo) {
@ -139,10 +182,11 @@ export class SchedulerComponent implements OnInit{
resp.forEach(abstractSchedule => { resp.forEach(abstractSchedule => {
if(abstractSchedule.scheduleType == 'BASIC') { if(abstractSchedule.scheduleType == 'BASIC') {
this.handleFetchedBasicSchedule(abstractSchedule as BasicScheduleInfo) this.handleFetchedBasicSchedule(abstractSchedule as BasicScheduleInfo)
} else if(abstractSchedule.scheduleType == 'ADVANCED') {
this.handleFetchedAdvancedSchedule(abstractSchedule as AdvancedScheduleInfo)
} }
}) })
this.refresh.next();
} }
}) })
} }
@ -159,7 +203,11 @@ export class SchedulerComponent implements OnInit{
title: this.computeTaskPath(schedule.taskgroupPath, schedule.task), title: this.computeTaskPath(schedule.taskgroupPath, schedule.task),
color: color, color: color,
allDay: true, allDay: true,
meta: {
ID: this.scheduleID
}
}) })
this.refresh.next();
} }
} }
@ -176,4 +224,112 @@ export class SchedulerComponent implements OnInit{
return result; return result;
} }
findTaskByTaskPathString(taskgroupPathString: string) :TaskShortInfo {
return this.task!;
}
findEventByTaskPath(taskPath: string, advanced: boolean, scheduleID: number | undefined) {
const events : CalendarEvent<any>[] = this.events.filter(event => event.title == taskPath);
if(scheduleID != -1) {
return this.events.find(calendarEvent => calendarEvent.meta.ID == scheduleID);
}
if(advanced) {
return events.find(calendarEvent => !calendarEvent.allDay)
} else {
return events.find(calendarEvent => calendarEvent.allDay)
}
}
eventTimesExternalChange(selectedDate: Date, start: boolean) {
const event: CalendarEvent<any>| undefined = this.findEventByTaskPath(this.computeTaskPath(this.taskgroupPath, this.task!), true, this.scheduleID);
if(event == undefined) {
if(start) {
this.events.push({
title: this.computeTaskPath(this.taskgroupPath, this.task!),
start: selectedDate,
color: colors['yellow'],
resizable: {
beforeStart: true,
afterEnd: true
},
meta: {
ID: -1
}
})
} else {
const updatedDate = moment(selectedDate).subtract(30, 'm').toDate();
this.events.push({
title: this.computeTaskPath(this.taskgroupPath, this.task!),
start: updatedDate,
color: colors['yellow'],
resizable: {
beforeStart: true,
afterEnd: true
},
meta: {
ID: -1
}
})
this.advancedScheduler!.setStartTime(updatedDate);
}
} else {
if(start) {
event.start = selectedDate;
} else {
event.end = selectedDate
}
}
this.refresh.next();
}
onAdvancedSchedule(schedule: AdvancedScheduleInfo) {
const event: CalendarEvent<any>| undefined = this.findEventByTaskPath(this.computeTaskPath(schedule.taskgroupPath, schedule.task), true, this.scheduleID);
if(event == undefined) {
this.events.push({
title: this.computeTaskPath(schedule.taskgroupPath, schedule.task),
start: new Date(schedule.scheduleStartTime),
end: new Date(schedule.scheduleStopTime),
color: colors['red'],
resizable: {
beforeStart: false,
afterEnd: false
},
meta: {
ID: this.scheduleID
}
})
this.refresh.next();
} else {
event.color = colors['red'];
event.resizable = {
beforeStart: false,
afterEnd: false
}
this.refresh.next();
}
}
private handleFetchedAdvancedSchedule(schedule: AdvancedScheduleInfo) {
let color: EventColor = colors['red']
if(schedule.scheduleID === this.scheduleID) {
color = colors['yellow']
}
this.events.push({
start: new Date(schedule.scheduleStartTime),
end: new Date(schedule.scheduleStopTime),
title: this.computeTaskPath(schedule.taskgroupPath, schedule.task),
color: color,
allDay: false,
meta: {
ID: schedule.scheduleID
}
})
this.refresh.next();
}
} }

View File

@ -10,6 +10,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head> </head>
<body class="mat-typography"> <body class="mat-typography">
<app-root></app-root> <app-root></app-root>

View File

@ -1309,6 +1309,7 @@ paths:
schema: schema:
type: object type: object
$ref: "#/components/schemas/SimpleStatusResponse" $ref: "#/components/schemas/SimpleStatusResponse"
/schedules/{taskID}/basic:
put: put:
security: security:
- API_TOKEN: [] - API_TOKEN: []
@ -1329,6 +1330,140 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/BasicScheduleFieldInfo' $ref: '#/components/schemas/BasicScheduleFieldInfo'
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/ScheduleInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
404:
description: Taskgroup does not exist
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
/schedules/{taskID}/advanced:
put:
security:
- API_TOKEN: []
tags:
- schedule
description: creates a advanced schedule for a task
summary: creates advanced schedule for task
parameters:
- name: taskID
in: path
description: internal id of task
required: true
schema:
type: number
example: 1
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AdvancedScheduleFieldInfo'
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/ScheduleInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
404:
description: Taskgroup does not exist
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
/schedules/{scheduleID}/basic:
post:
security:
- API_TOKEN: []
tags:
- schedule
description: reschedules a task
summary: reschedules task
parameters:
- name: scheduleID
in: path
description: internal id of schedule
required: true
schema:
type: number
example: 1
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/BasicScheduleFieldInfo'
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/ScheduleInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
404:
description: Taskgroup does not exist
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
/schedules/{scheduleID}/advanced:
post:
security:
- API_TOKEN: []
tags:
- schedule
description: reschedules a task
summary: reschedules task
parameters:
- name: scheduleID
in: path
description: internal id of schedule
required: true
schema:
type: number
example: 1
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/AdvancedScheduleFieldInfo'
responses: responses:
200: 200:
description: operation successfull description: operation successfull
@ -1352,48 +1487,6 @@ paths:
type: object type: object
$ref: "#/components/schemas/SimpleStatusResponse" $ref: "#/components/schemas/SimpleStatusResponse"
/schedules/{scheduleID}: /schedules/{scheduleID}:
post:
security:
- API_TOKEN: []
tags:
- schedule
description: reschedules a task
summary: reschedules task
parameters:
- name: scheduleID
in: path
description: internal id of schedule
required: true
schema:
type: number
example: 1
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/BasicScheduleFieldInfo'
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/ScheduleInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
404:
description: Taskgroup does not exist
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
delete: delete:
security: security:
- API_TOKEN: [] - API_TOKEN: []
@ -1737,6 +1830,42 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/SimpleStatusResponse' $ref: '#/components/schemas/SimpleStatusResponse'
/schedules/{scheduleID}/details:
get:
security:
- API_TOKEN: []
tags:
- schedule
description: gets details of schedule
summary: load schedule
parameters:
- name: scheduleID
in: path
description: internal id of schedule
required: true
schema:
type: number
example: 1
responses:
200:
description: Operation successfull
content:
application/json:
schema:
$ref: '#/components/schemas/ScheduleInfo'
403:
description: No permission
content:
application/json:
schema:
$ref: '#/components/schemas/SimpleStatusResponse'
404:
description: Schedule not found
content:
application/json:
schema:
$ref: '#/components/schemas/SimpleStatusResponse'
/history/workingStatus: /history/workingStatus:
get: get:
security: security:
@ -2347,4 +2476,30 @@ components:
type: string type: string
format: date format: date
description: time the schedule was stopped description: time the schedule was stopped
AdvancedScheduleInfo:
allOf:
- $ref: '#/components/schemas/ScheduleInfo'
- type: object
required:
- scheduleStartTime
- scheduleStopTime
additionalProperties: false
properties:
scheduleStartTime:
type: string
format: date-time
scheduleStopTime:
type: string
format: date-time
AdvancedScheduleFieldInfo:
required:
- scheduleStartTime
- scheduleStopTime
additionalProperties: false
properties:
scheduleStartTime:
type: string
format: date
scheduleStopTime:
type: string
format: date