diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ManualScheduleStopInfo.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ManualScheduleStopInfo.java index 6bb118a..9ceb5c5 100644 --- a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ManualScheduleStopInfo.java +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ManualScheduleStopInfo.java @@ -7,10 +7,9 @@ import java.time.LocalDateTime; public class ManualScheduleStopInfo { @NotNull - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") - private LocalDateTime endTime; + private long duration; - public LocalDateTime getEndTime() { - return endTime; + public long getDuration() { + return duration; } } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index 7b31760..63491a8 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -22,6 +22,7 @@ import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; import java.util.*; @Service @@ -240,7 +241,7 @@ public class TaskScheduleService { } public void finishScheduleManual(AbstractSchedule schedule, ManualScheduleStopInfo manualScheduleStopInfo) { - schedule.setStopTime(manualScheduleStopInfo.getEndTime()); + schedule.setStopTime(schedule.getStartTime().plusMinutes(manualScheduleStopInfo.getDuration())); scheduleRepository.save(schedule); } } diff --git a/frontend/src/api/.openapi-generator/FILES b/frontend/src/api/.openapi-generator/FILES index fe29b43..fa0da49 100644 --- a/frontend/src/api/.openapi-generator/FILES +++ b/frontend/src/api/.openapi-generator/FILES @@ -30,6 +30,7 @@ model/inlineResponse403.ts model/inlineResponse409.ts model/loginRequest.ts model/loginResponse.ts +model/manualScheduleStopInfo.ts model/models.ts model/passwordChangeRequest.ts model/propertiesInfo.ts diff --git a/frontend/src/api/api/schedule.service.ts b/frontend/src/api/api/schedule.service.ts index 14e529e..b97a351 100644 --- a/frontend/src/api/api/schedule.service.ts +++ b/frontend/src/api/api/schedule.service.ts @@ -21,6 +21,7 @@ import { Observable } from 'rxjs'; import { AdvancedScheduleFieldInfo } from '../model/models'; import { BasicScheduleFieldInfo } from '../model/models'; import { ForgottenActivityRequest } from '../model/models'; +import { ManualScheduleStopInfo } from '../model/models'; import { ScheduleActivateInfo } from '../model/models'; import { ScheduleInfo } from '../model/models'; import { SimpleStatusResponse } from '../model/models'; @@ -699,6 +700,76 @@ export class ScheduleService { ); } + /** + * load schedule + * gets details of schedule + * @param scheduleID internal id of schedule + * @param manualScheduleStopInfo + * @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 schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesScheduleIDStopManualPost(scheduleID: number, manualScheduleStopInfo?: ManualScheduleStopInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + if (scheduleID === null || scheduleID === undefined) { + throw new Error('Required parameter scheduleID was null or undefined when calling schedulesScheduleIDStopManualPost.'); + } + + 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(`${this.configuration.basePath}/schedules/${encodeURIComponent(String(scheduleID))}/stopManual`, + manualScheduleStopInfo, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + /** * deletes multiple schedules * deletes multiple schedules at once diff --git a/frontend/src/api/model/manualScheduleStopInfo.ts b/frontend/src/api/model/manualScheduleStopInfo.ts new file mode 100644 index 0000000..ba31c41 --- /dev/null +++ b/frontend/src/api/model/manualScheduleStopInfo.ts @@ -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 ManualScheduleStopInfo { + /** + * duration in minutes + */ + duration: number; +} + diff --git a/frontend/src/api/model/models.ts b/frontend/src/api/model/models.ts index 1411e50..466da64 100644 --- a/frontend/src/api/model/models.ts +++ b/frontend/src/api/model/models.ts @@ -14,6 +14,7 @@ export * from './inlineResponse403'; export * from './inlineResponse409'; export * from './loginRequest'; export * from './loginResponse'; +export * from './manualScheduleStopInfo'; export * from './passwordChangeRequest'; export * from './propertiesInfo'; export * from './propertyInfo'; diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 7cdfe19..99fa84e 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -88,6 +88,7 @@ import { HeatmapActivityComponent } from './statistics/taskgroup-activity/heatma import { ScheduleHistoryComponent } from './statistics/schedule-history/schedule-history.component'; import {MatButtonToggleModule} from "@angular/material/button-toggle"; import {MatGridListModule} from "@angular/material/grid-list"; +import { StopScheduleManuallyComponent } from './dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component'; @NgModule({ declarations: [ AppComponent, @@ -132,6 +133,7 @@ import {MatGridListModule} from "@angular/material/grid-list"; SimpleActivityDiagramComponent, HeatmapActivityComponent, ScheduleHistoryComponent, + StopScheduleManuallyComponent, ], imports: [ BrowserModule, diff --git a/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts b/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts index 1ab93e4..1d2dacf 100644 --- a/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts +++ b/frontend/src/app/dashboard/active-schedule/active-schedule.component.ts @@ -4,6 +4,7 @@ import {StopActiveScheduleInfo} from "./StopActiveScheduleInfo"; import {TaskOverviewComponent} from "../task-overview/task-overview.component"; import {MatDialog} from "@angular/material/dialog"; import {ForgottenTaskStartDialogComponent} from "../forgotten-task-start-dialog/forgotten-task-start-dialog.component"; +import {StopScheduleManuallyComponent} from "./stop-schedule-manually/stop-schedule-manually.component"; export interface StopActiveScheduleEmitterInfo { stopactiveScheduleResponse: StopActiveScheduleInfo, @@ -99,7 +100,23 @@ export class ActiveScheduleComponent implements OnInit{ } finishManual() { + const dialogRef = this.dialog.open(StopScheduleManuallyComponent, { + data: this.activeSchedule, + minWidth: "400px"}) + dialogRef.afterClosed().subscribe(res => { + if(res != undefined) { + this.scheduleStopEmitter.emit({ + finish: false, + taskID: this.activeSchedule!.scheduleID, + stopactiveScheduleResponse: { + schedule: this.activeSchedule!, + workedMinutes: res + } + }) + this.activeSchedule = undefined; + } + }) } openForgettedActivityDialog() { diff --git a/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.css b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.css new file mode 100644 index 0000000..e89871e --- /dev/null +++ b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.css @@ -0,0 +1,4 @@ +.dialog-padding { + padding-left: 5px; + padding-right: 5px; +} diff --git a/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.html b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.html new file mode 100644 index 0000000..cecadc8 --- /dev/null +++ b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.html @@ -0,0 +1,11 @@ +

Set Stoptime Manually

+ + + Spent Minutes + + + + + + + diff --git a/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.spec.ts b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.spec.ts new file mode 100644 index 0000000..b74760b --- /dev/null +++ b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StopScheduleManuallyComponent } from './stop-schedule-manually.component'; + +describe('StopScheduleManuallyComponent', () => { + let component: StopScheduleManuallyComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [StopScheduleManuallyComponent] + }); + fixture = TestBed.createComponent(StopScheduleManuallyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.ts b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.ts new file mode 100644 index 0000000..5f45dbe --- /dev/null +++ b/frontend/src/app/dashboard/active-schedule/stop-schedule-manually/stop-schedule-manually.component.ts @@ -0,0 +1,34 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {ScheduleInfo, ScheduleService} from "../../../../api"; +import {FormControl, Validators} from "@angular/forms"; + +@Component({ + selector: 'app-stop-schedule-manually', + templateUrl: './stop-schedule-manually.component.html', + styleUrls: ['./stop-schedule-manually.component.css'] +}) +export class StopScheduleManuallyComponent { + + formControl: FormControl = new FormControl('', [Validators.required]) + constructor(@Inject(MAT_DIALOG_DATA) public schedule: ScheduleInfo, + private scheduleService: ScheduleService, + private dialogRef: MatDialogRef) { + } + + cancel() { + this.dialogRef.close(); + } + + + save() { + console.log(this.schedule.scheduleID) + this.scheduleService.schedulesScheduleIDStopManualPost(this.schedule.scheduleID, { + duration: this.formControl.value + }).subscribe({ + next: resp => { + this.dialogRef.close(Number(this.formControl.value)) + } + }) + } +} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 7e7239a..f81b3d6 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -2,3 +2,7 @@ html, body { height: 100%; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } + +.long-form { + width: 100%; +} diff --git a/openapi.yaml b/openapi.yaml index a246191..997da1b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1882,6 +1882,47 @@ paths: application/json: schema: $ref: '#/components/schemas/SimpleStatusResponse' + /schedules/{scheduleID}/stopManual: + post: + security: + - API_TOKEN: [] + tags: + - schedule + description: gets details of schedule + summary: load schedule + parameters: + - name: scheduleID + in: path + description: internal id of schedule + required: true + schema: + type: number + example: 1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ManualScheduleStopInfo' + responses: + 200: + description: Operation successfull + content: + application/json: + schema: + $ref: '#/components/schemas/ScheduleInfo' + 403: + description: No permission + content: + application/json: + schema: + $ref: '#/components/schemas/SimpleStatusResponse' + 404: + description: Schedule not found + content: + application/json: + schema: + $ref: '#/components/schemas/SimpleStatusResponse' + /history/workingStatus: get: @@ -2663,5 +2704,12 @@ components: type: number description: Number of minutes the task was active example: 122 - - \ No newline at end of file + ManualScheduleStopInfo: + required: + - duration + additionalProperties: false + properties: + duration: + type: number + description: duration in minutes + example: 10 \ No newline at end of file