Merge pull request 'issue-18' (#28) from issue-18 into master

Reviewed-on: Sebastian/TimeManager#28
This commit is contained in:
Sebastian 2023-10-28 19:36:14 +02:00
commit 614a98b8cf
89 changed files with 5268 additions and 96 deletions

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">

View File

@ -4,21 +4,13 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Delete and clear Tasks (Frontend)">
<change afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupDetailInfo.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupShortInfo.java" afterDir="false" />
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Load worked minutes when reloading dashboard">
<change afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/taskSchedule/ScheduleStatus.java" 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/TaskgroupController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/api/controller/TaskgroupController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupEntityInfo.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupEntityInfo.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/Taskgroup.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/Taskgroup.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/api/.openapi-generator/FILES" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/api/.openapi-generator/FILES" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/api/api/taskgroup.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/api/api/taskgroup.service.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/api/model/models.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/api/model/models.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/app/app.module.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/app.module.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../openapi.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/../openapi.yaml" 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/api/models/timemanager/taskSchedule/ActiveMinutesInformation.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.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" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -28,6 +20,7 @@
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Enum" />
<option value="Interface" />
<option value="Class" />
</list>
@ -36,7 +29,7 @@
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$/.." value="master" />
<entry key="$PROJECT_DIR$/.." value="issue-23" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
@ -69,7 +62,9 @@
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.lookFeel&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;swagger&quot;,
&quot;ts.external.directory.path&quot;: &quot;/snap/intellij-idea-ultimate/459/plugins/javascript-impl/jsLanguageServicesImpl/external&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
},
&quot;keyToStringList&quot;: {
@ -103,6 +98,16 @@
<workItem from="1697923629354" duration="3164000" />
<workItem from="1697958018921" duration="91000" />
<workItem from="1697958118995" duration="5749000" />
<workItem from="1697969480767" duration="6407000" />
<workItem from="1697989716016" duration="3814000" />
<workItem from="1698067098771" duration="4770000" />
<workItem from="1698127431684" duration="2039000" />
<workItem from="1698164397550" duration="2329000" />
<workItem from="1698246651541" duration="5106000" />
<workItem from="1698298897364" duration="4242000" />
<workItem from="1698426430946" duration="665000" />
<workItem from="1698474363766" duration="3686000" />
<workItem from="1698499063683" duration="7685000" />
</task>
<task id="LOCAL-00001" summary="Structure Taskgroups in Hierarchies">
<option name="closed" value="true" />
@ -144,7 +149,95 @@
<option name="project" value="LOCAL" />
<updated>1697962125518</updated>
</task>
<option name="localTasksCounter" value="6" />
<task id="LOCAL-00006" summary="Define Entity BasicTaskSchedule and Taskcontroller">
<option name="closed" value="true" />
<created>1697976314517</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1697976314517</updated>
</task>
<task id="LOCAL-00007" summary="Delete Schedules">
<option name="closed" value="true" />
<created>1698089745245</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1698089745245</updated>
</task>
<task id="LOCAL-00008" summary="Removed unused TaskgroupShortInfo.java">
<option name="closed" value="true" />
<created>1698168406655</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1698168406655</updated>
</task>
<task id="LOCAL-00009" summary="Fix Foreign Key Constraint Fail when deleting Taskgroups">
<option name="closed" value="true" />
<created>1698247531000</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1698247531000</updated>
</task>
<task id="LOCAL-00010" summary="Stop and Finish TaskSchedules">
<option name="closed" value="true" />
<created>1698306038382</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1698306038383</updated>
</task>
<task id="LOCAL-00011" summary="Include TaskScheduleStopResponse">
<option name="closed" value="true" />
<created>1698306056254</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1698306056254</updated>
</task>
<task id="LOCAL-00012" summary="Fix starting schedule and returning active time of schedule after stop">
<option name="closed" value="true" />
<created>1698306442833</created>
<option name="number" value="00012" />
<option name="presentableId" value="LOCAL-00012" />
<option name="project" value="LOCAL" />
<updated>1698306442833</updated>
</task>
<task id="LOCAL-00013" summary="Remove update spamming in console">
<option name="closed" value="true" />
<created>1698306889808</created>
<option name="number" value="00013" />
<option name="presentableId" value="LOCAL-00013" />
<option name="project" value="LOCAL" />
<updated>1698306889808</updated>
</task>
<task id="LOCAL-00014" summary="Start task now from Taskoverview in Dashboard">
<option name="closed" value="true" />
<created>1698500028161</created>
<option name="number" value="00014" />
<option name="presentableId" value="LOCAL-00014" />
<option name="project" value="LOCAL" />
<updated>1698500028161</updated>
</task>
<task id="LOCAL-00015" summary="Load worked minutes when reloading dashboard">
<option name="closed" value="true" />
<created>1698512058945</created>
<option name="number" value="00015" />
<option name="presentableId" value="LOCAL-00015" />
<option name="project" value="LOCAL" />
<updated>1698512058945</updated>
</task>
<task id="LOCAL-00016" summary="Load worked minutes when reloading dashboard">
<option name="closed" value="true" />
<created>1698512069065</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1698512069065</updated>
</task>
<option name="localTasksCounter" value="17" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -157,7 +250,18 @@
<MESSAGE value="Implementing edit route for tasks" />
<MESSAGE value="Delete and clear Tasks" />
<MESSAGE value="Delete and clear Tasks (Frontend)" />
<option name="LAST_COMMIT_MESSAGE" value="Delete and clear Tasks (Frontend)" />
<MESSAGE value="Define Entity BasicTaskSchedule and Taskcontroller" />
<MESSAGE value="Delete Schedules" />
<MESSAGE value="Deliver Schedule Path Info when fetching Schedules" />
<MESSAGE value="Removed unused TaskgroupShortInfo.java" />
<MESSAGE value="Fix Foreign Key Constraint Fail when deleting Taskgroups" />
<MESSAGE value="Stop and Finish TaskSchedules" />
<MESSAGE value="Include TaskScheduleStopResponse" />
<MESSAGE value="Fix starting schedule and returning active time of schedule after stop" />
<MESSAGE value="Remove update spamming in console" />
<MESSAGE value="Start task now from Taskoverview in Dashboard" />
<MESSAGE value="Load worked minutes when reloading dashboard" />
<option name="LAST_COMMIT_MESSAGE" value="Load worked minutes when reloading dashboard" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
@ -170,4 +274,8 @@
</breakpoints>
</breakpoint-manager>
</component>
<component name="XSLT-Support.FileAssociations.UIState">
<expand />
<select />
</component>
</project>

View File

@ -0,0 +1,204 @@
package core.api.controller;
import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.taskSchedule.*;
import core.entities.User;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.ScheduleType;
import core.entities.timemanager.Task;
import core.repositories.UserRepository;
import core.repositories.timemanager.BasicTaskScheduleRepository;
import core.services.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.*;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api")
public class ScheduleController {
private final TaskService taskService;
private final TaskScheduleService taskScheduleService;
private final BasicTaskScheduleRepository basicTaskScheduleRepository;
private final UserRepository userRepository;
public ScheduleController(@Autowired TaskService taskService, @Autowired TaskScheduleService taskScheduleService,
BasicTaskScheduleRepository basicTaskScheduleRepository,
UserRepository userRepository) {
this.taskService = taskService;
this.taskScheduleService = taskScheduleService;
this.basicTaskScheduleRepository = basicTaskScheduleRepository;
this.userRepository = userRepository;
}
@GetMapping("/schedules/{taskID}/{scheduleType}")
public ResponseEntity<?> loadSchedulesOfTask(@PathVariable long taskID, @PathVariable ScheduleType scheduleType) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskPermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(taskPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
switch (scheduleType) {
case BASIC -> {
List<BasicTaskSchedule> basicTaskScheduleList = new ArrayList<>(taskPermissionResult.getResult().getBasicTaskSchedules());
basicTaskScheduleList.sort(Comparator.comparing(BasicTaskSchedule::getScheduleDate));
return ResponseEntity.ok(basicTaskScheduleList.stream().map(BasicTaskScheduleEntityInfo::new));
}
case ADVANCED, MODERATE -> ResponseEntity.ok(new ArrayList<>());
}
return null;
}
@PutMapping("/schedules/{taskID}/basic")
public ResponseEntity<?> basicScheduleTask(@PathVariable long taskID, @Valid @RequestBody BasicTaskScheduleFieldInfo basicTaskSchedule) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskPermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(taskPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
ServiceResult<BasicTaskSchedule> creationResult = taskScheduleService.createBasicTaskSchedule(taskPermissionResult.getResult(), basicTaskSchedule);
return ResponseEntity.ok(new BasicTaskScheduleEntityInfo(creationResult.getResult()));
}
@PostMapping("/schedules/{scheduleID}/basic")
public ResponseEntity<?> editScheduledTask(@PathVariable long scheduleID, @Valid @RequestBody BasicTaskScheduleFieldInfo basicTaskScheduleFieldInfo) {
PermissionResult<BasicTaskSchedule> 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"));
}
taskScheduleService.reschedule(permissionResult.getResult(), basicTaskScheduleFieldInfo);
return ResponseEntity.ok(new SimpleStatusResponse("success"));
}
@DeleteMapping("/schedules/{scheduleID}/{scheduleType}")
public ResponseEntity<?> deleteScheduledTask(@PathVariable long scheduleID, @PathVariable ScheduleType scheduleType) {
PermissionResult<BasicTaskSchedule> 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"));
}
taskScheduleService.deleteBasicSchedule(permissionResult.getResult());
return ResponseEntity.ok(new SimpleStatusResponse("success"));
}
@GetMapping("/schedules/today/{activateable}")
public ResponseEntity<?> loadTodaysSchedules(@PathVariable boolean activateable) {
ServiceResult<List<BasicTaskSchedule>> todaysSchedules = taskScheduleService.loadTodaysSchedule(SecurityContextHolder.getContext().getAuthentication().getName(), activateable);
if(todaysSchedules.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} else {
return ResponseEntity.ok(todaysSchedules.getResult().stream().map(ScheduleInfo::new).toList());
}
}
@GetMapping("/schedules")
public ResponseEntity<?> loadSchedules() {
ServiceResult<List<BasicTaskSchedule>> schedules = taskScheduleService.loadSchedules(SecurityContextHolder.getContext().getAuthentication().getName());
if(schedules.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
} else {
return ResponseEntity.ok(schedules.getResult().stream().map(ScheduleInfo::new).toList());
}
}
@PostMapping("/schedules/{taskID}/now")
public ResponseEntity<?> scheduleTaskNow(@PathVariable long taskID) {
PermissionResult<Task> permissionResult = taskService.getTaskPermissions(taskID, 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"));
}
ServiceResult<BasicTaskSchedule> scheduleResult = taskScheduleService.scheduleTaskNow(permissionResult.getResult());
if(scheduleResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) {
return ResponseEntity.status(409).body(new SimpleStatusResponse("failed"));
} else {
return ResponseEntity.ok(new ScheduleInfo(scheduleResult.getResult()));
}
}
@GetMapping("/schedules/active")
public ResponseEntity<?> getActiveSchedule() {
ServiceResult<BasicTaskSchedule> activeScheduleResult = taskScheduleService.getActiveSchedule(SecurityContextHolder.getContext().getAuthentication().getName());
if(activeScheduleResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.ok(new ScheduleInfo());
} else {
return ResponseEntity.ok(new ScheduleInfo(activeScheduleResult.getResult()));
}
}
@PostMapping("/schedules/{scheduleID}/activate")
public ResponseEntity<?> activateSchedule(@PathVariable long scheduleID) {
PermissionResult<BasicTaskSchedule> schedulePermissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!schedulePermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(schedulePermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
ServiceResult<BasicTaskSchedule> scheduleActivateResult = taskScheduleService.activateSchedule(schedulePermissionResult.getResult());
if(scheduleActivateResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) {
return ResponseEntity.status(409).body(new SimpleStatusResponse("failed"));
} else if(scheduleActivateResult.getExitCode() == ServiceExitCode.OK){
return ResponseEntity.ok(new ScheduleActivateInfo(scheduleActivateResult.getResult().getStartTime()));
} else {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
}
@PostMapping("/schedules/{scheduleID}/stop/{finish}")
public ResponseEntity<?> stopSchedule(@PathVariable long scheduleID, @PathVariable boolean finish) {
PermissionResult<BasicTaskSchedule> schedulePermissionResult = taskScheduleService.getSchedulePermissions(scheduleID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!schedulePermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(schedulePermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
ServiceResult<Integer> stopResult = taskScheduleService.stopSchedule(schedulePermissionResult.getResult(), finish);
if(stopResult.getExitCode() == ServiceExitCode.INVALID_OPERATION) {
return ResponseEntity.status(400).body(new SimpleStatusResponse("failed"));
} else {
return ResponseEntity.ok(new TaskScheduleStopResponse(stopResult.getResult()));
}
}
@GetMapping("/schedules/status/today")
public ResponseEntity<?> getWorkedMinutesToday() {
Optional<User> user = userRepository.findByUsername(SecurityContextHolder.getContext().getAuthentication().getName());
if(user.isEmpty()) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
int workedMinutes = taskScheduleService.getWorkedMinutes(user.get());
return ResponseEntity.ok(new ScheduleStatus(workedMinutes, taskScheduleService.isAnyScheduleMissed(user.get())));
}
}

View File

@ -1,6 +1,7 @@
package core.api.controller;
import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.taskSchedule.ScheduleInfo;
import core.api.models.timemanager.tasks.TaskEntityInfo;
import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.entities.timemanager.Task;
@ -96,4 +97,33 @@ public class TaskController {
taskService.deleteTask(taskPermissionResult.getResult());
return ResponseEntity.ok(new SimpleStatusResponse("success"));
}
@GetMapping("/tasks/{taskID}")
public ResponseEntity<?> loadTaskDetails(@PathVariable long taskID) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskPermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if (taskPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
return ResponseEntity.ok(new TaskEntityInfo(taskPermissionResult.getResult()));
}
@PostMapping("/tasks/{taskID}/finish")
public ResponseEntity<?> finishTask(@PathVariable long taskID) {
PermissionResult<Task> taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName());
if (!taskPermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if (taskPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
taskService.finishTask(taskPermissionResult.getResult());
return ResponseEntity.ok(new SimpleStatusResponse("success"));
}
}

View File

@ -1,6 +1,7 @@
package core.api.controller;
import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.taskgroup.RecursiveTaskgroupInfo;
import core.api.models.timemanager.taskgroup.TaskgroupDetailInfo;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo;
@ -80,6 +81,13 @@ public class TaskgroupController {
return ResponseEntity.ok(taskgroupEntityInfos);
}
@GetMapping("/taskgroups/tree")
public ResponseEntity<List<RecursiveTaskgroupInfo>> listTaskgroupsOfUserAsTree() {
List<Taskgroup> taskgroups = taskgroupService.getTopTaskgroupsByUser(SecurityContextHolder.getContext().getAuthentication().getName());
List<RecursiveTaskgroupInfo> taskgroupEntityInfos = taskgroups.stream().map(RecursiveTaskgroupInfo::new).toList();
return ResponseEntity.ok(taskgroupEntityInfos);
}
@GetMapping("/taskgroups/{taskgroupID}")
public ResponseEntity<?> getDetails(@PathVariable long taskgroupID) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());

View File

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

View File

@ -0,0 +1,22 @@
package core.api.models.timemanager.taskSchedule;
import core.entities.timemanager.BasicTaskSchedule;
import java.time.LocalDate;
public class BasicScheduleShortInfo extends AbstractScheduleShortInfo {
private LocalDate scheduleDate;
public BasicScheduleShortInfo(BasicTaskSchedule basicTaskSchedule) {
this.scheduleDate = basicTaskSchedule.getScheduleDate();
}
public LocalDate getScheduleDate() {
return scheduleDate;
}
public void setScheduleDate(LocalDate scheduleDate) {
this.scheduleDate = scheduleDate;
}
}

View File

@ -0,0 +1,53 @@
package core.api.models.timemanager.taskSchedule;
import core.entities.timemanager.BasicTaskSchedule;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class BasicTaskScheduleEntityInfo {
private long scheduleID;
private LocalDate scheduleDate;
private LocalDateTime startTime;
private LocalDateTime finishedTime;
public BasicTaskScheduleEntityInfo(BasicTaskSchedule basicTaskSchedule) {
this.scheduleID = basicTaskSchedule.getScheduleID();
this.scheduleDate = basicTaskSchedule.getScheduleDate();
this.startTime = basicTaskSchedule.getStartTime();
this.finishedTime = basicTaskSchedule.getFinishedTime();
}
public long getScheduleID() {
return scheduleID;
}
public void setScheduleID(long scheduleID) {
this.scheduleID = scheduleID;
}
public LocalDate getScheduleDate() {
return scheduleDate;
}
public void setScheduleDate(LocalDate scheduleDate) {
this.scheduleDate = scheduleDate;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getFinishedTime() {
return finishedTime;
}
public void setFinishedTime(LocalDateTime finishedTime) {
this.finishedTime = finishedTime;
}
}

View File

@ -0,0 +1,17 @@
package core.api.models.timemanager.taskSchedule;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
public class BasicTaskScheduleFieldInfo {
@NotNull
private LocalDate scheduleDate;
public LocalDate getScheduleDate() {
return scheduleDate;
}
public void setScheduleDate(LocalDate scheduleDate) {
this.scheduleDate = scheduleDate;
}
}

View File

@ -0,0 +1,21 @@
package core.api.models.timemanager.taskSchedule;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class ScheduleActivateInfo {
private LocalDateTime startTime;
public ScheduleActivateInfo(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
}

View File

@ -0,0 +1,114 @@
package core.api.models.timemanager.taskSchedule;
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
import core.api.models.timemanager.tasks.TaskShortInfo;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.ScheduleType;
import core.entities.timemanager.Taskgroup;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
public class ScheduleInfo {
private long scheduleID;
private ScheduleType scheduleType;
private LocalDateTime startTime;
private LocalDateTime finishTime;
private int activeMinutes;
private AbstractScheduleShortInfo schedule;
private List<TaskgroupEntityInfo> taskgroupPath;
private TaskShortInfo task;
public ScheduleInfo(BasicTaskSchedule basicTaskSchedule) {
this.scheduleID = basicTaskSchedule.getScheduleID();
this.scheduleType = ScheduleType.BASIC;
this.startTime = basicTaskSchedule.getStartTime();
this.finishTime = basicTaskSchedule.getFinishedTime();
if(this.finishTime == null && this.startTime != null) {
this.activeMinutes = (int) Duration.between(basicTaskSchedule.getStartTime(), LocalDateTime.now()).toMinutes();
} else if(this.startTime != null){
this.activeMinutes = (int) Duration.between(basicTaskSchedule.getStartTime(), basicTaskSchedule.getFinishedTime()).toMinutes();
}
this.schedule = new BasicScheduleShortInfo(basicTaskSchedule);
this.task = new TaskShortInfo(basicTaskSchedule.getTask());
List<Taskgroup> taskgroupPath = Taskgroup.getAncestorList(basicTaskSchedule.getTask().getTaskgroup());
taskgroupPath.add(basicTaskSchedule.getTask().getTaskgroup());
this.taskgroupPath = taskgroupPath.stream().map(TaskgroupEntityInfo::new).toList();
}
public ScheduleInfo() {
this.scheduleID = -1;
}
public long getScheduleID() {
return scheduleID;
}
public void setScheduleID(long scheduleID) {
this.scheduleID = scheduleID;
}
public ScheduleType getScheduleType() {
return scheduleType;
}
public void setScheduleType(ScheduleType scheduleType) {
this.scheduleType = scheduleType;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getFinishTime() {
return finishTime;
}
public void setFinishTime(LocalDateTime finishTime) {
this.finishTime = finishTime;
}
public int getActiveMinutes() {
return activeMinutes;
}
public void setActiveMinutes(int activeMinutes) {
this.activeMinutes = activeMinutes;
}
public AbstractScheduleShortInfo getSchedule() {
return schedule;
}
public void setSchedule(AbstractScheduleShortInfo schedule) {
this.schedule = schedule;
}
public List<TaskgroupEntityInfo> getTaskgroupPath() {
return taskgroupPath;
}
public void setTaskgroupPath(List<TaskgroupEntityInfo> taskgroupPath) {
this.taskgroupPath = taskgroupPath;
}
public TaskShortInfo getTask() {
return task;
}
public void setTask(TaskShortInfo task) {
this.task = task;
}
}

View File

@ -0,0 +1,28 @@
package core.api.models.timemanager.taskSchedule;
public class ScheduleStatus {
private int activeMinutes;
private boolean missedSchedules;
public ScheduleStatus(int activeMinutes, boolean missedSchedules) {
this.activeMinutes = activeMinutes;
this.missedSchedules = missedSchedules;
}
public int getActiveMinutes() {
return activeMinutes;
}
public void setActiveMinutes(int activeMinutes) {
this.activeMinutes = activeMinutes;
}
public boolean isMissedSchedules() {
return missedSchedules;
}
public void setMissedSchedules(boolean missedSchedules) {
this.missedSchedules = missedSchedules;
}
}

View File

@ -0,0 +1,18 @@
package core.api.models.timemanager.taskSchedule;
public class TaskScheduleStopResponse {
private int workTime;
public TaskScheduleStopResponse(int workTime) {
this.workTime = workTime;
}
public int getWorkTime() {
return workTime;
}
public void setWorkTime(int workTime) {
this.workTime = workTime;
}
}

View File

@ -0,0 +1,89 @@
package core.api.models.timemanager.taskgroup;
import core.api.models.timemanager.tasks.TaskOverviewInfo;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class RecursiveTaskgroupInfo {
private long taskgroupID;
private String taskgroupName;
private boolean hasOverdueTask;
private int amountActiveTasks;
private List<RecursiveTaskgroupInfo> childTaskgroups = new ArrayList<>();
private List<TaskOverviewInfo> activeTasks = new LinkedList<>();
public RecursiveTaskgroupInfo(Taskgroup taskgroup) {
this.taskgroupID = taskgroup.getTaskgroupID();
this.taskgroupName = taskgroup.getTaskgroupName();
for(Taskgroup child : taskgroup.getChildren()) {
this.childTaskgroups.add(new RecursiveTaskgroupInfo(child));
}
for(Task task : taskgroup.getActiveTasks()) {
this.activeTasks.add(new TaskOverviewInfo(task));
if(task.getDeadline().isBefore(LocalDate.now())) {
this.hasOverdueTask = true;
}
}
this.amountActiveTasks = taskgroup.getAmountOfActiveTasks();
}
public long getTaskgroupID() {
return taskgroupID;
}
public void setTaskgroupID(long taskgroupID) {
this.taskgroupID = taskgroupID;
}
public String getTaskgroupName() {
return taskgroupName;
}
public void setTaskgroupName(String taskgroupName) {
this.taskgroupName = taskgroupName;
}
public List<RecursiveTaskgroupInfo> getChildTaskgroups() {
return childTaskgroups;
}
public void setChildTaskgroups(List<RecursiveTaskgroupInfo> childTaskgroups) {
this.childTaskgroups = childTaskgroups;
}
public List<TaskOverviewInfo> getActiveTasks() {
return activeTasks;
}
public void setActiveTasks(List<TaskOverviewInfo> activeTasks) {
this.activeTasks = activeTasks;
}
public boolean isHasOverdueTask() {
return hasOverdueTask;
}
public void setHasOverdueTask(boolean hasOverdueTask) {
this.hasOverdueTask = hasOverdueTask;
}
public int getAmountActiveTasks() {
return amountActiveTasks;
}
public void setAmountActiveTasks(int amountActiveTasks) {
this.amountActiveTasks = amountActiveTasks;
}
}

View File

@ -1,7 +0,0 @@
package core.api.models.timemanager.taskgroup;
public class TaskgroupShortInfo {
private long taskgroupID;
private String taskgroupName;
}

View File

@ -20,6 +20,8 @@ public class TaskEntityInfo {
private boolean finished;
private int workTime;
public TaskEntityInfo(Task task) {
this.taskID = task.getTaskID();
this.taskName = task.getTaskName();
@ -28,6 +30,7 @@ public class TaskEntityInfo {
this.deadline = task.getDeadline();
this.overdue = LocalDate.now().isAfter(task.getDeadline());
this.finished = task.isFinished();
this.workTime = task.getWorkTime();
}
public long getTaskID() {
@ -85,4 +88,12 @@ public class TaskEntityInfo {
public void setFinished(boolean finished) {
this.finished = finished;
}
public int getWorkTime() {
return workTime;
}
public void setWorkTime(int workTime) {
this.workTime = workTime;
}
}

View File

@ -0,0 +1,72 @@
package core.api.models.timemanager.tasks;
import core.entities.timemanager.Task;
import java.time.LocalDate;
public class TaskOverviewInfo {
private long taskID;
private String taskName;
private int activeMinutes;
private int eta;
private LocalDate limit;
private boolean overdue;
public TaskOverviewInfo(Task task) {
this.taskID = task.getTaskID();
this.taskName = task.getTaskName();
this.activeMinutes = task.getWorkTime();
this.eta = task.getEta();
this.limit = task.getDeadline();
this.overdue = LocalDate.now().isAfter(task.getDeadline());
}
public long getTaskID() {
return taskID;
}
public void setTaskID(long taskID) {
this.taskID = taskID;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public int getActiveMinutes() {
return activeMinutes;
}
public void setActiveMinutes(int activeMinutes) {
this.activeMinutes = activeMinutes;
}
public int getEta() {
return eta;
}
public void setEta(int eta) {
this.eta = eta;
}
public LocalDate getLimit() {
return limit;
}
public void setLimit(LocalDate limit) {
this.limit = limit;
}
public boolean isOverdue() {
return overdue;
}
public void setOverdue(boolean overdue) {
this.overdue = overdue;
}
}

View File

@ -0,0 +1,30 @@
package core.api.models.timemanager.tasks;
import core.entities.timemanager.Task;
public class TaskShortInfo {
private long taskID;
private String taskName;
public TaskShortInfo(Task task) {
this.taskID = task.getTaskID();
this.taskName = task.getTaskName();
}
public long getTaskID() {
return taskID;
}
public void setTaskID(long taskID) {
this.taskID = taskID;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
}

View File

@ -0,0 +1,96 @@
package core.entities.timemanager;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Objects;
@Entity
@Table(name = "basic_schedules")
public class BasicTaskSchedule {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long scheduleID;
@ManyToOne
@JoinColumn(referencedColumnName = "taskID", name = "task")
private Task task;
private LocalDate scheduleDate;
private LocalDateTime startTime;
private LocalDateTime finishedTime;
public BasicTaskSchedule(Task task, LocalDate scheduleDate) {
this.task = task;
this.scheduleDate = scheduleDate;
}
public BasicTaskSchedule() {
}
public void start() {
this.startTime = LocalDateTime.now();
}
public void end() {
this.finishedTime = LocalDateTime.now();
}
public long getScheduleID() {
return scheduleID;
}
public void setScheduleID(long scheduleID) {
this.scheduleID = scheduleID;
}
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
public LocalDate getScheduleDate() {
return scheduleDate;
}
public void setScheduleDate(LocalDate scheduleDate) {
this.scheduleDate = scheduleDate;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getFinishedTime() {
return finishedTime;
}
public void setFinishedTime(LocalDateTime finishedTime) {
this.finishedTime = finishedTime;
}
public boolean isActivateAble() {
return startTime == null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BasicTaskSchedule that = (BasicTaskSchedule) o;
return scheduleID == that.scheduleID;
}
@Override
public int hashCode() {
return Objects.hash(scheduleID);
}
}

View File

@ -0,0 +1,8 @@
package core.entities.timemanager;
public enum ScheduleType {
BASIC,
MODERATE,
ADVANCED;
}

View File

@ -2,7 +2,10 @@ package core.entities.timemanager;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@Entity
@Table(name = "tasks")
@ -25,6 +28,11 @@ public class Task {
private boolean finished;
@OneToMany(mappedBy = "task", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<BasicTaskSchedule> basicTaskSchedules;
private int workTime;
public Task(Taskgroup taskgroup, String taskName, LocalDate startDate, LocalDate deadline, int eta) {
this.taskgroup = taskgroup;
this.taskName = taskName;
@ -93,6 +101,18 @@ public class Task {
this.finished = finished;
}
public int getWorkTime() {
return workTime;
}
public void setWorkTime(int workTime) {
this.workTime = workTime;
}
public void addWorkTime(int workTime) {
this.workTime += workTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -105,4 +125,25 @@ public class Task {
public int hashCode() {
return Objects.hash(taskID);
}
public void setTaskID(long taskID) {
this.taskID = taskID;
}
public List<BasicTaskSchedule> getBasicTaskSchedules() {
return basicTaskSchedules;
}
public void setBasicTaskSchedules(List<BasicTaskSchedule> basicTaskSchedules) {
this.basicTaskSchedules = basicTaskSchedules;
}
public boolean hasActiveSchedule() {
for(BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) {
if(basicTaskSchedule.getStartTime() != null && basicTaskSchedule.getFinishedTime() == null) {
return true;
}
}
return false;
}
}

View File

@ -97,4 +97,22 @@ public class Taskgroup {
}
return ancestors;
}
public List<Task> getActiveTasks() {
List<Task> tasks = new LinkedList<>();
for(Task task : this.tasks) {
if(!task.isFinished()) {
tasks.add(task);
}
}
return tasks;
}
public int getAmountOfActiveTasks() {
int activeAmountTasks = getActiveTasks().size();
for(Taskgroup taskgroup : children) {
activeAmountTasks += taskgroup.getAmountOfActiveTasks();
}
return activeAmountTasks;
}
}

View File

@ -0,0 +1,39 @@
package core.repositories.timemanager;
import core.entities.User;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
@Repository
public interface BasicTaskScheduleRepository extends CrudRepository<BasicTaskSchedule, Long> {
@Modifying
@Transactional
@Query(value = "DELETE FROM BasicTaskSchedule bts WHERE bts.scheduleID = ?1")
void deleteBasicTaskScheduleByID(long id);
@Modifying
@Transactional
@Query(value = "DELETE FROM BasicTaskSchedule bts WHERE bts.task = ?1")
void deleteAllByTask(Task task);
@Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1")
List<BasicTaskSchedule> findAllByUser(User user);
@Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1 AND bts.scheduleDate = ?2")
List<BasicTaskSchedule> findAllByUserAndDate(User user, LocalDate localDate);
@Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user.username = ?1 AND bts.startTime is not null and bts.finishedTime is null")
Optional<BasicTaskSchedule> findActiveTaskSchedule(String username);
List<BasicTaskSchedule> findAllByStartTimeIsNull();
}

View File

@ -4,5 +4,6 @@ public enum ServiceExitCode {
OK,
ENTITY_ALREADY_EXIST,
MISSING_ENTITY;
MISSING_ENTITY,
INVALID_OPERATION;
}

View File

@ -0,0 +1,159 @@
package core.services;
import core.api.models.timemanager.taskSchedule.BasicTaskScheduleFieldInfo;
import core.entities.User;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.repositories.UserRepository;
import core.repositories.timemanager.BasicTaskScheduleRepository;
import core.repositories.timemanager.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
@Service
public class TaskScheduleService {
private final BasicTaskScheduleRepository basicTaskScheduleRepository;
private final TaskRepository taskRepository;
private final UserRepository userRepository;
public TaskScheduleService(@Autowired BasicTaskScheduleRepository basicTaskScheduleRepository,
@Autowired TaskRepository taskRepository,
UserRepository userRepository) {
this.basicTaskScheduleRepository = basicTaskScheduleRepository;
this.taskRepository = taskRepository;
this.userRepository = userRepository;
}
public ServiceResult<BasicTaskSchedule> createBasicTaskSchedule(Task task, BasicTaskScheduleFieldInfo basicTaskScheduleFieldInfo) {
BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, basicTaskScheduleFieldInfo.getScheduleDate());
task.getBasicTaskSchedules().add(basicTaskSchedule);
basicTaskScheduleRepository.save(basicTaskSchedule);
taskRepository.save(task);
return new ServiceResult<>(basicTaskSchedule);
}
public PermissionResult<BasicTaskSchedule> getSchedulePermissions(long scheduleID, String name) {
Optional<BasicTaskSchedule> basicSchedule = basicTaskScheduleRepository.findById(scheduleID);
return basicSchedule.map(value -> new PermissionResult<>(value, value.getTask().getTaskgroup().getUser().getUsername().equals(name))).orElseGet(() ->
new PermissionResult<>(ServiceExitCode.MISSING_ENTITY));
}
public void reschedule(BasicTaskSchedule basicTaskSchedule, BasicTaskScheduleFieldInfo basicTaskScheduleFieldInfo) {
basicTaskSchedule.setScheduleDate(basicTaskScheduleFieldInfo.getScheduleDate());
basicTaskScheduleRepository.save(basicTaskSchedule);
}
public void deleteBasicSchedule(BasicTaskSchedule basicTaskSchedule) {
basicTaskScheduleRepository.deleteBasicTaskScheduleByID(basicTaskSchedule.getScheduleID());
}
public ServiceResult<List<BasicTaskSchedule>> loadTodaysSchedule(String username, boolean onlyActivateable) {
Optional<User> user = userRepository.findByUsername(username);
if(user.isEmpty()) {
return new ServiceResult<>(ServiceExitCode.MISSING_ENTITY);
}
List<BasicTaskSchedule> basicTaskSchedules = basicTaskScheduleRepository.findAllByUserAndDate(user.get(), LocalDate.now());
List<BasicTaskSchedule> activatableSchedules = new LinkedList<>();
if(onlyActivateable) {
for (BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) {
if (basicTaskSchedule.isActivateAble()) {
activatableSchedules.add(basicTaskSchedule);
}
}
}
return new ServiceResult<>(activatableSchedules);
}
public ServiceResult<List<BasicTaskSchedule>> loadSchedules(String username) {
Optional<User> user = userRepository.findByUsername(username);
return user.map(value -> new ServiceResult<>(basicTaskScheduleRepository.findAllByUser(value))).orElseGet(() ->
new ServiceResult<>(ServiceExitCode.MISSING_ENTITY));
}
public ServiceResult<BasicTaskSchedule> scheduleTaskNow(Task task) {
//Check if task has already an active schedule
if(task.hasActiveSchedule()) {
return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST);
} else {
BasicTaskSchedule basicTaskSchedule = new BasicTaskSchedule(task, LocalDate.now());
basicTaskSchedule.setStartTime(LocalDateTime.now());
task.getBasicTaskSchedules().add(basicTaskSchedule);
basicTaskScheduleRepository.save(basicTaskSchedule);
taskRepository.save(task);
return new ServiceResult<>(basicTaskSchedule);
}
}
public void deleteScheduleByTask(Task task) {
basicTaskScheduleRepository.deleteAllByTask(task);
}
public ServiceResult<BasicTaskSchedule> getActiveSchedule(String username) {
Optional<BasicTaskSchedule> activeTaskScheduleResult = basicTaskScheduleRepository.findActiveTaskSchedule(username);
return activeTaskScheduleResult.map(ServiceResult::new).orElseGet(() -> new ServiceResult<>(ServiceExitCode.MISSING_ENTITY));
}
public ServiceResult<BasicTaskSchedule> activateSchedule(BasicTaskSchedule taskSchedule) {
//Check if taskSchedule can be started
if(taskSchedule.getStartTime() != null) {
return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION);
}
if(getActiveSchedule(taskSchedule.getTask().getTaskgroup().getUser().getUsername()).getExitCode() == ServiceExitCode.MISSING_ENTITY) {
taskSchedule.setStartTime(LocalDateTime.now());
basicTaskScheduleRepository.save(taskSchedule);
return new ServiceResult<>(taskSchedule);
} else {
return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST);
}
}
public ServiceResult<Integer> stopSchedule(BasicTaskSchedule taskSchedule, boolean finish) {
if(taskSchedule.getStartTime() == null || taskSchedule.getFinishedTime() != null) {
return new ServiceResult<>(ServiceExitCode.INVALID_OPERATION);
}
taskSchedule.setFinishedTime(LocalDateTime.now());
long activeTime = Duration.between(taskSchedule.getStartTime(), taskSchedule.getFinishedTime()).toMinutes();
long workTime = taskSchedule.getTask().getWorkTime() + activeTime;
taskSchedule.getTask().setWorkTime((int) workTime);
if(finish) {
taskSchedule.getTask().setFinished(true);
}
basicTaskScheduleRepository.save(taskSchedule);
taskRepository.save(taskSchedule.getTask());
return new ServiceResult<>((int) activeTime);
}
public int getWorkedMinutes(User user) {
List<BasicTaskSchedule> basicTaskSchedules = basicTaskScheduleRepository.findAllByUser(user);
long workedMinutes = 0;
for(BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) {
if(basicTaskSchedule.getFinishedTime() != null && basicTaskSchedule.getFinishedTime().toLocalDate().isEqual(LocalDate.now())) {
workedMinutes += Duration.between(basicTaskSchedule.getStartTime(), basicTaskSchedule.getFinishedTime()).toMinutes();
}
}
return (int) workedMinutes;
}
public boolean isAnyScheduleMissed(User user) {
List<BasicTaskSchedule> unstartedSchedules = basicTaskScheduleRepository.findAllByStartTimeIsNull();
LocalDate dateReference = LocalDate.now();
for(BasicTaskSchedule schedule : unstartedSchedules) {
if(schedule.getScheduleDate().isBefore(dateReference)) {
return true;
}
}
return false;
}
}

View File

@ -1,27 +1,29 @@
package core.services;
import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.BasicTaskScheduleRepository;
import core.repositories.timemanager.TaskRepository;
import core.repositories.timemanager.TaskgroupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.time.LocalDateTime;
import java.util.*;
@Service
public class TaskService {
private final TaskRepository taskRepository;
private final TaskgroupRepository taskgroupRepository;
private final TaskScheduleService taskScheduleService;
public TaskService(@Autowired TaskRepository taskRepository,
TaskgroupRepository taskgroupRepository) {
@Autowired TaskScheduleService taskScheduleService) {
this.taskRepository = taskRepository;
this.taskgroupRepository = taskgroupRepository;
this.taskScheduleService = taskScheduleService;
}
public ServiceResult<Task> createTask(Taskgroup taskgroup, TaskFieldInfo taskFieldInfo) {
@ -67,10 +69,33 @@ public class TaskService {
}
public void deleteTask(Task task) {
taskScheduleService.deleteScheduleByTask(task);
taskRepository.deleteByTaskID(task.getTaskID());
}
public void clearTasks(Taskgroup taskgroup) {
taskRepository.deleteAllByTaskgroup(taskgroup);
}
public void finishTask(Task task) {
//Mark task as finished and remove all unstarted schedules as well as finish all started schedules
task.finish();
taskRepository.save(task);
List<BasicTaskSchedule> removedBasicTaskSchedules = new LinkedList<>();
for(BasicTaskSchedule basicTaskSchedule : task.getBasicTaskSchedules()) {
if(basicTaskSchedule.getStartTime() == null) {
removedBasicTaskSchedules.add(basicTaskSchedule);
} else if(basicTaskSchedule.getFinishedTime() == null) {
ServiceResult<?> result = taskScheduleService.stopSchedule(basicTaskSchedule, true);
System.out.println(result);
}
}
for(BasicTaskSchedule deletedTaskSchedule: removedBasicTaskSchedules) {
task.getBasicTaskSchedules().remove(deletedTaskSchedule);
taskRepository.save(task);
taskScheduleService.deleteBasicSchedule(deletedTaskSchedule);
}
}
}

View File

@ -27,6 +27,7 @@
"src/assets"
],
"styles": [
"node_modules/angular-calendar/css/angular-calendar.css",
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css"
],
@ -95,6 +96,7 @@
"src/assets"
],
"styles": [
"node_modules/angular-calendar/css/angular-calendar.css",
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css"
],

View File

@ -21,6 +21,8 @@
"@angular/platform-browser": "^16.2.7",
"@angular/platform-browser-dynamic": "^16.2.7",
"@angular/router": "^16.2.7",
"angular-calendar": "^0.31.0",
"date-fns": "^2.29.3",
"moment": "^2.29.4",
"rxjs": "~7.5.0",
"tslib": "^2.3.0",
@ -2574,7 +2576,6 @@
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz",
"integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.13.11"
},
@ -3953,6 +3954,11 @@
"tslib": "^2.1.0"
}
},
"node_modules/@mattlewis92/dom-autoscroller": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz",
"integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ=="
},
"node_modules/@ngtools/webpack": {
"version": "16.2.4",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.4.tgz",
@ -4152,6 +4158,12 @@
"node": ">=14"
}
},
"node_modules/@scarf/scarf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.3.0.tgz",
"integrity": "sha512-lHKK8M5CTcpFj2hZDB3wIjb0KAbEOgDmiJGDv1WBRfQgRm/a8/XMEkG/N1iM01xgbUDsPQwi42D+dFo1XPAKew==",
"hasInstallScript": true
},
"node_modules/@schematics/angular": {
"version": "16.2.4",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.4.tgz",
@ -4904,6 +4916,48 @@
"ajv": "^8.8.2"
}
},
"node_modules/angular-calendar": {
"version": "0.31.0",
"resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.31.0.tgz",
"integrity": "sha512-QGPObUmOYLr4IeSaj1pzZjcycN6otYx+SbeezJuujstXR9f2wo4CtMlBQ+SU+ZF5VFfrdYge8qkxMGCLBLBRrw==",
"dependencies": {
"@scarf/scarf": "^1.1.1",
"angular-draggable-droppable": "^8.0.0",
"angular-resizable-element": "^7.0.0",
"calendar-utils": "^0.10.4",
"positioning": "^2.0.1",
"tslib": "^2.4.1"
},
"funding": {
"url": "https://github.com/sponsors/mattlewis92"
},
"peerDependencies": {
"@angular/core": ">=15.0.0"
}
},
"node_modules/angular-draggable-droppable": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/angular-draggable-droppable/-/angular-draggable-droppable-8.0.0.tgz",
"integrity": "sha512-+gpSNBbygjV1pxTxsM3UPJKcXHXJabYoTtKcgQe74rGnb1umKc07XCBD1qDzvlG/kocthvhQ12qfYOYzHnE3ZA==",
"dependencies": {
"@mattlewis92/dom-autoscroller": "^2.4.2",
"tslib": "^2.4.1"
},
"peerDependencies": {
"@angular/core": ">=15.0.0"
}
},
"node_modules/angular-resizable-element": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-7.0.2.tgz",
"integrity": "sha512-/BGuNiA38n9klexHO1xgnsA3VYigj9v+jUGjKtBRgfB26bCxZKsNWParSu2k3EqbATrfAJC4Nl8f7cORpJFf4w==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/core": ">=15.0.0"
}
},
"node_modules/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@ -5403,6 +5457,11 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/calendar-utils": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/calendar-utils/-/calendar-utils-0.10.4.tgz",
"integrity": "sha512-gBK4xCJ42yjaUKwuUha6cZOfxAmGzvSgbdAaX3xLRioeKbYoOK1x1qeD6dch72rsMZlTgATPbBBx42bnkStqgQ=="
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@ -6153,6 +6212,21 @@
"node": ">=10"
}
},
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"dependencies": {
"@babel/runtime": "^7.21.0"
},
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/date-format": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
@ -10574,6 +10648,11 @@
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/positioning": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/positioning/-/positioning-2.0.1.tgz",
"integrity": "sha512-DsAgM42kV/ObuwlRpAzDTjH9E8fGKkMDJHWFX+kfNXSxh7UCCQxEmdjv/Ws5Ft1XDnt3JT8fIDYeKNSE2TbttA=="
},
"node_modules/postcss": {
"version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
@ -10974,8 +11053,7 @@
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"dev": true
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/regenerator-transform": {
"version": "0.15.2",

View File

@ -23,6 +23,8 @@
"@angular/platform-browser": "^16.2.7",
"@angular/platform-browser-dynamic": "^16.2.7",
"@angular/router": "^16.2.7",
"angular-calendar": "^0.31.0",
"date-fns": "^2.29.3",
"moment": "^2.29.4",
"rxjs": "~7.5.0",
"tslib": "^2.3.0",

View File

@ -5,6 +5,7 @@ api/account.service.ts
api/api.ts
api/login.service.ts
api/properties.service.ts
api/schedule.service.ts
api/task.service.ts
api/taskgroup.service.ts
api/users.service.ts
@ -13,6 +14,8 @@ encoder.ts
git_push.sh
index.ts
model/accountDeleteRequest.ts
model/basicScheduleEntityInfo.ts
model/basicScheduleFieldInfo.ts
model/eMailChangeRequest.ts
model/inlineResponse200.ts
model/inlineResponse401.ts
@ -25,10 +28,17 @@ model/passwordChangeRequest.ts
model/propertiesInfo.ts
model/propertyInfo.ts
model/propertyUpdateRequest.ts
model/recursiveTaskgroupInfo.ts
model/scheduleActivateInfo.ts
model/scheduleInfo.ts
model/scheduleStatus.ts
model/signUpRequest.ts
model/simpleStatusResponse.ts
model/taskEntityInfo.ts
model/taskFieldInfo.ts
model/taskOverviewInfo.ts
model/taskScheduleStopResponse.ts
model/taskShortInfo.ts
model/taskgroupDetailInfo.ts
model/taskgroupEntityInfo.ts
model/taskgroupFieldInfo.ts

View File

@ -5,6 +5,7 @@ import { HttpClient } from '@angular/common/http';
import { AccountService } from './api/account.service';
import { LoginService } from './api/login.service';
import { PropertiesService } from './api/properties.service';
import { ScheduleService } from './api/schedule.service';
import { TaskService } from './api/task.service';
import { TaskgroupService } from './api/taskgroup.service';
import { UsersService } from './api/users.service';

View File

@ -4,10 +4,12 @@ export * from './login.service';
import { LoginService } from './login.service';
export * from './properties.service';
import { PropertiesService } from './properties.service';
export * from './schedule.service';
import { ScheduleService } from './schedule.service';
export * from './task.service';
import { TaskService } from './task.service';
export * from './taskgroup.service';
import { TaskgroupService } from './taskgroup.service';
export * from './users.service';
import { UsersService } from './users.service';
export const APIS = [AccountService, LoginService, PropertiesService, TaskService, TaskgroupService, UsersService];
export const APIS = [AccountService, LoginService, PropertiesService, ScheduleService, TaskService, TaskgroupService, UsersService];

View File

@ -0,0 +1,766 @@
/**
* 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.
*/
/* tslint:disable:no-unused-variable member-ordering */
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent, HttpParameterCodec, HttpContext
} from '@angular/common/http';
import { CustomHttpParameterCodec } from '../encoder';
import { Observable } from 'rxjs';
import { BasicScheduleEntityInfo } from '../model/models';
import { BasicScheduleFieldInfo } from '../model/models';
import { ScheduleActivateInfo } from '../model/models';
import { ScheduleInfo } from '../model/models';
import { ScheduleStatus } from '../model/models';
import { SimpleStatusResponse } from '../model/models';
import { TaskScheduleStopResponse } from '../model/models';
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
@Injectable({
providedIn: 'root'
})
export class ScheduleService {
protected basePath = 'http://localhost:8080/api';
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
public encoder: HttpParameterCodec;
constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (configuration) {
this.configuration = configuration;
}
if (typeof this.configuration.basePath !== 'string') {
if (typeof basePath !== 'string') {
basePath = this.basePath;
}
this.configuration.basePath = basePath;
}
this.encoder = this.configuration.encoder || new CustomHttpParameterCodec();
}
private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
if (typeof value === "object" && value instanceof Date === false) {
httpParams = this.addToHttpParamsRecursive(httpParams, value);
} else {
httpParams = this.addToHttpParamsRecursive(httpParams, value, key);
}
return httpParams;
}
private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
if (value == null) {
return httpParams;
}
if (typeof value === "object") {
if (Array.isArray(value)) {
(value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key));
} else if (value instanceof Date) {
if (key != null) {
httpParams = httpParams.append(key,
(value as Date).toISOString().substr(0, 10));
} else {
throw Error("key may not be null if value is Date");
}
} else {
Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive(
httpParams, value[k], key != null ? `${key}.${k}` : k));
}
} else if (key != null) {
httpParams = httpParams.append(key, value);
} else {
throw Error("key may not be null if value is not object or array");
}
return httpParams;
}
/**
* get active schedule
* get active schedule
* @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 schedulesActiveGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesActiveGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesActiveGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesActiveGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<ScheduleInfo>(`${this.configuration.basePath}/schedules/active`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* gets all schedules of user
* gets all schedules of user
* @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 schedulesGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<ScheduleInfo>>;
public schedulesGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<ScheduleInfo>>>;
public schedulesGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<ScheduleInfo>>>;
public schedulesGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<Array<ScheduleInfo>>(`${this.configuration.basePath}/schedules`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* activates schedule
* activates schedule
* @param scheduleID internal id of schedule
* @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 schedulesScheduleIDActivatePost(scheduleID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleActivateInfo>;
public schedulesScheduleIDActivatePost(scheduleID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleActivateInfo>>;
public schedulesScheduleIDActivatePost(scheduleID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleActivateInfo>>;
public schedulesScheduleIDActivatePost(scheduleID: number, 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 schedulesScheduleIDActivatePost.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<ScheduleActivateInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/activate`,
null,
{
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<SimpleStatusResponse>;
public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public schedulesScheduleIDBasicPost(scheduleID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
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<SimpleStatusResponse>(`${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 a schedule
* @param scheduleID internal id of schedule
* @param scheduleType internal id of task
* @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 schedulesScheduleIDScheduleTypeDelete(scheduleID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public schedulesScheduleIDScheduleTypeDelete(scheduleID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public schedulesScheduleIDScheduleTypeDelete(scheduleID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public schedulesScheduleIDScheduleTypeDelete(scheduleID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', 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 schedulesScheduleIDScheduleTypeDelete.');
}
if (scheduleType === null || scheduleType === undefined) {
throw new Error('Required parameter scheduleType was null or undefined when calling schedulesScheduleIDScheduleTypeDelete.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.delete<SimpleStatusResponse>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/${encodeURIComponent(String(scheduleType))}`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* @param scheduleID internal id of schedule
* @param finish internal id of schedule
* @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 schedulesScheduleIDStopFinishPost(scheduleID: number, finish: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<TaskScheduleStopResponse>;
public schedulesScheduleIDStopFinishPost(scheduleID: number, finish: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<TaskScheduleStopResponse>>;
public schedulesScheduleIDStopFinishPost(scheduleID: number, finish: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<TaskScheduleStopResponse>>;
public schedulesScheduleIDStopFinishPost(scheduleID: number, finish: boolean, 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 schedulesScheduleIDStopFinishPost.');
}
if (finish === null || finish === undefined) {
throw new Error('Required parameter finish was null or undefined when calling schedulesScheduleIDStopFinishPost.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<TaskScheduleStopResponse>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/stop/${encodeURIComponent(String(finish))}`,
null,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* get number of active minutes
* get number of worked minutes today
* @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 schedulesStatusTodayGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleStatus>;
public schedulesStatusTodayGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleStatus>>;
public schedulesStatusTodayGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleStatus>>;
public schedulesStatusTodayGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<ScheduleStatus>(`${this.configuration.basePath}/schedules/status/today`,
{
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<BasicScheduleEntityInfo>;
public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<BasicScheduleEntityInfo>>;
public schedulesTaskIDBasicPut(taskID: number, basicScheduleFieldInfo?: BasicScheduleFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<BasicScheduleEntityInfo>>;
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<BasicScheduleEntityInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/basic`,
basicScheduleFieldInfo,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* schedule task now
* schedule task now
* @param taskID internal id of task
* @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 schedulesTaskIDNowPost(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ScheduleInfo>;
public schedulesTaskIDNowPost(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ScheduleInfo>>;
public schedulesTaskIDNowPost(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ScheduleInfo>>;
public schedulesTaskIDNowPost(taskID: number, 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 schedulesTaskIDNowPost.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<ScheduleInfo>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/now`,
null,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* gets schedules of task
* gets schedules of task
* @param taskID internal id of task
* @param scheduleType internal id of task
* @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 schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<BasicScheduleEntityInfo>>;
public schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<BasicScheduleEntityInfo>>>;
public schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<BasicScheduleEntityInfo>>>;
public schedulesTaskIDScheduleTypeGet(taskID: number, scheduleType: 'BASIC' | 'MODERATE' | 'ADVANCED', 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 schedulesTaskIDScheduleTypeGet.');
}
if (scheduleType === null || scheduleType === undefined) {
throw new Error('Required parameter scheduleType was null or undefined when calling schedulesTaskIDScheduleTypeGet.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<Array<BasicScheduleEntityInfo>>(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(taskID))}/${encodeURIComponent(String(scheduleType))}`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* get today\&#39;s schedules
* get all schedules of today
* @param activateable determines whether only schedules that can be started should be included or all schedules of today
* @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 schedulesTodayActivateableGet(activateable: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<ScheduleInfo>>;
public schedulesTodayActivateableGet(activateable: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<ScheduleInfo>>>;
public schedulesTodayActivateableGet(activateable: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<ScheduleInfo>>>;
public schedulesTodayActivateableGet(activateable: boolean, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (activateable === null || activateable === undefined) {
throw new Error('Required parameter activateable was null or undefined when calling schedulesTodayActivateableGet.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<Array<ScheduleInfo>>(`${this.configuration.basePath}/schedules/today/${encodeURIComponent(String(activateable))}`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
}

View File

@ -0,0 +1,144 @@
/**
* 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.
*/
/* tslint:disable:no-unused-variable member-ordering */
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent, HttpParameterCodec, HttpContext
} from '@angular/common/http';
import { CustomHttpParameterCodec } from '../encoder';
import { Observable } from 'rxjs';
import { ActiveMinutesInformation } from '../model/models';
import { SimpleStatusResponse } from '../model/models';
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
@Injectable({
providedIn: 'root'
})
export class SchedulesService {
protected basePath = 'http://localhost:8080/api';
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
public encoder: HttpParameterCodec;
constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (configuration) {
this.configuration = configuration;
}
if (typeof this.configuration.basePath !== 'string') {
if (typeof basePath !== 'string') {
basePath = this.basePath;
}
this.configuration.basePath = basePath;
}
this.encoder = this.configuration.encoder || new CustomHttpParameterCodec();
}
private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
if (typeof value === "object" && value instanceof Date === false) {
httpParams = this.addToHttpParamsRecursive(httpParams, value);
} else {
httpParams = this.addToHttpParamsRecursive(httpParams, value, key);
}
return httpParams;
}
private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
if (value == null) {
return httpParams;
}
if (typeof value === "object") {
if (Array.isArray(value)) {
(value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key));
} else if (value instanceof Date) {
if (key != null) {
httpParams = httpParams.append(key,
(value as Date).toISOString().substr(0, 10));
} else {
throw Error("key may not be null if value is Date");
}
} else {
Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive(
httpParams, value[k], key != null ? `${key}.${k}` : k));
}
} else if (key != null) {
httpParams = httpParams.append(key, value);
} else {
throw Error("key may not be null if value is not object or array");
}
return httpParams;
}
/**
* get number of active minutes
* get number of worked minutes today
* @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 schedulesWorkedMinutesTodayGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<ActiveMinutesInformation>;
public schedulesWorkedMinutesTodayGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<ActiveMinutesInformation>>;
public schedulesWorkedMinutesTodayGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<ActiveMinutesInformation>>;
public schedulesWorkedMinutesTodayGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<ActiveMinutesInformation>(`${this.configuration.basePath}/schedules/workedMinutesToday`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
}

View File

@ -92,14 +92,13 @@ export class TaskService {
* edits an existing task
* edits an existing task
* @param taskID internal id of task
* @param taskFieldInfo
* @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 tasksTaskIDDelete(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public tasksTaskIDDelete(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public tasksTaskIDDelete(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public tasksTaskIDDelete(taskID: number, taskFieldInfo?: TaskFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
public tasksTaskIDDelete(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public tasksTaskIDDelete(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public tasksTaskIDDelete(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public tasksTaskIDDelete(taskID: number, 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 tasksTaskIDDelete.');
}
@ -131,15 +130,6 @@ export class TaskService {
}
// 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';
@ -157,6 +147,125 @@ export class TaskService {
);
}
/**
* finishs task
* finish tasks
* @param taskID internal id of task
* @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 tasksTaskIDFinishPost(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<SimpleStatusResponse>;
public tasksTaskIDFinishPost(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<SimpleStatusResponse>>;
public tasksTaskIDFinishPost(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<SimpleStatusResponse>>;
public tasksTaskIDFinishPost(taskID: number, 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 tasksTaskIDFinishPost.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.post<SimpleStatusResponse>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}/finish`,
null,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* gets taskdetails
* loads information about a given task
* @param taskID internal id of task
* @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 tasksTaskIDGet(taskID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<TaskEntityInfo>;
public tasksTaskIDGet(taskID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<TaskEntityInfo>>;
public tasksTaskIDGet(taskID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<TaskEntityInfo>>;
public tasksTaskIDGet(taskID: number, 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 tasksTaskIDGet.');
}
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<TaskEntityInfo>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* edits an existing task
* edits an existing task

View File

@ -20,6 +20,7 @@ import { Observable } from 'rxjs';
import { InlineResponse200 } from '../model/models';
import { InlineResponse403 } from '../model/models';
import { RecursiveTaskgroupInfo } from '../model/models';
import { SimpleStatusResponse } from '../model/models';
import { TaskgroupDetailInfo } from '../model/models';
import { TaskgroupEntityInfo } from '../model/models';
@ -513,4 +514,59 @@ export class TaskgroupService {
);
}
/**
* list all top level taskgroups of authorized user
* list all taskgroups of authorized user
* @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 taskgroupsTreeGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<RecursiveTaskgroupInfo>>;
public taskgroupsTreeGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<RecursiveTaskgroupInfo>>>;
public taskgroupsTreeGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<RecursiveTaskgroupInfo>>>;
public taskgroupsTreeGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
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();
}
let responseType_: 'text' | 'json' = 'json';
if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}
return this.httpClient.get<Array<RecursiveTaskgroupInfo>>(`${this.configuration.basePath}/taskgroups/tree`,
{
context: localVarHttpContext,
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: localVarHeaders,
observe: observe,
reportProgress: reportProgress
}
);
}
}

View File

@ -0,0 +1,20 @@
/**
* 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 ActiveMinutesInformation {
/**
* number of minutes it was worked today
*/
activeMinutes: number;
}

View File

@ -0,0 +1,36 @@
/**
* 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 BasicScheduleEntityInfo {
/**
* internal id of schedule
*/
scheduleID: number;
/**
* date on which the task is scheduled
*/
scheduleDate: string;
/**
* 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
*/
activeTime?: number;
}

View File

@ -0,0 +1,20 @@
/**
* 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 BasicScheduleFieldInfo {
/**
* date on which the task is scheduled
*/
scheduleDate: string;
}

View File

@ -1,4 +1,6 @@
export * from './accountDeleteRequest';
export * from './basicScheduleEntityInfo';
export * from './basicScheduleFieldInfo';
export * from './eMailChangeRequest';
export * from './inlineResponse200';
export * from './inlineResponse401';
@ -10,10 +12,17 @@ export * from './passwordChangeRequest';
export * from './propertiesInfo';
export * from './propertyInfo';
export * from './propertyUpdateRequest';
export * from './recursiveTaskgroupInfo';
export * from './scheduleActivateInfo';
export * from './scheduleInfo';
export * from './scheduleStatus';
export * from './signUpRequest';
export * from './simpleStatusResponse';
export * from './taskEntityInfo';
export * from './taskFieldInfo';
export * from './taskOverviewInfo';
export * from './taskScheduleStopResponse';
export * from './taskShortInfo';
export * from './taskgroupDetailInfo';
export * from './taskgroupEntityInfo';
export * from './taskgroupFieldInfo';

View File

@ -0,0 +1,35 @@
/**
* 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 { TaskOverviewInfo } from './taskOverviewInfo';
export interface RecursiveTaskgroupInfo {
/**
* internal id of taskgroup
*/
taskgroupID: number;
/**
* name of taskgroup
*/
taskgroupName: string;
childTaskgroups: Array<RecursiveTaskgroupInfo>;
activeTasks: Array<TaskOverviewInfo>;
/**
* determines whether the taskgroup has an overdue task or not
*/
hasOverdueTask: boolean;
/**
* determines the number of active tasks that can be scheduled
*/
amountActiveTasks: number;
}

View File

@ -0,0 +1,20 @@
/**
* 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 ScheduleActivateInfo {
/**
* point in time at which the schedule was started
*/
startTime: string;
}

View File

@ -0,0 +1,51 @@
/**
* 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 { BasicScheduleFieldInfo } from './basicScheduleFieldInfo';
import { TaskgroupEntityInfo } from './taskgroupEntityInfo';
import { TaskShortInfo } from './taskShortInfo';
export interface ScheduleInfo {
/**
* internal id of schedule
*/
scheduleID: number;
/**
* type of schedule
*/
scheduleType: ScheduleInfo.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;
schedule: BasicScheduleFieldInfo;
task: TaskShortInfo;
taskgroupPath: Array<TaskgroupEntityInfo>;
}
export namespace ScheduleInfo {
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,24 @@
/**
* 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 ScheduleStatus {
/**
* number of minutes it was worked today
*/
activeMinutes: number;
/**
* states whether a schedule was missed or not
*/
missedSchedules: boolean;
}

View File

@ -40,5 +40,9 @@ export interface TaskEntityInfo {
* determines whether the task is finished
*/
finished: boolean;
/**
* number in minutes that was already worked on this task
*/
workTime: number;
}

View File

@ -0,0 +1,40 @@
/**
* 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 TaskOverviewInfo {
/**
* internal id of task
*/
taskID: number;
/**
* name of task
*/
taskName: string;
/**
* expected time to finish task
*/
eta: number;
/**
* date until the task has to be finished
*/
limit: string;
/**
* determines whether the task is overdue
*/
overdue: boolean;
/**
* number in minutes that was already worked on this task
*/
activeTime?: number;
}

View File

@ -0,0 +1,20 @@
/**
* 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 TaskScheduleStopResponse {
/**
* time where the schedule was active
*/
workTime: number;
}

View File

@ -0,0 +1,24 @@
/**
* 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 TaskShortInfo {
/**
* internal id of task
*/
taskID: number;
/**
* name of task
*/
taskName: string;
}

View File

@ -5,13 +5,18 @@ import {AdminDashboardComponent} from "./admin-dashboard/admin-dashboard.compone
import {MainComponent} from "./main/main.component";
import {UserSettingsComponent} from "./user-settings/user-settings.component";
import {TaskgroupDashboardComponent} from "./taskgroups/taskgroup-dashboard/taskgroup-dashboard.component";
import {TaskDetailOverviewComponent} from "./tasks/task-detail-overview/task-detail-overview.component";
import {SchedulerComponent} from "./schedules/scheduler/scheduler.component";
const routes: Routes = [
{path: '', component: MainComponent},
{path: 'admin', component: AdminDashboardComponent},
{path: 'user/settings', component: UserSettingsComponent},
{path: 'taskgroups', component: TaskgroupDashboardComponent},
{path: 'taskgroups/:taskgroupID', component: TaskgroupDashboardComponent}
{path: 'taskgroups/:taskgroupID', component: TaskgroupDashboardComponent},
{path: 'taskgroups/:taskgroupID/tasks/:taskID', component: TaskDetailOverviewComponent},
{path: 'taskgroups/:taskgroupID/tasks/:taskID/schedule', component: SchedulerComponent},
{path: 'taskgroups/:taskgroupID/tasks/:taskID/schedule/:scheduleID', component: SchedulerComponent}
];
@NgModule({

View File

@ -45,7 +45,7 @@ import {MatTableModule} from "@angular/material/table";
import {MatCheckboxModule} from "@angular/material/checkbox";
import {MatCardModule} from "@angular/material/card";
import {MatListModule} from "@angular/material/list";
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule} from "@angular/material/core";
import {MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule} from "@angular/material/core";
import {MatMomentDateModule, MomentDateModule} from "@angular/material-moment-adapter";
import { TaskDashboardComponent } from './tasks/task-dashboard/task-dashboard.component';
import {MatSlideToggleModule} from "@angular/material/slide-toggle";
@ -53,7 +53,20 @@ import {MatSortModule} from "@angular/material/sort";
import {MatPaginatorModule} from "@angular/material/paginator";
import { ClearTaskDialogComponent } from './tasks/clear-task-dialog/clear-task-dialog.component';
import { NavigationLinkListComponent } from './navigation-link-list/navigation-link-list.component';
import { TaskDetailOverviewComponent } from './tasks/task-detail-overview/task-detail-overview.component';
import {MatProgressBarModule} from "@angular/material/progress-bar";
import {MatExpansionModule} from "@angular/material/expansion";
import { SchedulerComponent } from './schedules/scheduler/scheduler.component';
import { CalendarModule, DateAdapter } from 'angular-calendar';
import { adapterFactory } from 'angular-calendar/date-adapters/date-fns';
import {MatSelectModule} from "@angular/material/select";
import { BasicSchedulerComponent } from './schedules/basic-scheduler/basic-scheduler.component';
import { ScheduleDashboardComponent } from './schedules/schedule-dashboard/schedule-dashboard.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { ActiveScheduleComponent } from './dashboard/active-schedule/active-schedule.component';
import {MatTreeModule} from "@angular/material/tree";
import { TaskgroupOverviewComponent } from './dashboard/taskgroup-overview/taskgroup-overview.component';
import { TaskOverviewComponent } from './dashboard/task-overview/task-overview.component';
@NgModule({
declarations: [
AppComponent,
@ -76,39 +89,52 @@ import { NavigationLinkListComponent } from './navigation-link-list/navigation-l
TaskEditorComponent,
TaskDashboardComponent,
ClearTaskDialogComponent,
NavigationLinkListComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ApiModule,
HttpClientModule,
BrowserAnimationsModule,
MatToolbarModule,
MatButtonModule,
MatIconModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatProgressSpinnerModule,
MatSnackBarModule,
MatMenuModule,
MatTabsModule,
MatTableModule,
MatCheckboxModule,
MatCardModule,
ReactiveFormsModule,
MatListModule,
MatDatepickerModule,
MatInputModule,
MatDatepickerModule,
MatMomentDateModule,
FormsModule,
MatSlideToggleModule,
MatSortModule,
MatPaginatorModule
NavigationLinkListComponent,
TaskDetailOverviewComponent,
SchedulerComponent,
BasicSchedulerComponent,
ScheduleDashboardComponent,
DashboardComponent,
ActiveScheduleComponent,
TaskgroupOverviewComponent,
TaskOverviewComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ApiModule,
HttpClientModule,
BrowserAnimationsModule,
MatToolbarModule,
MatButtonModule,
MatIconModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatProgressSpinnerModule,
MatSnackBarModule,
MatMenuModule,
MatTabsModule,
MatTableModule,
MatCheckboxModule,
MatCardModule,
ReactiveFormsModule,
MatListModule,
MatDatepickerModule,
MatInputModule,
MatDatepickerModule,
MatMomentDateModule,
FormsModule,
MatSlideToggleModule,
MatSortModule,
MatPaginatorModule,
MatProgressBarModule,
MatExpansionModule,
CalendarModule.forRoot({provide: DateAdapter, useFactory: adapterFactory}),
MatSelectModule,
MatTreeModule
],
providers: [
HttpClientModule,
/*

View File

@ -0,0 +1,6 @@
import {ScheduleInfo} from "../../../api";
export interface StopActiveScheduleInfo {
schedule: ScheduleInfo
workedMinutes: number
}

View File

@ -0,0 +1,141 @@
.container {
margin: 20px auto;
width: 70%;
display: flex;
}
.spacer {
margin-bottom: 2.5%;
}
@media screen and (max-width: 600px) {
.container {
width: 100%;
margin: 20px 10px;
}
}
.today-worked-info {
margin-left: 20px;
background-color: #e1e1e1;
padding-right: 5px;
padding-left: 5px;
border-radius: 5px;
}
.red-card {
background-color: #e54c3c;
color: white;
}
.green-card {
background-color: #00bc8c;
color: white;
}
.main-container {
width: 45%;
margin-right: 20px;
}
.btn-link {
text-decoration: underline;
color: white;
margin-left: 20px;
}
.dashboard-heading {
margin-top: 20px;
font-size: 2.5em;
}
.today-worked-info {
font-size: .8em;
}
.lightBlueBtn {
background-color: #3498db;
color: white;
}
.grayBtn {
background-color: #444444;
color: white;
border-radius: 0;
}
::ng-deep .mat-mdc-list-base {
--mdc-list-list-item-label-text-color: white
}
::ng-deep .mat-mdc-list-base .taskgroup-btn, ::ng-deep .mat-mdc-list-base .taskgroup-last-btn {
--mdc-list-list-item-label-text-color: black
}
.taskgroup-overview {
width: 25%;
float: right;
}
.spacer {
flex: 1 1 auto;
}
.taskgroup-btn {
background-color: #f3f3f3;
border: 0 solid #000000;
border-bottom-width: 1px;
}
.taskgroup-last-btn {
background-color: #f3f3f3;
}
.link-no-deco {
text-decoration: none;
color: black;
}
.link-no-deco:hover{
text-decoration: underline;
}
.gray-text {
color: #6e6e6e;
}
.yellowBtn {
background-color: #f39c12;
color: white;
border-radius: 0;
}
.primaryBtn {
border-radius: 0;
}
::ng-deep .mat-mdc-card-header-text {
display: block;
width: 100%;
}
.schedule-del-btn {
margin-top: 10px;
}
.left-actions {
float: left;
}
.right-actions {
float: right;
}
.greenBtn {
background-color: #00bc8c;
color: white;
border-radius: 0;
}

View File

@ -0,0 +1,19 @@
<mat-card class="green-card" *ngIf="activeSchedule == undefined">
<mat-card-content>
<p>Currently there is no task in progress.</p>
<a class="btn-link" routerLink="/">Did you forget to start an activity?</a>
</mat-card-content>
</mat-card>
<mat-card *ngIf="activeSchedule != undefined">
<mat-card-header>
<mat-card-title><a routerLink="/" class="link-no-deco">{{activeSchedule!.task.taskName}}</a></mat-card-title>
</mat-card-header>
<mat-card-content>
<span *ngFor="let taskgroupPath of activeSchedule!.taskgroupPath">{{taskgroupPath.taskgroupName}} /</span>
<p class="gray-text" *ngIf="activeSchedule!.scheduleType==='BASIC'">Running for {{displayTime}}</p>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button class="grayBtn" (click)="stopTask(false)">Stop</button>
<button mat-raised-button class="greenBtn" (click)="stopTask(true)">Finish</button>
</mat-card-actions>
</mat-card>

View File

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

View File

@ -0,0 +1,77 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ScheduleInfo, ScheduleService, TaskOverviewInfo} from "../../../api";
import {StopActiveScheduleInfo} from "./StopActiveScheduleInfo";
import {TaskOverviewComponent} from "../task-overview/task-overview.component";
@Component({
selector: 'app-active-schedule',
templateUrl: './active-schedule.component.html',
styleUrls: ['./active-schedule.component.css']
})
export class ActiveScheduleComponent implements OnInit{
activeSchedule: ScheduleInfo | undefined
startTime: number = 0;
currentTime: number = 0;
displayTime: string = "00:00:00"
@Output('onStopTask') scheduleStopEmitter = new EventEmitter<StopActiveScheduleInfo>;
constructor(private scheduleService: ScheduleService) {
}
updateTime() {
const now = Date.now();
const elapsed = this.activeSchedule != undefined ? now - this.startTime + this.currentTime : this.currentTime;
this.displayTime = this.formatTime(elapsed);
requestAnimationFrame(() => this.updateTime());
}
formatTime(milliseconds: number): string {
const seconds = Math.floor((milliseconds / 1000) % 60);
const minutes = Math.floor((milliseconds / 1000 / 60) % 60);
const hours = Math.floor(milliseconds / 1000 / 60 / 60);
return `${this.padNumber(hours)}:${this.padNumber(minutes)}:${this.padNumber(seconds)}`;
}
padNumber(num: number): string {
return num < 10 ? `0${num}` : `${num}`;
}
ngOnInit(): void {
this.scheduleService.schedulesActiveGet().subscribe({
next: resp => {
if(resp.scheduleID >= 0) {
this.activateSchedule(resp);
}
},
})
}
stopTask(finish: boolean) {
this.scheduleService.schedulesScheduleIDStopFinishPost(this.activeSchedule!.scheduleID, finish).subscribe({
next: resp => {
this.scheduleStopEmitter.emit({
schedule: this.activeSchedule!,
workedMinutes: resp.workTime
})
this.activeSchedule = undefined
}
})
}
activateSchedule(schedule: ScheduleInfo) {
this.activeSchedule = schedule;
this.startTime = new Date(this.activeSchedule.startTime).getTime();
this.updateTime();
}
finishTaskByOverview(task: TaskOverviewInfo) {
this.activeSchedule = undefined
}
}

View File

@ -0,0 +1,143 @@
.container {
margin: 20px auto;
width: 70%;
display: flex;
}
.spacer {
margin-bottom: 2.5%;
}
@media screen and (max-width: 600px) {
.container {
width: 100%;
margin: 20px 10px;
}
}
.today-worked-info {
margin-left: 20px;
background-color: #e1e1e1;
padding-right: 5px;
padding-left: 5px;
border-radius: 5px;
}
.red-card {
background-color: #e54c3c;
color: white;
}
.green-card {
background-color: #00bc8c;
color: white;
}
.main-container {
width: 45%;
margin-right: 20px;
}
.btn-link {
text-decoration: underline;
color: white;
margin-left: 20px;
}
.dashboard-heading {
margin-top: 20px;
font-size: 2.5em;
}
.today-worked-info {
font-size: .8em;
}
.lightBlueBtn {
background-color: #3498db;
color: white;
}
.grayBtn {
background-color: #444444;
color: white;
border-radius: 0;
}
::ng-deep .mat-mdc-list-base {
--mdc-list-list-item-label-text-color: white
}
::ng-deep .mat-mdc-list-base .taskgroup-btn, ::ng-deep .mat-mdc-list-base .taskgroup-last-btn {
--mdc-list-list-item-label-text-color: black
}
.taskgroup-overview {
width: 35%;
float: right;
margin-right: 20px;
}
.spacer {
flex: 1 1 auto;
}
.taskgroup-btn {
background-color: #f3f3f3;
border: 0 solid #000000;
border-bottom-width: 1px;
}
.taskgroup-last-btn {
background-color: #f3f3f3;
}
.link-no-deco {
text-decoration: none;
color: black;
}
.link-no-deco:hover{
text-decoration: underline;
}
.gray-text {
color: #6e6e6e;
}
.yellowBtn {
background-color: #f39c12;
color: white;
border-radius: 0;
}
.primaryBtn {
border-radius: 0;
}
::ng-deep .mat-mdc-card-header-text {
display: block;
width: 100%;
}
.schedule-del-btn {
margin-top: 10px;
}
.left-actions {
float: left;
}
.right-actions {
float: right;
}
.taskgroup-first-child {
background-color: #f3f3f3;
border: 0 solid #000000;
border-top-width: 1px;
border-bottom-width: 1px;
}

View File

@ -0,0 +1,51 @@
<div class="container">
<div class="main-container">
<mat-card *ngIf="missedSchedules" class="red-card">
<mat-card-content>
<p>There are missed schedules. Please reschedule them.</p>
<a class="btn-link" routerLink="/">Reschedule</a>
</mat-card-content>
</mat-card>
<h1 class="dashboard-heading">Now<b class="today-worked-info">Today: {{workedMinutesToday}} min</b></h1>
<app-active-schedule #activeSchedule (onStopTask)="stopedTask($event)"></app-active-schedule>
<h1 class="dashboard-heading">Scheduled for today</h1>
<mat-card class="green-card" *ngIf="schedules.length == 0">
<mat-card-content>
<p>There is no scheduled Task for today</p>
</mat-card-content>
</mat-card>
<div>
<mat-card *ngFor="let schedule of schedules">
<mat-card-header>
<mat-card-title>
<a routerLink="/" class="link-no-deco">{{schedule.task.taskName}}</a>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<span *ngFor="let taskgroupPath of schedule.taskgroupPath">{{taskgroupPath.taskgroupName}} /</span>
<p class="gray-text" *ngIf="schedule.scheduleType==='BASIC'">To be done sometime today</p>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button color="primary" class="primaryBtn" (click)="startSchedule(schedule)" [disabled]="activeScheduleComponent!.activeSchedule != undefined">Start now</button>
<button mat-raised-button class="yellowBtn">Reschedule</button>
</mat-card-actions>
</mat-card>
</div>
</div>
<div class="taskgroup-overview">
<app-task-overview [tasks]="tasks" (onStartNow)="onStartTaskNow($event)" [taskgroupID]="selectedTaskgroupID" (onFinished)="onFinishTask($event)"></app-task-overview>
</div>
<div class="taskgroup-overview">
<app-taskgroup-overview (taskgroupSelected)="onSelectTaskgroup($event)"></app-taskgroup-overview>
</div>
</div>

View File

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

View File

@ -0,0 +1,75 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {BasicScheduleEntityInfo, ScheduleInfo, ScheduleService, TaskOverviewInfo} from "../../api";
import {ActiveScheduleComponent} from "./active-schedule/active-schedule.component";
import {StopActiveScheduleInfo} from "./active-schedule/StopActiveScheduleInfo";
import {TaskOverviewComponent} from "./task-overview/task-overview.component";
import {TaskOverviewData} from "./taskgroup-overview/taskgroup-overview.component";
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit{
missedSchedules: boolean = true
schedules: ScheduleInfo[] = []
workedMinutesToday: number = 0
tasks: TaskOverviewInfo[] = []
selectedTaskgroupID: number | undefined
@ViewChild('activeSchedule') activeScheduleComponent: ActiveScheduleComponent | undefined
constructor(private scheduleService: ScheduleService) {
}
ngOnInit() {
this.scheduleService.schedulesTodayActivateableGet(true).subscribe({
next: resp => {
this.schedules = resp;
}
})
this.scheduleService.schedulesStatusTodayGet().subscribe({
next: resp => {
this.workedMinutesToday = resp.activeMinutes;
this.missedSchedules = resp.missedSchedules;
}
})
}
startSchedule(schedule: ScheduleInfo) {
this.scheduleService.schedulesScheduleIDActivatePost(schedule.scheduleID).subscribe({
next: resp => {
schedule.startTime = resp.startTime;
if(this.activeScheduleComponent != undefined) {
this.activeScheduleComponent.activateSchedule(schedule);
}
}
})
}
stopedTask(stopActiveScheduleInfo: StopActiveScheduleInfo) {
this.workedMinutesToday += stopActiveScheduleInfo.workedMinutes;
this.schedules = this.schedules.filter(schedule => schedule.scheduleID !== stopActiveScheduleInfo.schedule.scheduleID);
}
protected readonly TaskOverviewComponent = TaskOverviewComponent;
onSelectTaskgroup(taskOverviewData: TaskOverviewData) {
this.tasks = taskOverviewData.tasks;
this.selectedTaskgroupID = taskOverviewData.taskgroupID;
}
onStartTaskNow(schedule: ScheduleInfo) {
this.activeScheduleComponent?.activateSchedule(schedule)
}
onFinishTask(task: TaskOverviewInfo) {
this.activeScheduleComponent?.finishTaskByOverview(task);
this.schedules = this.schedules.filter(schedule => schedule.task.taskID !== task.taskID)
}
}

View File

@ -0,0 +1,33 @@
.greenBtn {
background-color: #00bc8c;
color: white;
}
.btn-without-radius {
border-radius: 0;
}
.task-info {
line-height: .75em;
}
.progress {
margin-bottom: 10px;
margin-top: -5px;
}
.long-btn {
width: 100%;
}
.yellowBtn {
background-color: #f39c12;
color: white;
border-radius: 0;
}
.task-link {
text-decoration: none;
color: black;
}

View File

@ -0,0 +1,14 @@
<button mat-raised-button class="greenBtn long-btn" *ngIf="taskgroupID != undefined" (click)="openTaskCreation()">Add</button>
<mat-card *ngFor="let task of tasks">
<mat-card-content>
<h3><a class="task-link" [routerLink]="['/taskgroups', taskgroupID!, 'tasks', task.taskID]">{{task.taskName}}</a></h3>
<mat-progress-bar mode="determinate" value="{{task.activeTime}}" class="progress"></mat-progress-bar>
<p class="task-info"><i>ETA: </i>{{task.activeTime}} / {{task.eta}}</p>
<p class="task-info"><i>Limit: </i>{{task.limit}}</p>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button color="primary" class="btn-without-radius" (click)="startTaskNow(task)">Start now</button>
<button *ngIf="taskgroupID != undefined" mat-raised-button class="yellowBtn btn-without-radius" [routerLink]="['/taskgroups', taskgroupID!, 'tasks', task.taskID, 'schedule']">Schedule</button>
<button mat-raised-button class="greenBtn btn-without-radius" (click)="finishTask(task)">Finish</button>
</mat-card-actions>
</mat-card>

View File

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

View File

@ -0,0 +1,82 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {BasicScheduleEntityInfo, ScheduleInfo, ScheduleService, TaskOverviewInfo, TaskService} from "../../../api";
import {MatSnackBar} from "@angular/material/snack-bar";
import {TaskEditorData} from "../../tasks/task-editor/TaskEditorData";
import {TaskEditorComponent} from "../../tasks/task-editor/task-editor.component";
import {MatDialog} from "@angular/material/dialog";
@Component({
selector: 'app-task-overview',
templateUrl: './task-overview.component.html',
styleUrls: ['./task-overview.component.css']
})
export class TaskOverviewComponent {
@Input() tasks: TaskOverviewInfo[] = []
@Input() taskgroupID: number | undefined
@Output('onStartNow') startNowEmitter: EventEmitter<ScheduleInfo> = new EventEmitter<ScheduleInfo>();
@Output('onFinished') finishedEmitter: EventEmitter<TaskOverviewInfo> = new EventEmitter<TaskOverviewInfo>();
constructor(private scheduleService: ScheduleService,
private snackbar: MatSnackBar,
private taskService: TaskService,
private dialog: MatDialog) {
}
startTaskNow(task: TaskOverviewInfo) {
this.scheduleService.schedulesTaskIDNowPost(task.taskID).subscribe({
next: resp => {
this.startNowEmitter.emit(resp);
},
error: err => {
if(err.status == 403) {
this.snackbar.open("No permission", "", {duration: 2000});
} else if(err.status == 404) {
this.snackbar.open("Task not found", "", {duration: 2000});
} else if(err.status == 409) {
this.snackbar.open("Task is already running", "", {duration: 2000});
} else {
this.snackbar.open("Unexpected error", "", {duration: 2000});
}
}
})
}
finishTask(task: TaskOverviewInfo) {
this.taskService.tasksTaskIDFinishPost(task.taskID).subscribe({
next: resp => {
this.finishedEmitter.emit(task);
this.tasks = this.tasks.filter(ct => ct.taskID !== task.taskID)
},
error: err => {
if(err.status == 403) {
this.snackbar.open("No permission", "", {duration: 2000});
} else if(err.status == 404) {
this.snackbar.open("Task not found", "", {duration: 2000});
} else {
this.snackbar.open("Unexpected error", "", {duration: 2000});
}
}
})
}
openTaskCreation() {
const editorData: TaskEditorData = {
task: undefined,
taskgroupID: this.taskgroupID!
}
const dialogRef = this.dialog.open(TaskEditorComponent, {data: editorData, width: "600px"})
dialogRef.afterClosed().subscribe(res => {
if(res != undefined) {
this.tasks.push({
taskID: res.taskID,
eta: res.eta,
limit: res.deadline,
taskName: res.taskName,
activeTime: 0,
overdue: res.overdue
})
}
})
}
}

View File

@ -0,0 +1,167 @@
.container {
margin: 20px auto;
width: 70%;
}
.spacer {
flex: 1 1 auto;
}
@media screen and (max-width: 600px) {
.container {
width: 100%;
margin: 20px 10px;
}
}
.today-worked-info {
margin-left: 20px;
background-color: #e1e1e1;
padding-right: 5px;
padding-left: 5px;
border-radius: 5px;
}
.red-card {
background-color: #e54c3c;
color: white;
}
.green-card {
background-color: #00bc8c;
color: white;
}
.main-container {
width: 45%;
margin-right: 20px;
}
.btn-link {
text-decoration: underline;
color: white;
margin-left: 20px;
}
.dashboard-heading {
margin-top: 20px;
font-size: 2.5em;
}
.today-worked-info {
font-size: .8em;
}
.lightBlueBtn {
background-color: #3498db;
color: white;
}
.grayBtn {
background-color: #444444;
color: white;
border-radius: 0;
}
::ng-deep .mat-mdc-list-base {
--mdc-list-list-item-label-text-color: white
}
::ng-deep .mat-mdc-list-base .taskgroup-btn, ::ng-deep .mat-mdc-list-base .taskgroup-last-btn {
--mdc-list-list-item-label-text-color: black
}
.taskgroup-overview {
width: 25%;
float: right;
}
.spacer {
flex: 1 1 auto;
}
.taskgroup-btn {
background-color: #f3f3f3;
border: 0 solid #000000;
border-bottom-width: 1px;
}
.taskgroup-last-btn {
background-color: #f3f3f3;
}
.link-no-deco {
text-decoration: none;
color: black;
}
.link-no-deco:hover{
text-decoration: underline;
}
.gray-text {
color: #6e6e6e;
}
.yellowBtn {
background-color: #f39c12;
color: white;
border-radius: 0;
}
.primaryBtn {
border-radius: 0;
}
::ng-deep .mat-mdc-card-header-text {
display: block;
width: 100%;
}
.schedule-del-btn {
margin-top: 10px;
}
.left-actions {
float: left;
}
.right-actions {
float: right;
}
.taskgroup-first-child {
background-color: #f3f3f3;
border: 0 solid #000000;
border-top-width: 1px;
border-bottom-width: 1px;
}
.node-name {
font-style: normal;
font-weight: normal;
text-align: left;
}
.task-number{
color: white;
background-color: deepskyblue;
padding: 1px 10px;
border-radius: 5px;
margin-right: 5px;
}
.treenode-content-container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
}
.overdue-taskgroup {
background-color: #ff695b;
}

View File

@ -0,0 +1,29 @@
<mat-action-list style="padding: 0">
<button mat-list-item class="lightBlueBtn" [routerLink]="['/taskgroups']">Manage Taskgroups</button>
</mat-action-list>
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" >
<!-- This is the tree node template for leaf nodes -->
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding class="taskgroup-btn" matTreeNodePaddingIndent="10" [ngClass]="node.hasOverdueTask? 'overdue-taskgroup':''">
<!-- use a disabled button to provide padding for tree leaf -->
<button mat-icon-button disabled></button>
<div class="treenode-content-container">
<button mat-button class="node-name" (click)="onSelectTaskgroup(node.tasks, node.taskgroupID)">{{node.name}}</button>
<span class="spacer"></span>
<div class="task-number">{{node.activeTasks}}</div>
</div>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding class="taskgroup-btn" matTreeNodePaddingIndent="10" [ngClass]="node.hasOverdueTask? 'overdue-taskgroup':''">
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'Toggle ' + node.name" style="padding-left: 10px">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
<div class="treenode-content-container">
<button mat-button class="node-name" (click)="onSelectTaskgroup(node.tasks, node.taskgroupID)">{{node.name}}</button>
<span class="spacer"></span>
<div class="task-number">{{node.activeTasks}}</div>
</div>
</mat-tree-node>
</mat-tree>

View File

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

View File

@ -0,0 +1,81 @@
import {Component, EventEmitter, Output} from '@angular/core';
import {MatIconModule} from "@angular/material/icon";
import {MatButtonModule} from "@angular/material/button";
import {MatTreeFlatDataSource, MatTreeFlattener, MatTreeModule} from "@angular/material/tree";
import {FlatTreeControl} from "@angular/cdk/tree";
import {RecursiveTaskgroupInfo, TaskgroupService, TaskOverviewInfo} from "../../../api";
import {TaskOverviewComponent} from "../task-overview/task-overview.component";
/** Flat node with expandable and level information */
interface ExampleFlatNode {
expandable: boolean;
level: number;
name: string
activeTasks: number;
hasOverdueTask: boolean;
tasks: TaskOverviewInfo[];
taskgroupID: number
}
export interface TaskOverviewData {
tasks: TaskOverviewInfo[],
taskgroupID: number
}
@Component({
selector: 'app-taskgroup-overview',
templateUrl: './taskgroup-overview.component.html',
styleUrls: ['./taskgroup-overview.component.css']
})
export class TaskgroupOverviewComponent {
@Output('taskgroupSelected') taskgroupSelected: EventEmitter<TaskOverviewData> = new EventEmitter<TaskOverviewData>();
private _transformer = (node: RecursiveTaskgroupInfo, level: number) => {
return {
expandable: !!node.childTaskgroups && node.childTaskgroups.length > 0,
name: node.taskgroupName,
level: level,
activeTasks: node.amountActiveTasks,
hasOverdueTask: node.hasOverdueTask,
tasks: node.activeTasks,
taskgroupID: node.taskgroupID
};
};
treeControl = new FlatTreeControl<ExampleFlatNode>(
node => node.level,
node => node.expandable,
);
treeFlattener = new MatTreeFlattener(
this._transformer,
node => node.level,
node => node.expandable,
node => node.childTaskgroups,
);
dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
constructor(private taskgroupService: TaskgroupService) {
}
ngOnInit() {
this.taskgroupService.taskgroupsTreeGet().subscribe({
next: resp => {
this.dataSource.data = resp;
}
})
}
hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
onSelectTaskgroup(tasks: TaskOverviewInfo[], taskgroupID: number) {
this.taskgroupSelected.emit({
tasks: tasks,
taskgroupID: taskgroupID
})
}
}

View File

@ -0,0 +1 @@
<app-dashboard></app-dashboard>

View File

@ -0,0 +1,15 @@
.scheduleContainer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
mat-form-field {
width: 80%;
}
.scheduleBtn {
float: right;
margin-top: 10px;
}

View File

@ -0,0 +1,11 @@
<div class="scheduler-container">
<mat-form-field>
<input matInput [matDatepicker]="picker" [formControl]="dateCtrl">
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<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 { BasicSchedulerComponent } from './basic-scheduler.component';
describe('BasicSchedulerComponent', () => {
let component: BasicSchedulerComponent;
let fixture: ComponentFixture<BasicSchedulerComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [BasicSchedulerComponent]
});
fixture = TestBed.createComponent(BasicSchedulerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,78 @@
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
import {FormControl, Validators} from "@angular/forms";
import {BasicScheduleEntityInfo, ScheduleService, TaskEntityInfo, TaskgroupEntityInfo} from "../../../api";
import {MatSnackBar} from "@angular/material/snack-bar";
import {Router} from "@angular/router";
@Component({
selector: 'app-basic-scheduler',
templateUrl: './basic-scheduler.component.html',
styleUrls: ['./basic-scheduler.component.css']
})
export class BasicSchedulerComponent implements OnChanges{
dateCtrl: FormControl = new FormControl('', [Validators.required])
@Input('taskgroup') taskgroup: TaskgroupEntityInfo | undefined
@Input('task') task: TaskEntityInfo | undefined
@Input('scheduleInfo') scheduleEntityInfo: BasicScheduleEntityInfo | undefined
@Output('onSchedule') scheduleEmitter: EventEmitter<BasicScheduleEntityInfo> = new EventEmitter<BasicScheduleEntityInfo>();
constructor(private scheduleService: ScheduleService,
private snackbar: MatSnackBar,
private router: Router) {
}
setDate(date: Date) {
this.dateCtrl.setValue(date);
}
schedule() {
if(this.task != undefined) {
if(this.scheduleEntityInfo == undefined) {
this.scheduleService.schedulesTaskIDBasicPut(this.task.taskID, {
scheduleDate: this.dateCtrl.value
}).subscribe({
next: resp => {
this.scheduleEmitter.emit(resp);
}
})
} else {
this.scheduleService.schedulesScheduleIDBasicPost(this.scheduleEntityInfo!.scheduleID, {
scheduleDate: this.dateCtrl.value
}).subscribe({
next: resp => {
this.router.navigateByUrl("/taskgroups/" + this.taskgroup!.taskgroupID + "/tasks/" + this.task!.taskID);
},
error: err => {
if(err.status == 403) {
this.snackbar.open("No permission", "",{duration: 2000});
} else if(err.status == 404) {
this.snackbar.open("Not found", "", {duration: 2000});
} else {
this.snackbar.open("Unexpected error", "",{duration: 2000});
}
}
})
}
}
}
ngOnInit(): void {
if(this.scheduleEntityInfo != undefined) {
this.dateCtrl.setValue(this.scheduleEntityInfo!.scheduleID)
}
}
ngOnChanges(): void {
if(this.scheduleEntityInfo != undefined) {
this.dateCtrl.setValue(this.scheduleEntityInfo!.scheduleID)
}
}
setEditedBasicSchedule(basicSchedule: BasicScheduleEntityInfo) {
this.dateCtrl.setValue(basicSchedule.scheduleDate)
this.scheduleEntityInfo = basicSchedule;
console.log(this.dateCtrl.value)
}
}

View File

@ -0,0 +1,14 @@
.basicScheduleContainer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.basicScheduleContent {
display: inline;
}
.scheduleContainer {
margin-bottom: 5px;
}

View File

@ -0,0 +1,17 @@
<mat-card *ngFor="let schedule of schedules" class="scheduleContainer">
<mat-card-content>
<div class="basicScheduleContainer">
<p class="basicScheduleContent">{{schedule.scheduleDate | date:'EEEE, d MMM. y'}}</p>
<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>
</mat-card-content>
</mat-card>
<button style="float: right" mat-raised-button color="primary" [routerLink]="['/taskgroups', taskgroup!.taskgroupID, 'tasks', task!.taskID, 'schedule']">Add</button>

View File

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

View File

@ -0,0 +1,50 @@
import {Component, Input, OnInit} from '@angular/core';
import {BasicScheduleEntityInfo, ScheduleService, TaskEntityInfo, TaskgroupEntityInfo} from "../../../api";
import {MatSnackBar} from "@angular/material/snack-bar";
@Component({
selector: 'app-schedule-dashboard',
templateUrl: './schedule-dashboard.component.html',
styleUrls: ['./schedule-dashboard.component.css']
})
export class ScheduleDashboardComponent implements OnInit{
@Input('taskgroup') taskgroup: TaskgroupEntityInfo | undefined
@Input('task') task: TaskEntityInfo | undefined
schedules: BasicScheduleEntityInfo[] = []
constructor(private scheduleService: ScheduleService,
private snackbar: MatSnackBar) {
}
ngOnInit() {
this.scheduleService.schedulesTaskIDScheduleTypeGet(this.task!.taskID, "BASIC").subscribe({
next: resp => {
this.schedules = resp;
}
})
}
reschedule() {
//todo
}
deleteSchedule(deletedSchedule: BasicScheduleEntityInfo) {
this.scheduleService.schedulesScheduleIDScheduleTypeDelete(deletedSchedule.scheduleID, 'BASIC').subscribe({
next: resp => {
this.schedules = this.schedules.filter(schedule => schedule.scheduleID !== deletedSchedule.scheduleID);
},
error: err => {
if(err.status == 403) {
this.snackbar.open("No permission", "", {duration: 2000});
} else if(err.status == 404) {
this.snackbar.open("Schedule not found", "", {duration: 2000});
} else {
this.snackbar.open("Unexpected error", "",{duration: 2000});
}
}
})
}
}

View File

@ -0,0 +1,27 @@
.container {
margin: 20px auto;
width: 70%;
}
.spacer {
margin-bottom: 2.5%;
}
@media screen and (max-width: 600px) {
.container {
width: 100%;
margin: 20px 10px;
}
}
.schedule-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.long-form {
width: 100%;
}

View File

@ -0,0 +1,24 @@
<div class="container">
<app-navigation-link-list #navLinkList [navigationLinks]="defaultNavigationLinkPath"></app-navigation-link-list>
<div class="schedule-header">
<h1>Monday, {{ viewDate | calendarDate:(view + 'ViewTitle'):'en':1 }}</h1>
<mat-form-field style="float:right;">
<mat-label>Schedule Strategy</mat-label>
<mat-select [(ngModel)]="scheduleStrategy">
<mat-option [value]="1">Basic</mat-option>
<mat-option [value]="2">Moderate</mat-option>
<mat-option [value]="3">Advanced</mat-option>
</mat-select>
</mat-form-field>
</div>
<mwl-calendar-week-view [viewDate]="viewDate" [daysInWeek]="daysInWeek" [dayStartHour]="7" [dayEndHour]="21" [refresh]="refresh"
(dayHeaderClicked)="timeClick($event.day.date)"
(hourSegmentClicked)="timeClick($event.date)" [events]="events" (eventClicked)="eventClicked($event)"
>
</mwl-calendar-week-view>
<app-basic-scheduler *ngIf="scheduleStrategy === 1" #basicScheduler [task]="task" [taskgroup]="taskgroup" (onSchedule)="onBasicSchedule($event)"></app-basic-scheduler>
</div>

View File

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

View File

@ -0,0 +1,172 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component";
import {
BasicScheduleEntityInfo, ScheduleService,
TaskEntityInfo,
TaskgroupEntityInfo,
TaskgroupService,
TaskService, TaskShortInfo
} from "../../../api";
import {ActivatedRoute, Router} from "@angular/router";
import {CalendarDateFormatter, CalendarEvent, CalendarView} from "angular-calendar";
import { Subject } from 'rxjs';
import {CalendarDatePipe} from "angular-calendar/modules/common/calendar-date/calendar-date.pipe";
import {BasicSchedulerComponent} from "../basic-scheduler/basic-scheduler.component";
import * as events from "events";
import { EventColor } from 'calendar-utils';
const colors: Record<string, EventColor> = {
red: {
primary: '#ad2121',
secondary: '#FAE3E3',
},
blue: {
primary: '#1e90ff',
secondary: '#D1E8FF',
},
yellow: {
primary: '#e3bc08',
secondary: '#FDF1BA',
},
};
@Component({
selector: 'app-scheduler',
templateUrl: './scheduler.component.html',
styleUrls: ['./scheduler.component.css']
})
export class SchedulerComponent implements OnInit{
defaultNavigationLinkPath: NavigationLink[] = [
{
linkText: "Dashboard",
routerLink: ['/']
},
{
linkText: "Taskgroups",
routerLink: ["/taskgroups"]
}
]
taskgroups: TaskgroupEntityInfo[] = []
taskgroup: TaskgroupEntityInfo | undefined
taskgroupPath: TaskgroupEntityInfo[] = []
taskgroupID: number = -1;
scheduleID: number = -1;
@ViewChild('navLinkList') navLinkListComponent: NavigationLinkListComponent | undefined
task: TaskEntityInfo | undefined
scheduleStrategy: number = 1
/**************************************************/
//Calendar-Stuff
/**************************************************/
view: CalendarView = CalendarView.Week;
viewDate = new Date();
daysInWeek = 7;
refresh: Subject<void> = new Subject<void>()
events: CalendarEvent[] = []
@ViewChild('basicScheduler') basicScheduler: BasicSchedulerComponent | undefined
constructor(private activatedRoute: ActivatedRoute,
private taskgroupService: TaskgroupService,
private taskService: TaskService,
private scheduleService: ScheduleService,
private router: Router) {
}
ngOnInit(): void {
this.activatedRoute.paramMap.subscribe(params => {
if (params.has('taskgroupID')) {
this.taskgroupID = Number(params.get('taskgroupID'));
this.taskgroupService.taskgroupsTaskgroupIDGet(this.taskgroupID).subscribe({
next: resp => {
this.taskgroups = resp.children
this.taskgroupPath = resp.ancestors
this.taskgroup = resp.taskgroupInfo;
this.initializeNavigationLinkList()
}
})
}
if(params.has('taskID')) {
this.taskService.tasksTaskIDGet(Number(params.get('taskID'))).subscribe({
next: resp => {
this.task = resp;
this.initializeNavigationLinkList()
this.fetschSchedules();
}
})
}
if(params.has('scheduleID')) {
this.scheduleID = Number(params.get('scheduleID'));
}
});
}
initializeNavigationLinkList() {
if(this.taskgroup != undefined && this.task != undefined) {
this.navLinkListComponent!.addNavigationLink(this.taskgroup!.taskgroupName, ['/taskgroups', this.taskgroup!.taskgroupID.toString()])
this.taskgroupPath.forEach(taskgroupEntity => {
this.navLinkListComponent!.addNavigationLink(taskgroupEntity.taskgroupName, ['/taskgroups', taskgroupEntity.taskgroupID.toString()]);
})
this.navLinkListComponent!.addNavigationLink(this.task!.taskName, ['/taskgroups', this.taskgroup!.taskgroupID.toString(), 'tasks', this.task.taskID.toString()]);
this.navLinkListComponent!.addNavigationLink('Schedule', [this.taskgroup!.taskgroupID.toString(), 'tasks', this.task.taskID.toString(), 'schedule'])
}
}
protected readonly CalendarView = CalendarView;
timeClick(clickedDate: Date) {
if(this.basicScheduler != undefined) {
this.basicScheduler.setDate(clickedDate)
}
}
onBasicSchedule(scheduleInfo: BasicScheduleEntityInfo) {
this.events.push({
start: new Date(scheduleInfo.scheduleDate),
title: this.task!.taskName,
color: colors['red'],
allDay: true
})
this.refresh.next();
}
fetschSchedules() {
this.scheduleService.schedulesGet().subscribe({
next: resp => {
resp.forEach(schedule => {
let color: EventColor = colors['red']
if(schedule.scheduleID === this.scheduleID) {
color = colors['yellow']
}
if(schedule.scheduleType === 'BASIC') {
this.events.push({
start: new Date(schedule.schedule.scheduleDate),
title: this.computeTaskPath(schedule.taskgroupPath, schedule.task),
color: color,
allDay: true,
})
}
})
this.refresh.next();
}
})
}
eventClicked({ event }: { event: CalendarEvent }): void {
this.router.navigateByUrl("/taskgroups/" + this.taskgroupID.toString() + "/tasks/" + this.task!.taskID )
}
computeTaskPath(taskgroupPath: TaskgroupEntityInfo[], task: TaskShortInfo | TaskEntityInfo) {
let result = "";
taskgroupPath.forEach(taskgroupPathPart => {
result += taskgroupPathPart.taskgroupName + "/"
});
result += task!.taskName
return result;
}
}

View File

@ -35,3 +35,11 @@ td, th {
float: right;
margin-top: 10px;
}
.navLink {
text-decoration: underline;
color: black;
margin-right: 5px;
margin-left: 3px;
}

View File

@ -10,7 +10,9 @@
<table mat-table [dataSource]="datasource" matSort>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let task"> {{task.taskName}} </td>
<td mat-cell *matCellDef="let task">
<a class="navLink" [routerLink]="['/taskgroups', taskgroupID!, 'tasks', task.taskID]">{{task.taskName}}</a>
</td>
</ng-container>
<ng-container matColumnDef="eta">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ETA </th>
@ -27,7 +29,7 @@
<ng-container matColumnDef="finished">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Finished </th>
<td mat-cell *matCellDef="let task">
<mat-checkbox [value]="task.finished" [contentEditable]="false" disableRipple="true" (click)="$event.preventDefault()"></mat-checkbox>
<mat-checkbox [checked]="task.finished" [contentEditable]="false" disableRipple="true" (click)="$event.preventDefault()"></mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="status">

View File

@ -22,6 +22,8 @@ export class TaskDashboardComponent implements OnChanges{
this.datasource = new MatTableDataSource<TaskEntityInfo>(resp);
this.datasource.paginator = this.paginator!;
this.datasource.sort = this.sort!;
resp.forEach(task => console.log(task))
}
})
}

View File

@ -0,0 +1,93 @@
.container {
margin: 20px auto;
width: 70%;
}
.spacer {
margin-bottom: 2.5%;
}
@media screen and (max-width: 600px) {
.container {
width: 100%;
margin: 20px 10px;
}
}
.yellowBtn {
background-color: #f39c12;
color: white;
border-radius: 0;
}
.grayBtn {
background-color: #444444;
color: white;
border-radius: 0;
}
.greenBtn {
background-color: #00bc8c;
color: white;
border-radius: 0;
}
.lightBlueBtn {
background-color: #3498db;
color: white;
border-radius: 0;
}
.borderless-btn {
border-radius: 0;
}
.progressbar {
color: #00bc8c;
background-color: #20ffc5;
}
.status-indicator {
width: 20px;
height: 20px;
border-radius: 50%;
margin: 0 auto;
display: inline;
margin-top: 5px;
}
.task-header {
display: inline-block;
margin-right: 10px;
}
.example-spacer {
flex: 1 1 auto;
}
.task-header-container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.left, .right {
display: inline;
}
.left {
flex-grow: 4;
}
::ng-deep .mat-mdc-card-header-text {
display: block;
width: 100%;
}
.small-btn {
font-size: 0.6rem;
background-color: #3498db;
}

View File

@ -0,0 +1,45 @@
<div class="container">
<app-navigation-link-list #navLinkList [navigationLinks]="defaultNavigationLinkPath"></app-navigation-link-list>
<mat-card *ngIf="task != undefined">
<mat-card-header>
<mat-card-title>
<div class="task-header-container">
<div class="left">
<div>🟢 {{task!.taskName}}</div>
</div>
<button class="right lightBlueBtn" mat-raised-button style="margin-left: auto">Add Subtask</button>
</div>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<p>ETA: {{task!.eta}} Minuten - Deadline: {{task!.deadline}}</p>
<mat-progress-bar [mode]="'determinate'" [value]="task!.workTime"></mat-progress-bar>
</mat-card-content>
<mat-card-actions *ngIf="taskgroup != undefined && task != undefined">
<div style="width: 100%">
<div style="float: left">
<button mat-flat-button class="borderless-btn" color="primary" [routerLink]="['/taskgroups', taskgroup!.taskgroupID, 'tasks', task!.taskID, 'schedule']">Schedule</button>
<button mat-flat-button class="yellowBtn" (click)="startTaskNow()">Start now</button>
<button mat-flat-button class="grayBtn" (click)="openTaskEditor()">Edit</button>
<!--<button mat-raised-button>Copy</button>-->
<button mat-flat-button class="greenBtn" >Finished</button>
</div>
<div style="float:right;">
<button mat-raised-button color="warn">Delete</button>
</div>
</div>
</mat-card-actions>
</mat-card>
<mat-expansion-panel *ngIf="taskgroup != undefined && task != undefined" style="margin-top: 20px" expanded>
<mat-expansion-panel-header>Schedules</mat-expansion-panel-header>
<div>
<app-schedule-dashboard [taskgroup]="taskgroup" [task]="task"></app-schedule-dashboard>
</div>
</mat-expansion-panel>
</div>

View File

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

View File

@ -0,0 +1,95 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {NavigationLink, NavigationLinkListComponent} from "../../navigation-link-list/navigation-link-list.component";
import {ActivatedRoute, Router} from "@angular/router";
import {ScheduleService, TaskEntityInfo, TaskgroupEntityInfo, TaskgroupService, TaskService} from "../../../api";
import {TaskDashboardComponent} from "../task-dashboard/task-dashboard.component";
import {MatDialog} from "@angular/material/dialog";
import {TaskEditorComponent} from "../task-editor/task-editor.component";
import {TaskEditorData} from "../task-editor/TaskEditorData";
@Component({
selector: 'app-task-detail-overview',
templateUrl: './task-detail-overview.component.html',
styleUrls: ['./task-detail-overview.component.css']
})
export class TaskDetailOverviewComponent implements OnInit {
defaultNavigationLinkPath: NavigationLink[] = [
{
linkText: "Dashboard",
routerLink: ['/']
},
{
linkText: "Taskgroups",
routerLink: ["/taskgroups"]
}
]
taskgroups: TaskgroupEntityInfo[] = []
taskgroup: TaskgroupEntityInfo | undefined
taskgroupPath: TaskgroupEntityInfo[] = []
taskgroupID: number = -1;
@ViewChild('navLinkList') navLinkListComponent: NavigationLinkListComponent | undefined
task: TaskEntityInfo | undefined
constructor(private activatedRoute: ActivatedRoute,
private taskgroupService: TaskgroupService,
private taskService: TaskService,
private dialog: MatDialog,
private scheduleService: ScheduleService,
private router: Router) {
}
ngOnInit(): void {
this.activatedRoute.paramMap.subscribe(params => {
if (params.has('taskgroupID')) {
this.taskgroupID = Number(params.get('taskgroupID'));
this.taskgroupService.taskgroupsTaskgroupIDGet(this.taskgroupID).subscribe({
next: resp => {
this.taskgroups = resp.children
this.taskgroupPath = resp.ancestors
this.taskgroup = resp.taskgroupInfo;
this.navLinkListComponent!.addNavigationLink(this.taskgroup.taskgroupName, ['/taskgroups', this.taskgroup.taskgroupID.toString()])
this.taskgroupPath.forEach(taskgroupEntity => {
this.navLinkListComponent!.addNavigationLink(taskgroupEntity.taskgroupName, ['/taskgroups', taskgroupEntity.taskgroupID.toString()]);
})
}
})
}
if(params.has('taskID')) {
this.taskService.tasksTaskIDGet(Number(params.get('taskID'))).subscribe({
next: resp => {
this.task = resp;
}
})
}
});
}
getStatusOfTask(task: TaskEntityInfo | undefined) {
return "green";
}
openTaskEditor() {
if(this.task != undefined) {
const taskEditorInfo: TaskEditorData = {
task: this.task!,
taskgroupID: this.taskgroupID!
};
this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"})
}
}
startTaskNow() {
if(this.task != undefined) {
this.scheduleService.schedulesTaskIDNowPost(this.task.taskID).subscribe({
next: resp => {
this.router.navigateByUrl('/');
}
});
}
}
}

View File

@ -13,5 +13,22 @@
</head>
<body class="mat-typography">
<app-root></app-root>
<style type="text/css">
.cal-week-view .cal-time-events {
max-height: 400px;
overflow-y: auto;
}
.cal-day-headers {
}
.cal-day-columns {
height: 100%;
}
</style>
</body>
</html>

View File

@ -581,6 +581,23 @@ paths:
type: array
items:
$ref: '#/components/schemas/TaskgroupEntityInfo'
/taskgroups/tree:
get:
security:
- API_TOKEN: []
tags:
- taskgroup
summary: list all top level taskgroups of authorized user
description: list all taskgroups of authorized user
responses:
200:
description: Anfrage erfolgreich
content:
'application/json':
schema:
type: array
items:
$ref: '#/components/schemas/RecursiveTaskgroupInfo'
/taskgroups:
get:
security:
@ -1095,11 +1112,6 @@ paths:
schema:
type: number
example: 1
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TaskFieldInfo'
responses:
200:
description: Anfrage erfolgreich
@ -1122,9 +1134,495 @@ paths:
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
get:
security:
- API_TOKEN: []
tags:
- task
summary: gets taskdetails
description: loads information about a given task
parameters:
- name: taskID
in: path
description: internal id of task
required: true
schema:
type: number
example: 1
responses:
200:
description: Anfrage erfolgreich
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/TaskEntityInfo"
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"
/tasks/{taskID}/finish:
post:
security:
- API_TOKEN: []
tags:
- task
summary: finishs task
description: finish tasks
parameters:
- name: taskID
in: path
description: internal id of task
required: true
schema:
type: number
example: 1
responses:
200:
description: Anfrage erfolgreich
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
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:
get:
security:
- API_TOKEN: []
tags:
- schedule
description: gets all schedules of user
summary: gets all schedules of user
responses:
200:
description: request successfull
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ScheduleInfo'
/schedules/{taskID}/{scheduleType}:
get:
security:
- API_TOKEN: []
tags:
- schedule
description: gets schedules of task
summary: gets schedules of task
parameters:
- name: taskID
in: path
description: internal id of task
required: true
schema:
type: number
example: 1
- name: scheduleType
in: path
description: internal id of task
required: true
schema:
type: string
enum:
- BASIC
- MODERATE
- ADVANCED
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/BasicScheduleEntityInfo'
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}/basic:
put:
security:
- API_TOKEN: []
tags:
- schedule
description: creates a basic schedule for a task
summary: creates basic 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/BasicScheduleFieldInfo'
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/BasicScheduleEntityInfo'
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/SimpleStatusResponse'
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}/{scheduleType}:
delete:
security:
- API_TOKEN: []
tags:
- schedule
description: deletes a schedule
summary: deletes schedule
parameters:
- name: scheduleID
in: path
description: internal id of schedule
required: true
schema:
type: number
example: 1
- name: scheduleType
in: path
description: internal id of task
required: true
schema:
type: string
enum:
- BASIC
- MODERATE
- ADVANCED
responses:
200:
description: operation successfull
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/SimpleStatusResponse'
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/today/{activateable}:
get:
security:
- API_TOKEN: []
tags:
- schedule
description: get all schedules of today
summary: get today's schedules
parameters:
- name: activateable
in: path
description: determines whether only schedules that can be started should be included or all schedules of today
required: true
schema:
type: boolean
example: true
responses:
200:
description: Operation successfull
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ScheduleInfo'
/schedules/{taskID}/now:
post:
security:
- API_TOKEN: []
tags:
- schedule
description: schedule task now
summary: schedule task now
parameters:
- name: taskID
in: path
description: internal id of task
required: true
schema:
type: number
example: 1
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"
409:
description: Task is already running
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
/schedules/active:
get:
security:
- API_TOKEN: []
tags:
- schedule
description: get active schedule
summary: get active schedule
responses:
200:
description: operation successfull
content:
application/json:
schema:
$ref: '#/components/schemas/ScheduleInfo'
404:
description: there is no active schedule
content:
application/json:
schema:
$ref: '#/components/schemas/SimpleStatusResponse'
/schedules/{scheduleID}/activate:
post:
security:
- API_TOKEN: []
tags:
- schedule
description: activates schedule
summary: activates 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:
type: object
$ref: '#/components/schemas/ScheduleActivateInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
404:
description: Schedule does not exist
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
409:
description: Task is already running
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
/schedules/{scheduleID}/stop/{finish}:
post:
security:
- API_TOKEN: []
tags:
- schedule
parameters:
- name: scheduleID
in: path
description: internal id of schedule
required: true
schema:
type: number
example: 1
- name: finish
in: path
description: internal id of schedule
required: true
schema:
type: boolean
example: True
responses:
200:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/TaskScheduleStopResponse"
403:
description: No permission
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
404:
description: Schedule does not exist
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
400:
description: Operation not valid
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
/schedules/status/today:
get:
security:
- API_TOKEN: []
tags:
- schedule
description: get number of worked minutes today
summary: get number of active minutes
responses:
200:
description: operation successfull
content:
application/json:
schema:
$ref: '#/components/schemas/ScheduleStatus'
404:
description: User not found
content:
'application/json':
schema:
type: object
$ref: "#/components/schemas/SimpleStatusResponse"
components:
securitySchemes:
API_TOKEN:
@ -1382,6 +1880,7 @@ components:
- deadline
- overdue
- finished
- workTime
additionalProperties: false
properties:
taskID:
@ -1413,6 +1912,10 @@ components:
type: boolean
description: determines whether the task is finished
example: True
workTime:
type: number
description: number in minutes that was already worked on this task
example: 10
TaskFieldInfo:
required:
- taskName
@ -1437,4 +1940,204 @@ components:
deadline:
type: string
format: date
description: date until the task has to be finished
description: date until the task has to be finished
BasicScheduleEntityInfo:
required:
- scheduleID
- scheduleDate
additionalProperties: false
properties:
scheduleID:
type: number
description: internal id of schedule
example: 1
scheduleDate:
type: string
format: date
description: date on which the task is scheduled
startTime:
type: string
format: date-time
description: date on which the task schedule was started
finishedTime:
type: string
format: date-time
description: date on which the tasks schedule was finished
activeTime:
type: number
description: number in minutes that the schedule was active
example: 10
BasicScheduleFieldInfo:
required:
- scheduleDate
additionalProperties: false
properties:
scheduleDate:
type: string
format: date
description: date on which the task is scheduled
ScheduleInfo:
required:
- scheduleID
- scheduleType
- startTime
- finishTime
- activeMinutes
- schedule
- task
- taskgroupPath
additionalProperties: false
properties:
scheduleID:
type: number
description: internal id of schedule
example: 1
scheduleType:
type: string
description: type of schedule
example: BASIC
enum:
- BASIC
- MODERATE
- ADVANCED
startTime:
type: string
format: date-time
description: date on which the task schedule was started
finishedTime:
type: string
format: date-time
description: date on which the tasks schedule was finished
activeMinutes:
type: number
description: number in minutes that the schedule was active
example: 10
schedule:
type: object
oneOf:
- $ref: '#/components/schemas/BasicScheduleFieldInfo'
task:
type: object
$ref: '#/components/schemas/TaskShortInfo'
taskgroupPath:
type: array
items:
$ref: '#/components/schemas/TaskgroupEntityInfo'
TaskShortInfo:
required:
- taskID
- taskName
additionalProperties: false
properties:
taskID:
type: number
description: internal id of task
example: 1
taskName:
type: string
description: name of task
example: "Vorlesung zusammenfassen"
ScheduleActivateInfo:
required:
- startTime
additionalProperties: false
properties:
startTime:
type: string
format: date-time
description: point in time at which the schedule was started
TaskScheduleStopResponse:
required:
- workTime
additionalProperties: false
properties:
workTime:
type: number
description: time where the schedule was active
example: 10
RecursiveTaskgroupInfo:
required:
- taskgroupID
- taskgroupName
- childTaskgroups
- activeTasks
- hasOverdueTask
- amountActiveTasks
additionalProperties: false
properties:
taskgroupID:
type: number
description: internal id of taskgroup
example: 1
taskgroupName:
type: string
description: name of taskgroup
example: Taskgroup 1
maxLength: 255
minLength: 1
childTaskgroups:
type: array
items:
$ref: '#/components/schemas/RecursiveTaskgroupInfo'
activeTasks:
type: array
items:
$ref: '#/components/schemas/TaskOverviewInfo'
hasOverdueTask:
type: boolean
example: true
description: determines whether the taskgroup has an overdue task or not
amountActiveTasks:
type: number
example: 2
description: determines the number of active tasks that can be scheduled
TaskOverviewInfo:
required:
- taskID
- taskName
- activeMinutes
- eta
- limit
- overdue
additionalProperties: false
properties:
taskID:
type: number
description: internal id of task
example: 1
taskName:
type: string
description: name of task
example: Vorlesung schauen
eta:
type: number
description: expected time to finish task
example: 10
minimum: 0
limit:
type: string
format: date
description: date until the task has to be finished
overdue:
type: boolean
description: determines whether the task is overdue
example: True
activeTime:
type: number
description: number in minutes that was already worked on this task
example: 10
ScheduleStatus:
required:
- activeMinutes
- missedSchedules
additionalProperties: false
properties:
activeMinutes:
type: number
example: 1
description: number of minutes it was worked today
missedSchedules:
type: boolean
description: states whether a schedule was missed or not
example: true