issue-18 #28
@ -5,10 +5,10 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Remove update spamming in console">
|
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Remove update spamming in console">
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/taskgroup/RecursiveTaskgroupInfo.java" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/tasks/TaskOverviewInfo.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/src/app/app.module.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/app.module.ts" 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$/../frontend/src/app/dashboard/dashboard.component.css" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/dashboard/dashboard.component.css" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/src/app/dashboard/dashboard.component.html" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/dashboard/dashboard.component.html" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@ -104,7 +104,7 @@
|
|||||||
<workItem from="1698246651541" duration="5106000" />
|
<workItem from="1698246651541" duration="5106000" />
|
||||||
<workItem from="1698298897364" duration="4242000" />
|
<workItem from="1698298897364" duration="4242000" />
|
||||||
<workItem from="1698426430946" duration="665000" />
|
<workItem from="1698426430946" duration="665000" />
|
||||||
<workItem from="1698474363766" duration="612000" />
|
<workItem from="1698474363766" duration="1934000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="Structure Taskgroups in Hierarchies">
|
<task id="LOCAL-00001" summary="Structure Taskgroups in Hierarchies">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package core.api.controller;
|
package core.api.controller;
|
||||||
|
|
||||||
import core.api.models.auth.SimpleStatusResponse;
|
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.TaskgroupDetailInfo;
|
||||||
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
|
import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo;
|
||||||
import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo;
|
import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo;
|
||||||
@ -80,6 +81,13 @@ public class TaskgroupController {
|
|||||||
return ResponseEntity.ok(taskgroupEntityInfos);
|
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}")
|
@GetMapping("/taskgroups/{taskgroupID}")
|
||||||
public ResponseEntity<?> getDetails(@PathVariable long taskgroupID) {
|
public ResponseEntity<?> getDetails(@PathVariable long taskgroupID) {
|
||||||
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
|
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
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.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RecursiveTaskgroupInfo {
|
||||||
|
|
||||||
|
private long taskgroupID;
|
||||||
|
private String taskgroupName;
|
||||||
|
|
||||||
|
private List<RecursiveTaskgroupInfo> childTaskgroups = new ArrayList<>();
|
||||||
|
|
||||||
|
private List<TaskOverviewInfo> activeTasks = new ArrayList<>();
|
||||||
|
|
||||||
|
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.getTasks()) {
|
||||||
|
this.activeTasks.add(new TaskOverviewInfo(task));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -28,12 +28,14 @@ model/passwordChangeRequest.ts
|
|||||||
model/propertiesInfo.ts
|
model/propertiesInfo.ts
|
||||||
model/propertyInfo.ts
|
model/propertyInfo.ts
|
||||||
model/propertyUpdateRequest.ts
|
model/propertyUpdateRequest.ts
|
||||||
|
model/recursiveTaskgroupInfo.ts
|
||||||
model/scheduleActivateInfo.ts
|
model/scheduleActivateInfo.ts
|
||||||
model/scheduleInfo.ts
|
model/scheduleInfo.ts
|
||||||
model/signUpRequest.ts
|
model/signUpRequest.ts
|
||||||
model/simpleStatusResponse.ts
|
model/simpleStatusResponse.ts
|
||||||
model/taskEntityInfo.ts
|
model/taskEntityInfo.ts
|
||||||
model/taskFieldInfo.ts
|
model/taskFieldInfo.ts
|
||||||
|
model/taskOverviewInfo.ts
|
||||||
model/taskScheduleStopResponse.ts
|
model/taskScheduleStopResponse.ts
|
||||||
model/taskShortInfo.ts
|
model/taskShortInfo.ts
|
||||||
model/taskgroupDetailInfo.ts
|
model/taskgroupDetailInfo.ts
|
||||||
|
@ -20,6 +20,7 @@ import { Observable } from 'rxjs';
|
|||||||
|
|
||||||
import { InlineResponse200 } from '../model/models';
|
import { InlineResponse200 } from '../model/models';
|
||||||
import { InlineResponse403 } from '../model/models';
|
import { InlineResponse403 } from '../model/models';
|
||||||
|
import { RecursiveTaskgroupInfo } from '../model/models';
|
||||||
import { SimpleStatusResponse } from '../model/models';
|
import { SimpleStatusResponse } from '../model/models';
|
||||||
import { TaskgroupDetailInfo } from '../model/models';
|
import { TaskgroupDetailInfo } from '../model/models';
|
||||||
import { TaskgroupEntityInfo } 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
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@ export * from './passwordChangeRequest';
|
|||||||
export * from './propertiesInfo';
|
export * from './propertiesInfo';
|
||||||
export * from './propertyInfo';
|
export * from './propertyInfo';
|
||||||
export * from './propertyUpdateRequest';
|
export * from './propertyUpdateRequest';
|
||||||
|
export * from './recursiveTaskgroupInfo';
|
||||||
export * from './scheduleActivateInfo';
|
export * from './scheduleActivateInfo';
|
||||||
export * from './scheduleInfo';
|
export * from './scheduleInfo';
|
||||||
export * from './signUpRequest';
|
export * from './signUpRequest';
|
||||||
export * from './simpleStatusResponse';
|
export * from './simpleStatusResponse';
|
||||||
export * from './taskEntityInfo';
|
export * from './taskEntityInfo';
|
||||||
export * from './taskFieldInfo';
|
export * from './taskFieldInfo';
|
||||||
|
export * from './taskOverviewInfo';
|
||||||
export * from './taskScheduleStopResponse';
|
export * from './taskScheduleStopResponse';
|
||||||
export * from './taskShortInfo';
|
export * from './taskShortInfo';
|
||||||
export * from './taskgroupDetailInfo';
|
export * from './taskgroupDetailInfo';
|
||||||
|
27
frontend/src/api/model/recursiveTaskgroupInfo.ts
Normal file
27
frontend/src/api/model/recursiveTaskgroupInfo.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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>;
|
||||||
|
}
|
||||||
|
|
40
frontend/src/api/model/taskOverviewInfo.ts
Normal file
40
frontend/src/api/model/taskOverviewInfo.ts
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,10 @@
|
|||||||
.container {
|
.container {
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
width: 70%;
|
width: 70%;
|
||||||
display: flex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.spacer {
|
.spacer {
|
||||||
margin-bottom: 2.5%;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -146,3 +145,19 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: left;
|
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%;
|
||||||
|
}
|
||||||
|
@ -6,7 +6,11 @@
|
|||||||
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding class="taskgroup-btn" matTreeNodePaddingIndent="10">
|
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding class="taskgroup-btn" matTreeNodePaddingIndent="10">
|
||||||
<!-- use a disabled button to provide padding for tree leaf -->
|
<!-- use a disabled button to provide padding for tree leaf -->
|
||||||
<button mat-icon-button disabled></button>
|
<button mat-icon-button disabled></button>
|
||||||
<button mat-button class="node-name">{{node.name}}</button>
|
<div class="treenode-content-container">
|
||||||
|
<button mat-button class="node-name">{{node.name}}</button>
|
||||||
|
<span class="spacer"></span>
|
||||||
|
<div class="task-number">{{node.activeTasks}}</div>
|
||||||
|
</div>
|
||||||
</mat-tree-node>
|
</mat-tree-node>
|
||||||
<!-- This is the tree node template for expandable nodes -->
|
<!-- This is the tree node template for expandable nodes -->
|
||||||
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding class="taskgroup-btn" matTreeNodePaddingIndent="10">
|
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding class="taskgroup-btn" matTreeNodePaddingIndent="10">
|
||||||
@ -16,6 +20,10 @@
|
|||||||
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
|
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-button class="node-name">{{node.name}}</button>
|
<div class="treenode-content-container">
|
||||||
|
<button mat-button class="node-name">{{node.name}}</button>
|
||||||
|
<span class="spacer"></span>
|
||||||
|
<div class="task-number">{{node.activeTasks}}</div>
|
||||||
|
</div>
|
||||||
</mat-tree-node>
|
</mat-tree-node>
|
||||||
</mat-tree>
|
</mat-tree>
|
||||||
|
@ -3,52 +3,17 @@ import {MatIconModule} from "@angular/material/icon";
|
|||||||
import {MatButtonModule} from "@angular/material/button";
|
import {MatButtonModule} from "@angular/material/button";
|
||||||
import {MatTreeFlatDataSource, MatTreeFlattener, MatTreeModule} from "@angular/material/tree";
|
import {MatTreeFlatDataSource, MatTreeFlattener, MatTreeModule} from "@angular/material/tree";
|
||||||
import {FlatTreeControl} from "@angular/cdk/tree";
|
import {FlatTreeControl} from "@angular/cdk/tree";
|
||||||
|
import {RecursiveTaskgroupInfo, TaskgroupService} from "../../../api";
|
||||||
|
|
||||||
|
|
||||||
interface TreeNode {
|
|
||||||
name: string
|
|
||||||
children?: TreeNode[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const TREE_DATA: TreeNode[] = [
|
|
||||||
{
|
|
||||||
name: "KIT",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: "WS23",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: "Computergrafik",
|
|
||||||
children: [{name: "Vorlesungen"}, {name: "Globalübungen"}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Softwaretechnik II",
|
|
||||||
children: [{name: "Vorlesungen"}, {name: "Globalübungen"}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Algorithmen II",
|
|
||||||
children: [{name: "Vorlesungen"}, {name: "Globalübungen"}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "SS24",
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: "Interaktive Computergrafik",
|
|
||||||
children: [{name: "Vorlesungen"}, {name: "Globalübungen"}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
/** Flat node with expandable and level information */
|
/** Flat node with expandable and level information */
|
||||||
interface ExampleFlatNode {
|
interface ExampleFlatNode {
|
||||||
expandable: boolean;
|
expandable: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
level: number;
|
level: number;
|
||||||
|
activeTasks: number;
|
||||||
}
|
}
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-taskgroup-overview',
|
selector: 'app-taskgroup-overview',
|
||||||
@ -56,12 +21,12 @@ interface ExampleFlatNode {
|
|||||||
styleUrls: ['./taskgroup-overview.component.css']
|
styleUrls: ['./taskgroup-overview.component.css']
|
||||||
})
|
})
|
||||||
export class TaskgroupOverviewComponent {
|
export class TaskgroupOverviewComponent {
|
||||||
|
private _transformer = (node: RecursiveTaskgroupInfo, level: number) => {
|
||||||
private _transformer = (node: TreeNode, level: number) => {
|
|
||||||
return {
|
return {
|
||||||
expandable: !!node.children && node.children.length > 0,
|
expandable: !!node.childTaskgroups && node.childTaskgroups.length > 0,
|
||||||
name: node.name,
|
name: node.taskgroupName,
|
||||||
level: level,
|
level: level,
|
||||||
|
activeTasks: node.activeTasks.length
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,13 +39,21 @@ export class TaskgroupOverviewComponent {
|
|||||||
this._transformer,
|
this._transformer,
|
||||||
node => node.level,
|
node => node.level,
|
||||||
node => node.expandable,
|
node => node.expandable,
|
||||||
node => node.children,
|
node => node.childTaskgroups,
|
||||||
);
|
);
|
||||||
|
|
||||||
dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
|
dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
|
||||||
|
|
||||||
constructor() {
|
constructor(private taskgroupService: TaskgroupService) {
|
||||||
this.dataSource.data = TREE_DATA;
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.taskgroupService.taskgroupsTreeGet().subscribe({
|
||||||
|
next: resp => {
|
||||||
|
this.dataSource.data = resp;
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
|
hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
|
||||||
|
80
openapi.yaml
80
openapi.yaml
@ -581,6 +581,23 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/TaskgroupEntityInfo'
|
$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:
|
/taskgroups:
|
||||||
get:
|
get:
|
||||||
security:
|
security:
|
||||||
@ -1978,4 +1995,65 @@ components:
|
|||||||
workTime:
|
workTime:
|
||||||
type: number
|
type: number
|
||||||
description: time where the schedule was active
|
description: time where the schedule was active
|
||||||
example: 10
|
example: 10
|
||||||
|
RecursiveTaskgroupInfo:
|
||||||
|
required:
|
||||||
|
- taskgroupID
|
||||||
|
- taskgroupName
|
||||||
|
- childTaskgroups
|
||||||
|
- activeTasks
|
||||||
|
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'
|
||||||
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user