issue-106 #107
| @ -164,4 +164,20 @@ public class TaskController { | ||||
|         taskService.finishTask(taskPermissionResult.getResult()); | ||||
|         return ResponseEntity.ok(new SimpleStatusResponse("success")); | ||||
|     } | ||||
| 
 | ||||
|     @PutMapping("/tasks/{taskID}/createSubtask") | ||||
|     public ResponseEntity<?> onCreateSubTask(@PathVariable long taskID, @Valid @RequestBody TaskFieldInfo taskFieldInfo) { | ||||
|         var taskPermissionResult = taskService.getTaskPermissions(taskID, SecurityContextHolder.getContext().getAuthentication().getName()); | ||||
|         if(taskPermissionResult.hasIssue()) { | ||||
|             return taskPermissionResult.mapToResponseEntity(); | ||||
|         } | ||||
| 
 | ||||
|         var serviceResult = taskService.createSubTask(taskPermissionResult.getResult(), taskFieldInfo); | ||||
|         if(serviceResult.hasIssue()) { | ||||
|             return serviceResult.mapToResponseEntity(); | ||||
|         } else { | ||||
|             return ResponseEntity.ok(new TaskEntityInfo(serviceResult.getResult())); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -33,7 +33,7 @@ public class Task { | ||||
|     @OneToOne(mappedBy = "task", cascade = CascadeType.ALL, orphanRemoval = true) | ||||
|     private TaskSerieItem taskSerieItem; | ||||
| 
 | ||||
|     @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true) | ||||
|     @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) | ||||
|     private Set<Task> subtasks; | ||||
| 
 | ||||
|     @ManyToOne | ||||
|  | ||||
| @ -153,6 +153,76 @@ export class TaskService { | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates Subtask | ||||
|      * Create Subtask | ||||
|      * @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 tasksTaskIDCreateSubtaskPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<TaskEntityInfo>; | ||||
|     public tasksTaskIDCreateSubtaskPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<TaskEntityInfo>>; | ||||
|     public tasksTaskIDCreateSubtaskPut(taskID: number, taskFieldInfo?: TaskFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<TaskEntityInfo>>; | ||||
|     public tasksTaskIDCreateSubtaskPut(taskID: number, taskFieldInfo?: TaskFieldInfo, 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 tasksTaskIDCreateSubtaskPut.'); | ||||
|         } | ||||
| 
 | ||||
|         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<TaskEntityInfo>(`${this.configuration.basePath}/tasks/${encodeURIComponent(String(taskID))}/createSubtask`, | ||||
|             taskFieldInfo, | ||||
|             { | ||||
|                 context: localVarHttpContext, | ||||
|                 responseType: <any>responseType_, | ||||
|                 withCredentials: this.configuration.withCredentials, | ||||
|                 headers: localVarHeaders, | ||||
|                 observe: observe, | ||||
|                 reportProgress: reportProgress | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * edits an existing task | ||||
|      * edits an existing task | ||||
|  | ||||
| @ -93,7 +93,8 @@ export class ActiveTaskOverviewComponent implements OnInit{ | ||||
|   editTask(editedTask: TaskTaskgroupInfo) { | ||||
|     const taskEditorInfo: TaskEditorData = { | ||||
|       task: editedTask, | ||||
|       taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID | ||||
|       taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID, | ||||
|       parentTask: undefined | ||||
|     }; | ||||
|     this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"}) | ||||
|   } | ||||
|  | ||||
| @ -75,7 +75,8 @@ export class TaskOverviewComponent { | ||||
|   openTaskCreation() { | ||||
|     const editorData: TaskEditorData = { | ||||
|       task: undefined, | ||||
|       taskgroupID: this.taskgroupID! | ||||
|       taskgroupID: this.taskgroupID!, | ||||
|       parentTask: undefined | ||||
|     } | ||||
|     const dialogRef = this.dialog.open(TaskEditorComponent, {data: editorData, width: "600px"}) | ||||
|     dialogRef.afterClosed().subscribe(res => { | ||||
|  | ||||
| @ -104,7 +104,8 @@ export class TaskgroupDashboardComponent implements OnInit { | ||||
|   openTaskCreation() { | ||||
|     const editorData: TaskEditorData = { | ||||
|       task: undefined, | ||||
|       taskgroupID: this.taskgroupID | ||||
|       taskgroupID: this.taskgroupID, | ||||
|       parentTask: undefined | ||||
|     } | ||||
|     const dialogRef = this.dialog.open(TaskEditorComponent, {data: editorData, width: "600px"}) | ||||
|     dialogRef.afterClosed().subscribe(res => { | ||||
|  | ||||
| @ -97,7 +97,8 @@ export class TaskDashboardComponent implements OnChanges{ | ||||
|   editTask(task: TaskEntityInfo) { | ||||
|     const taskEditorInfo: TaskEditorData = { | ||||
|       task: task, | ||||
|       taskgroupID: this.taskgroupID! | ||||
|       taskgroupID: this.taskgroupID!, | ||||
|       parentTask: undefined | ||||
|     }; | ||||
|     const dialogRef = this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, minWidth: "400px"}) | ||||
|   } | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|           <div class="left"> | ||||
|             <div>{{taskStatus + " " + task!.taskName}}</div> | ||||
|           </div> | ||||
|           <button class="right lightBlueBtn" mat-raised-button style="margin-left: auto">Add Subtask</button> | ||||
|           <button class="right lightBlueBtn" mat-raised-button style="margin-left: auto" (click)="addSubtask()">Add Subtask</button> | ||||
|         </div> | ||||
|       </mat-card-title> | ||||
| 
 | ||||
|  | ||||
| @ -135,7 +135,8 @@ export class TaskDetailOverviewComponent implements OnInit { | ||||
|     if(this.task != undefined) { | ||||
|       const taskEditorInfo: TaskEditorData = { | ||||
|         task: this.task!, | ||||
|         taskgroupID: this.taskgroupID! | ||||
|         taskgroupID: this.taskgroupID!, | ||||
|         parentTask: undefined | ||||
|       }; | ||||
|       this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"}) | ||||
|     } | ||||
| @ -166,4 +167,16 @@ export class TaskDetailOverviewComponent implements OnInit { | ||||
|       minWidth: "400px" | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   addSubtask() { | ||||
|     const editorData: TaskEditorData = { | ||||
|       task: undefined, | ||||
|       taskgroupID: this.taskgroupID, | ||||
|       parentTask: this.task | ||||
|     } | ||||
|     const dialogRef = this.dialog.open(TaskEditorComponent, { | ||||
|       data: editorData, | ||||
|       minWidth: "400px" | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -3,4 +3,5 @@ import {TaskEntityInfo, TaskTaskgroupInfo} from "../../../api"; | ||||
| export interface TaskEditorData { | ||||
|   taskgroupID: number; | ||||
|   task: TaskTaskgroupInfo | TaskEntityInfo | undefined | ||||
|   parentTask: TaskEntityInfo | undefined | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| <h1 mat-dialog-title *ngIf="editorData.task != undefined">Edit Task ({{editorData.task!.taskName}})</h1> | ||||
| <h1 mat-dialog-title *ngIf="editorData.task == undefined">Create New Task</h1> | ||||
| <h1 mat-dialog-title *ngIf="editorData.task == undefined">Create New {{editorData.parentTask != undefined? 'Sub-':''}}Task</h1> | ||||
| <div mat-dialog-content> | ||||
|   <p *ngIf="editorData.parentTask != undefined">Create a new Subtask for the Task <i>{{editorData.parentTask!.taskName}}</i></p> | ||||
|   <mat-form-field appearance="outline" class="long-form"> | ||||
|     <mat-label>Name</mat-label> | ||||
|     <input matInput [formControl]="nameCtrl"> | ||||
|  | ||||
| @ -61,7 +61,36 @@ export class TaskEditorComponent implements OnInit { | ||||
|       startDate_formatted = moment(this.startDate.value).format('YYYY-MM-DDTHH:mm:ss.SSSZ'); | ||||
|     } | ||||
| 
 | ||||
|     this.taskService.tasksTaskgroupIDPut(this.editorData.taskgroupID, { | ||||
|     if(this.editorData.parentTask != undefined) { | ||||
|       this.createSubTask(startDate_formatted, endDate_formatted); | ||||
|     } else { | ||||
|       this.taskService.tasksTaskgroupIDPut(this.editorData.taskgroupID, { | ||||
|         taskName: this.nameCtrl.value, | ||||
|         eta: this.etaCtrl.value, | ||||
|         startDate: startDate_formatted, | ||||
|         deadline: endDate_formatted, | ||||
|         finishable: this.finishable, | ||||
|       }).subscribe({ | ||||
|         next: resp => { | ||||
|           this.dialog.close(resp); | ||||
|         }, | ||||
|         error: err => { | ||||
|           if(err.status == 403) { | ||||
|             this.snackbar.open("No permission", "", {duration: 2000}); | ||||
|           } else if(err.status == 404) { | ||||
|             this.snackbar.open("Taskgroup not found", "", {duration: 2000}); | ||||
|           } else if(err.status == 409) { | ||||
|             this.snackbar.open("Task already exists", "", {duration: 2000}); | ||||
|           } else  { | ||||
|             this.snackbar.open("Unexpected error", "", {duration: 3000}); | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   createSubTask(startDate_formatted: string|undefined, endDate_formatted: string|undefined) { | ||||
|     this.taskService.tasksTaskIDCreateSubtaskPut(this.editorData.parentTask!.taskID, { | ||||
|       taskName: this.nameCtrl.value, | ||||
|       eta: this.etaCtrl.value, | ||||
|       startDate: startDate_formatted, | ||||
| @ -78,7 +107,9 @@ export class TaskEditorComponent implements OnInit { | ||||
|           this.snackbar.open("Taskgroup not found", "", {duration: 2000}); | ||||
|         } else if(err.status == 409) { | ||||
|           this.snackbar.open("Task already exists", "", {duration: 2000}); | ||||
|         } else  { | ||||
|         } else if(err.status == 400) { | ||||
|           this.snackbar.open("Invalid Dates", "", {duration: 2000}) | ||||
|         } else { | ||||
|           this.snackbar.open("Unexpected error", "", {duration: 3000}); | ||||
|         } | ||||
|       } | ||||
| @ -123,4 +154,6 @@ export class TaskEditorComponent implements OnInit { | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   protected readonly parent = parent; | ||||
| } | ||||
|  | ||||
| @ -59,7 +59,8 @@ export class UpcomingTaskOverviewComponent implements OnInit{ | ||||
|   editTask(editedTask: TaskTaskgroupInfo) { | ||||
|     const taskEditorInfo: TaskEditorData = { | ||||
|       task: editedTask, | ||||
|       taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID | ||||
|       taskgroupID: editedTask.taskgroups[editedTask.taskgroups.length-1].taskgroupID, | ||||
|       parentTask: undefined | ||||
|     }; | ||||
|     this.dialog.open(TaskEditorComponent, {data: taskEditorInfo, width: "600px"}) | ||||
|   } | ||||
|  | ||||
							
								
								
									
										47
									
								
								openapi.yaml
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								openapi.yaml
									
									
									
									
									
								
							| @ -1269,6 +1269,53 @@ paths: | ||||
|               schema: | ||||
|                 type: object | ||||
|                 $ref: "#/components/schemas/SimpleStatusResponse" | ||||
|   /tasks/{taskID}/createSubtask: | ||||
|     put: | ||||
|       security: | ||||
|         - API_TOKEN: [] | ||||
|       tags: | ||||
|         - task | ||||
|       description: Create Subtask | ||||
|       summary: Creates Subtask | ||||
|       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/TaskFieldInfo' | ||||
|       responses: | ||||
|         200: | ||||
|           description: Operation successfull | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/TaskEntityInfo' | ||||
|         403: | ||||
|           description: No permission | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SimpleStatusResponse' | ||||
|         404: | ||||
|           description: Task not found | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SimpleStatusResponse' | ||||
|         400: | ||||
|           description: Invalid start/end date | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SimpleStatusResponse' | ||||
|        | ||||
|   /schedules: | ||||
|     get: | ||||
|       security: | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user