UI: add/remove Schedule/ScheduleEntry

This commit is contained in:
Patrick Haßel 2021-10-29 00:32:59 +02:00
parent ed2d5172bf
commit 87acae3b2e
21 changed files with 212 additions and 113 deletions

View File

@ -1671,10 +1671,10 @@
"@fortawesome/fontawesome-common-types": "^0.2.36" "@fortawesome/fontawesome-common-types": "^0.2.36"
} }
}, },
"@fortawesome/free-solid-svg-icons": { "@fortawesome/free-regular-svg-icons": {
"version": "5.15.4", "version": "5.15.4",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz",
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==",
"requires": { "requires": {
"@fortawesome/fontawesome-common-types": "^0.2.36" "@fortawesome/fontawesome-common-types": "^0.2.36"
} }

View File

@ -20,7 +20,7 @@
"@angular/router": "~12.2.0", "@angular/router": "~12.2.0",
"@fortawesome/angular-fontawesome": "^0.9.0", "@fortawesome/angular-fontawesome": "^0.9.0",
"@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-solid-svg-icons": "^5.15.3", "@fortawesome/free-regular-svg-icons": "^5.15.4",
"rxjs": "~6.6.0", "rxjs": "~6.6.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"

View File

@ -10,6 +10,13 @@ export function NO_SORT<T>(a: T, b: T): number {
return 0; return 0;
} }
function errorInterceptor(errorHandler: (error: any) => void): ((error: any) => void) {
return error => {
console.error(error);
errorHandler(error);
};
}
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
@ -21,31 +28,24 @@ export class ApiService {
// nothing // nothing
} }
getItem<T>(path: string, fromJson: (json: any) => T, next: (item: T) => void = NO_OP, errorHandler: (error: any) => void = NO_OP) { getItem<T>(path: string, fromJson: (json: any) => T, next: (item: T) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.get<any>(environment.apiBasePath + path).pipe(map(fromJson)).subscribe(next, this.getErrorHandler(errorHandler)); this.http.get<any>(environment.apiBasePath + path).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
} }
getList<T>(path: string, fromJson: (json: any) => T, compare: (a: T, b: T) => number = NO_SORT, next: (list: T[]) => void = NO_OP, errorHandler: (error: any) => void = NO_OP) { getList<T>(path: string, fromJson: (json: any) => T, compare: (a: T, b: T) => number = NO_SORT, next: (list: T[]) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.get<any[]>(environment.apiBasePath + path).pipe(map(list => list.map(fromJson).sort(compare))).subscribe(next, this.getErrorHandler(errorHandler)); this.http.get<any[]>(environment.apiBasePath + path).pipe(map(list => list.map(fromJson).sort(compare))).subscribe(next, errorInterceptor(error));
} }
postReturnNone<T>(path: string, data: any, next: (_: void) => void = NO_OP, errorHandler: (error: any) => void = NO_OP) { postReturnNone<T>(path: string, data: any, next: (_: void) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.post<any>(environment.apiBasePath + path, data).subscribe(next, this.getErrorHandler(errorHandler)); this.http.post<any>(environment.apiBasePath + path, data).subscribe(next, errorInterceptor(error));
} }
postReturnItem<T>(path: string, data: any, fromJson: (json: any) => T, next: (item: T) => void = NO_OP, errorHandler: (error: any) => void = NO_OP) { postReturnItem<T>(path: string, data: any, fromJson: (json: any) => T, next: (item: T) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.post<any>(environment.apiBasePath + path, data).pipe(map(fromJson)).subscribe(next, this.getErrorHandler(errorHandler)); this.http.post<any>(environment.apiBasePath + path, data).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
} }
postReturnList<T>(path: string, data: any, fromJson: (json: any) => T, next: (list: T[]) => void = NO_OP, errorHandler: (error: any) => void = NO_OP) { postReturnList<T>(path: string, data: any, fromJson: (json: any) => T, next: (list: T[]) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.post<any>(environment.apiBasePath + path, data).pipe(map(list => list.map(fromJson))).subscribe(next, this.getErrorHandler(errorHandler)); this.http.post<any>(environment.apiBasePath + path, data).pipe(map(list => list.map(fromJson))).subscribe(next, errorInterceptor(error));
}
private getErrorHandler(errorHandler: (error: any) => void): ((error: any) => void) {
return error => {
console.error(error);
errorHandler(error);
};
} }
} }

View File

@ -1,6 +1,7 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {ScheduleEntry} from "./ScheduleEntry"; import {ScheduleEntry} from "./ScheduleEntry";
import {ApiService, NO_OP} from "../../api.service"; import {ApiService, NO_OP} from "../../api.service";
import {Schedule} from "../Schedule";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -13,12 +14,20 @@ export class ScheduleEntryService {
// nothing // nothing
} }
findAll(next: (list: ScheduleEntry[]) => void, compare: (a: ScheduleEntry, b: ScheduleEntry) => number, errorHandler: (error: any) => void = NO_OP): void { findAll(next: (list: ScheduleEntry[]) => void, compare: (a: ScheduleEntry, b: ScheduleEntry) => number, error: (error: any) => void = NO_OP): void {
this.api.getList("scheduleEntry/findAll", ScheduleEntry.fromJson, compare, next, errorHandler); this.api.getList("scheduleEntry/findAll", ScheduleEntry.fromJson, compare, next, error);
} }
set(entry: ScheduleEntry, key: string, value: any, next: (item: ScheduleEntry) => void, errorHandler: (error: any) => void = NO_OP): void { set(entry: ScheduleEntry, key: string, value: any, next: (item: ScheduleEntry) => void, error: (error: any) => void = NO_OP): void {
this.api.postReturnItem("schedule/entry/set/" + entry.id + "/" + key, value, ScheduleEntry.fromJson, next, errorHandler); this.api.postReturnItem("schedule/entry/set/" + entry.id + "/" + key, value, ScheduleEntry.fromJson, next, error);
}
create(schedule: Schedule, next: (item: ScheduleEntry) => void, error: (error: any) => void = NO_OP): void {
this.api.getItem("schedule/entry/create/" + schedule.id, ScheduleEntry.fromJson, next, error);
}
delete(entry: ScheduleEntry, next: () => void, error: (error: any) => void = NO_OP): void {
this.api.getItem("schedule/entry/delete/" + entry.id, _ => _, next, error);
} }
} }

View File

@ -13,16 +13,24 @@ export class ScheduleService {
// nothing // nothing
} }
findAll(next: (list: Schedule[]) => void, compare: (a: Schedule, b: Schedule) => number, errorHandler: (error: any) => void = NO_OP): void { findAll(next: (list: Schedule[]) => void, compare: (a: Schedule, b: Schedule) => number, error: (error: any) => void = NO_OP): void {
this.api.getList("schedule/findAll", Schedule.fromJson, compare, next, errorHandler); this.api.getList("schedule/findAll", Schedule.fromJson, compare, next, error);
} }
set(schedule: Schedule, key: string, value: any, next: (item: Schedule) => void, errorHandler: (error: any) => void = NO_OP): void { set(schedule: Schedule, key: string, value: any, next: (item: Schedule) => void, error: (error: any) => void = NO_OP): void {
this.api.postReturnItem("schedule/set/" + schedule.id + "/" + key, value, Schedule.fromJson, next, errorHandler); this.api.postReturnItem("schedule/set/" + schedule.id + "/" + key, value, Schedule.fromJson, next, error);
} }
findById(id: number, next: (item: Schedule) => void, errorHandler: (error: any) => void = NO_OP): void { findById(id: number, next: (item: Schedule) => void, error: (error: any) => void = NO_OP): void {
this.api.getItem("schedule/findById/" + id, Schedule.fromJson, next, errorHandler); this.api.getItem("schedule/findById/" + id, Schedule.fromJson, next, error);
}
create(next: (item: Schedule) => void, error: (error: any) => void = NO_OP): void {
this.api.getItem("schedule/create/", Schedule.fromJson, next, error);
}
delete(schedule: Schedule, next: () => void, error: (error: any) => void = NO_OP): void {
this.api.getItem("schedule/delete/" + schedule.id, _ => _, next, error);
} }
} }

View File

@ -2,14 +2,26 @@
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>Bezeichnung</th> <th>Bezeichnung</th>
<th>&nbsp;</th>
</tr> </tr>
<tr *ngFor="let schedule of schedules; trackBy: Schedule.trackBy"> <tr *ngFor="let schedule of schedules; trackBy: Schedule.trackBy">
<td class="boolean" (click)="set(schedule, 'enabled', !schedule.enabled)" [class.true]="schedule.enabled" [class.false]="!schedule.enabled"> <td class="boolean" (click)="set(schedule, 'enabled', !schedule.enabled)" [class.true]="schedule.enabled" [class.false]="!schedule.enabled">
<fa-icon *ngIf="schedule.enabled" [icon]="faCheck"></fa-icon> <fa-icon *ngIf="schedule.enabled" [icon]="faCheckCircle"></fa-icon>
<fa-icon *ngIf="!schedule.enabled" [icon]="faTimes"></fa-icon> <fa-icon *ngIf="!schedule.enabled" [icon]="faCircle"></fa-icon>
</td> </td>
<td [routerLink]="['/Schedule', {id: schedule.id}]"> <td [routerLink]="['/Schedule', {id: schedule.id}]">
{{schedule.name}} {{schedule.name}}
</td> </td>
<td class="delete" (click)="delete(schedule)">
<fa-icon title="Löschen" [icon]="faTimes"></fa-icon>
</td>
</tr> </tr>
</table> </table>
<p>
<button (click)="create()">+ Hinzufügen</button>
</p>

View File

@ -10,22 +10,6 @@ th {
background-color: lightblue; background-color: lightblue;
} }
tr.blank {
th, td {
border: none;
}
}
tr.header {
th:not(:first-child), td:not(:first-child) {
border: none;
}
}
.empty { .empty {
text-align: center; text-align: center;
color: gray; color: gray;
@ -57,7 +41,7 @@ tr.header {
padding-right: 0; padding-right: 0;
} }
.minute { .middle {
border-right-width: 0; border-right-width: 0;
border-left-width: 0; border-left-width: 0;
padding-right: 0; padding-right: 0;
@ -69,11 +53,8 @@ tr.header {
padding-left: 0; padding-left: 0;
} }
.middle { .delete {
border-right-width: 0; color: darkred;
border-left-width: 0;
padding-right: 0;
padding-left: 0;
} }
.disabled { .disabled {

View File

@ -1,7 +1,7 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ScheduleService} from "../../api/schedule/schedule.service"; import {ScheduleService} from "../../api/schedule/schedule.service";
import {Schedule} from "../../api/schedule/Schedule"; import {Schedule} from "../../api/schedule/Schedule";
import {faCheck, faTimes} from '@fortawesome/free-solid-svg-icons'; import {faCheckCircle, faCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons';
@Component({ @Component({
selector: 'app-schedule-list', selector: 'app-schedule-list',
@ -10,8 +10,9 @@ import {faCheck, faTimes} from '@fortawesome/free-solid-svg-icons';
}) })
export class ScheduleListComponent implements OnInit { export class ScheduleListComponent implements OnInit {
readonly faCheck = faCheck; readonly faCheckCircle = faCheckCircle;
readonly faTimes = faTimes; readonly faCircle = faCircle;
readonly faTimes = faTimesCircle;
readonly Schedule = Schedule; readonly Schedule = Schedule;
schedules: Schedule[] = []; schedules: Schedule[] = [];
@ -27,10 +28,10 @@ export class ScheduleListComponent implements OnInit {
} }
set(schedule: Schedule, key: string, value: any): void { set(schedule: Schedule, key: string, value: any): void {
this.scheduleService.set(schedule, key, value, schedule => this.updateSchedule(schedule)); this.scheduleService.set(schedule, key, value, schedule => this.addOrReplace(schedule));
} }
private updateSchedule(schedule: Schedule): void { private addOrReplace(schedule: Schedule): void {
const index: number = this.schedules.findIndex(s => s.id === schedule.id); const index: number = this.schedules.findIndex(s => s.id === schedule.id);
if (index < 0) { if (index < 0) {
this.schedules.push(schedule); this.schedules.push(schedule);
@ -40,4 +41,16 @@ export class ScheduleListComponent implements OnInit {
this.schedules = this.schedules.sort(Schedule.compareName) this.schedules = this.schedules.sort(Schedule.compareName)
} }
private remove(schedule: Schedule): void {
this.schedules.splice(this.schedules.findIndex(s => s.id === schedule.id), 1);
}
create(): void {
this.scheduleService.create(schedule => this.addOrReplace(schedule));
}
delete(schedule: Schedule): void {
this.scheduleService.delete(schedule, () => this.remove(schedule));
}
} }

View File

@ -1,20 +1,20 @@
<ng-container *ngIf="dataService.schedule"> <ng-container *ngIf="schedule">
<ng-template #boolean let-entry="entry" let-value="value" let-key="key"> <ng-template #boolean let-entry="entry" let-value="value" let-key="key">
<td class="boolean" (click)="set(entry, key, !value)" [class.true]="value" [class.false]="!value"> <td class="boolean" (click)="set(entry, key, !value)" [class.true]="value" [class.false]="!value">
<fa-icon *ngIf="value" [icon]="faCheck"></fa-icon> <fa-icon *ngIf="value" [icon]="faCheckCircle"></fa-icon>
<fa-icon *ngIf="!value" [icon]="faTimes"></fa-icon> <fa-icon *ngIf="!value" [icon]="faCircle"></fa-icon>
</td> </td>
</ng-template> </ng-template>
<table> <table>
<tr class="header"> <tr class="header">
<ng-container *ngTemplateOutlet="boolean;context:{schedule: dataService.schedule, value: dataService.schedule.enabled, key:'enabled'}"></ng-container> <ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, value: schedule.enabled, key:'enabled'}"></ng-container>
<td colspan="20"> <td colspan="20">
<app-edit-field [initial]="dataService.schedule.name" (valueChange)="set(null, 'name', $event)"></app-edit-field> <app-edit-field [initial]="schedule.name" (valueChange)="set(null, 'name', $event)"></app-edit-field>
</td> </td>
</tr> </tr>
<tr [class.disabled]="!dataService.schedule.enabled"> <tr [class.disabled]="!schedule.enabled">
<th>&nbsp;</th> <th>&nbsp;</th>
<th>Mo</th> <th>Mo</th>
<th>Di</th> <th>Di</th>
@ -28,8 +28,9 @@
<th colspan="3">Uhrzeit</th> <th colspan="3">Uhrzeit</th>
<th>Unschärfe</th> <th>Unschärfe</th>
<th colspan="6">Nächste Ausführung</th> <th colspan="6">Nächste Ausführung</th>
<th>&nbsp;</th>
</tr> </tr>
<tr *ngFor="let entry of dataService.schedule.entries" [class.disabled]="entry.nextClearTimestamp === null"> <tr *ngFor="let entry of schedule.entries" [class.disabled]="entry.nextClearTimestamp === null">
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.enabled, key:'enabled'}"></ng-container> <ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.enabled, key:'enabled'}"></ng-container>
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.monday, key:'monday'}"></ng-container> <ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.monday, key:'monday'}"></ng-container>
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.tuesday, key:'tuesday'}"></ng-container> <ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.tuesday, key:'tuesday'}"></ng-container>
@ -119,7 +120,15 @@
<td class="empty last"></td> <td class="empty last"></td>
</ng-container> </ng-container>
<td class="delete" (click)="delete(entry)">
<fa-icon title="Löschen" [icon]="faTimes"></fa-icon>
</td>
</tr> </tr>
</table> </table>
<p>
<button (click)="create()">+ Hinzufügen</button>
</p>
</ng-container> </ng-container>

View File

@ -10,14 +10,6 @@ th {
background-color: lightblue; background-color: lightblue;
} }
tr.blank {
th, td {
border: none;
}
}
tr.header { tr.header {
th:not(:first-child), td:not(:first-child) { th:not(:first-child), td:not(:first-child) {
@ -57,7 +49,7 @@ tr.header {
padding-right: 0; padding-right: 0;
} }
.minute { .middle {
border-right-width: 0; border-right-width: 0;
border-left-width: 0; border-left-width: 0;
padding-right: 0; padding-right: 0;
@ -69,11 +61,8 @@ tr.header {
padding-left: 0; padding-left: 0;
} }
.middle { .delete {
border-right-width: 0; color: darkred;
border-left-width: 0;
padding-right: 0;
padding-left: 0;
} }
.disabled { .disabled {

View File

@ -3,7 +3,7 @@ import {ScheduleService} from "../../api/schedule/schedule.service";
import {Schedule} from "../../api/schedule/Schedule"; import {Schedule} from "../../api/schedule/Schedule";
import {ScheduleEntry} from "../../api/schedule/entry/ScheduleEntry"; import {ScheduleEntry} from "../../api/schedule/entry/ScheduleEntry";
import {ScheduleEntryService} from "../../api/schedule/entry/schedule-entry.service"; import {ScheduleEntryService} from "../../api/schedule/entry/schedule-entry.service";
import {faCheck, faTimes} from '@fortawesome/free-solid-svg-icons'; import {faCheckCircle, faCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons';
import {ActivatedRoute} from "@angular/router"; import {ActivatedRoute} from "@angular/router";
import {DataService} from "../../data.service"; import {DataService} from "../../data.service";
@ -14,10 +14,13 @@ import {DataService} from "../../data.service";
}) })
export class ScheduleComponent implements OnInit { export class ScheduleComponent implements OnInit {
readonly faCheck = faCheck; readonly faCheckCircle = faCheckCircle;
readonly faTimes = faTimes; readonly faCircle = faCircle;
readonly faTimes = faTimesCircle;
readonly Schedule = Schedule; readonly Schedule = Schedule;
schedule!: Schedule;
constructor( constructor(
readonly activatedRoute: ActivatedRoute, readonly activatedRoute: ActivatedRoute,
readonly scheduleService: ScheduleService, readonly scheduleService: ScheduleService,
@ -33,30 +36,38 @@ export class ScheduleComponent implements OnInit {
} }
private setSchedule(schedule: Schedule): void { private setSchedule(schedule: Schedule): void {
this.schedule = schedule;
this.dataService.schedule = schedule; this.dataService.schedule = schedule;
} }
set(entry: ScheduleEntry | null, key: string, value: any): void { set(entry: ScheduleEntry | null, key: string, value: any): void {
if (entry) { if (entry) {
this.scheduleEntryService.set(entry, key, value, entry => this.updateEntry(entry)); this.scheduleEntryService.set(entry, key, value, entry => this.addOrReplace(entry));
} else { } else {
if (this.dataService.schedule) { this.scheduleService.set(this.schedule, key, value, schedule => this.setSchedule(schedule));
this.scheduleService.set(this.dataService.schedule, key, value, schedule => this.dataService.schedule = schedule);
}
} }
} }
private updateEntry(entry: ScheduleEntry): void { private addOrReplace(entry: ScheduleEntry): void {
if (!this.dataService.schedule) { const index: number = this.schedule.entries.findIndex(s => s.id === entry.id);
return;
}
const index: number = this.dataService.schedule.entries.findIndex(s => s.id === entry.id);
if (index < 0) { if (index < 0) {
this.dataService.schedule.entries.push(entry); this.schedule.entries.push(entry);
} else { } else {
this.dataService.schedule.entries[index] = entry; this.schedule.entries[index] = entry;
} }
this.dataService.schedule.entries = this.dataService.schedule.entries.sort(ScheduleEntry.compareId) this.schedule.entries = this.schedule.entries.sort(ScheduleEntry.compareId)
}
private remove(entry: ScheduleEntry): void {
this.schedule.entries.splice(this.schedule.entries.findIndex(e => e.id === entry.id), 1);
}
create(): void {
this.scheduleEntryService.create(this.schedule, entry => this.addOrReplace(entry));
}
delete(entry: ScheduleEntry): void {
this.scheduleEntryService.delete(entry, () => this.remove(entry));
} }
} }

View File

@ -46,6 +46,7 @@ public class DemoDataService {
if (scheduleRepository.count() == 0) { if (scheduleRepository.count() == 0) {
final Schedule scheduleEgFlurLicht = new Schedule(); final Schedule scheduleEgFlurLicht = new Schedule();
scheduleEgFlurLicht.setEnabled(true);
scheduleEgFlurLicht.setName("EG Flur Licht"); scheduleEgFlurLicht.setName("EG Flur Licht");
createTime(scheduleEgFlurLicht, 11, 30, 0, MIN30, new PropertyEntry(eg_flur_licht_schalten, true)); createTime(scheduleEgFlurLicht, 11, 30, 0, MIN30, new PropertyEntry(eg_flur_licht_schalten, true));
createTime(scheduleEgFlurLicht, 12, 30, 0, MIN30, new PropertyEntry(eg_flur_licht_schalten, false)); createTime(scheduleEgFlurLicht, 12, 30, 0, MIN30, new PropertyEntry(eg_flur_licht_schalten, false));
@ -58,6 +59,7 @@ public class DemoDataService {
scheduleRepository.save(scheduleEgFlurLicht); scheduleRepository.save(scheduleEgFlurLicht);
final Schedule scheduleEgAmbiente = new Schedule(); final Schedule scheduleEgAmbiente = new Schedule();
scheduleEgAmbiente.setEnabled(true);
scheduleEgAmbiente.setName("EG Ambiente"); scheduleEgAmbiente.setName("EG Ambiente");
createTime(scheduleEgAmbiente, 7, 15, 0, MIN30, new PropertyEntry(eg_ambiente_schalten, true)); createTime(scheduleEgAmbiente, 7, 15, 0, MIN30, new PropertyEntry(eg_ambiente_schalten, true));
createTime(scheduleEgAmbiente, 9, 30, 0, MIN30, new PropertyEntry(eg_ambiente_schalten, false)); createTime(scheduleEgAmbiente, 9, 30, 0, MIN30, new PropertyEntry(eg_ambiente_schalten, false));
@ -66,6 +68,7 @@ public class DemoDataService {
scheduleRepository.save(scheduleEgAmbiente); scheduleRepository.save(scheduleEgAmbiente);
final Schedule scheduleOgAmbiente = new Schedule(); final Schedule scheduleOgAmbiente = new Schedule();
scheduleOgAmbiente.setEnabled(true);
scheduleOgAmbiente.setName("OG Ambiente"); scheduleOgAmbiente.setName("OG Ambiente");
createTime(scheduleOgAmbiente, 7, 15, 0, MIN30, new PropertyEntry(og_ambiente_schalten, true)); createTime(scheduleOgAmbiente, 7, 15, 0, MIN30, new PropertyEntry(og_ambiente_schalten, true));
createTime(scheduleOgAmbiente, 9, 30, 0, MIN30, new PropertyEntry(og_ambiente_schalten, false)); createTime(scheduleOgAmbiente, 9, 30, 0, MIN30, new PropertyEntry(og_ambiente_schalten, false));
@ -74,24 +77,28 @@ public class DemoDataService {
scheduleRepository.save(scheduleOgAmbiente); scheduleRepository.save(scheduleOgAmbiente);
final Schedule scheduleWohnzimmerRollladen = new Schedule(); final Schedule scheduleWohnzimmerRollladen = new Schedule();
scheduleWohnzimmerRollladen.setEnabled(true);
scheduleWohnzimmerRollladen.setName("Rollläden Wohnzimmer"); scheduleWohnzimmerRollladen.setName("Rollläden Wohnzimmer");
createSunrise(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren, 0)); createSunrise(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren, 0));
createSunset(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren, 100)); createSunset(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(wohnzimmer_rollladen_position_anfahren, 100));
scheduleRepository.save(scheduleWohnzimmerRollladen); scheduleRepository.save(scheduleWohnzimmerRollladen);
final Schedule scheduleSchlafzimmerRollladen = new Schedule(); final Schedule scheduleSchlafzimmerRollladen = new Schedule();
scheduleSchlafzimmerRollladen.setEnabled(true);
scheduleSchlafzimmerRollladen.setName("Rollläden Schlafzimmer"); scheduleSchlafzimmerRollladen.setName("Rollläden Schlafzimmer");
createTime(scheduleSchlafzimmerRollladen, 7, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren, 0)); createTime(scheduleSchlafzimmerRollladen, 7, 0, 0, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren, 0));
createSunset(scheduleSchlafzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren, 100)); createSunset(scheduleSchlafzimmerRollladen, Zenith.CIVIL, 0, new PropertyEntry(schlafzimmer_rollladen_position_anfahren, 100));
scheduleRepository.save(scheduleSchlafzimmerRollladen); scheduleRepository.save(scheduleSchlafzimmerRollladen);
final Schedule scheduleFlurRollladen = new Schedule(); final Schedule scheduleFlurRollladen = new Schedule();
scheduleFlurRollladen.setEnabled(true);
scheduleFlurRollladen.setName("Rollläden Flur"); scheduleFlurRollladen.setName("Rollläden Flur");
createSunrise(scheduleFlurRollladen, Zenith.CIVIL, 0, new PropertyEntry(flur_rollladen_position_anfahren, 0)); createSunrise(scheduleFlurRollladen, Zenith.CIVIL, 0, new PropertyEntry(flur_rollladen_position_anfahren, 0));
createSunset(scheduleFlurRollladen, Zenith.CIVIL, 0, new PropertyEntry(flur_rollladen_position_anfahren, 100)); createSunset(scheduleFlurRollladen, Zenith.CIVIL, 0, new PropertyEntry(flur_rollladen_position_anfahren, 100));
scheduleRepository.save(scheduleFlurRollladen); scheduleRepository.save(scheduleFlurRollladen);
final Schedule scheduleBadLichtMitte = new Schedule(); final Schedule scheduleBadLichtMitte = new Schedule();
scheduleBadLichtMitte.setEnabled(true);
scheduleBadLichtMitte.setName("Bad Licht Mitte"); scheduleBadLichtMitte.setName("Bad Licht Mitte");
createTime(scheduleBadLichtMitte, 10, 30, 0, MIN30, new PropertyEntry(bad_licht_mitteschalten, true)); createTime(scheduleBadLichtMitte, 10, 30, 0, MIN30, new PropertyEntry(bad_licht_mitteschalten, true));
createTime(scheduleBadLichtMitte, 11, 30, 0, MIN30, new PropertyEntry(bad_licht_mitteschalten, false)); createTime(scheduleBadLichtMitte, 11, 30, 0, MIN30, new PropertyEntry(bad_licht_mitteschalten, false));
@ -115,23 +122,24 @@ public class DemoDataService {
private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final int fuzzySeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createRelative(final Schedule schedule, final int inSeconds, final int fuzzySeconds, final Map.Entry<String, String>... entries) {
final ZonedDateTime now = ZonedDateTime.now().plusSeconds(inSeconds).withNano(0); final ZonedDateTime now = ZonedDateTime.now().plusSeconds(inSeconds).withNano(0);
return create(schedule, ScheduleEntryType.TIME, null, now.getHour(), now.getMinute(), now.getSecond(), fuzzySeconds, entries); return newScheduleEntry(schedule, ScheduleEntryType.TIME, null, now.getHour(), now.getMinute(), now.getSecond(), fuzzySeconds, entries);
} }
private ScheduleEntry createTime(final Schedule schedule, final int hour, final int minute, final int second, final int fuzzySeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createTime(final Schedule schedule, final int hour, final int minute, final int second, final int fuzzySeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.TIME, null, hour, minute, second, fuzzySeconds, entries); return newScheduleEntry(schedule, ScheduleEntryType.TIME, null, hour, minute, second, fuzzySeconds, entries);
} }
private ScheduleEntry createSunrise(final Schedule schedule, final Zenith zenith, final int fuzzySeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createSunrise(final Schedule schedule, final Zenith zenith, final int fuzzySeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, fuzzySeconds, entries); return newScheduleEntry(schedule, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, fuzzySeconds, entries);
} }
private ScheduleEntry createSunset(final Schedule schedule, final Zenith zenith, final int fuzzySeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry createSunset(final Schedule schedule, final Zenith zenith, final int fuzzySeconds, final Map.Entry<String, String>... entries) {
return create(schedule, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, fuzzySeconds, entries); return newScheduleEntry(schedule, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, fuzzySeconds, entries);
} }
private ScheduleEntry create(final Schedule schedule, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final int fuzzySeconds, final Map.Entry<String, String>... entries) { private ScheduleEntry newScheduleEntry(final Schedule schedule, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final int fuzzySeconds, final Map.Entry<String, String>... entries) {
final ScheduleEntry entry = new ScheduleEntry(); final ScheduleEntry entry = new ScheduleEntry();
entry.setEnabled(true);
entry.setType(type); entry.setType(type);
if (zenith != null) { if (zenith != null) {
entry.setZenith(zenith.degrees().doubleValue()); entry.setZenith(zenith.degrees().doubleValue());

View File

@ -21,12 +21,11 @@ public class Schedule {
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
private Long id; private Long id;
private boolean enabled = true; private boolean enabled = false;
@Column(nullable = false, unique = true) @Column(nullable = false, unique = true)
private String name; private String name;
// TODO move ownership of relation to ScheduleEntry ???
@ToString.Exclude @ToString.Exclude
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Set<ScheduleEntry> entries = new HashSet<>(); private Set<ScheduleEntry> entries = new HashSet<>();

View File

@ -30,6 +30,16 @@ public class ScheduleController {
return scheduleReadService.findAllNextExecutionDtos(); return scheduleReadService.findAllNextExecutionDtos();
} }
@GetMapping("create")
public ScheduleDto create() {
return scheduleWriteService.create();
}
@GetMapping("delete/{id}")
public void delete(@PathVariable final long id) {
scheduleWriteService.delete(id);
}
@PostMapping("set/{id}/enabled") @PostMapping("set/{id}/enabled")
public ScheduleDto setEnabled(@PathVariable final long id, @RequestBody final boolean enabled) { public ScheduleDto setEnabled(@PathVariable final long id, @RequestBody final boolean enabled) {
return scheduleWriteService.set(id, Schedule::setEnabled, enabled); return scheduleWriteService.set(id, Schedule::setEnabled, enabled);

View File

@ -24,7 +24,7 @@ public class ScheduleReadService {
private final ScheduleMapper scheduleMapper; private final ScheduleMapper scheduleMapper;
public Schedule get(final long id) { public Schedule getById(final long id) {
return scheduleRepository.findById(id).orElseThrow(() -> new NotFoundException("Schedule.id=%d", id)); return scheduleRepository.findById(id).orElseThrow(() -> new NotFoundException("Schedule.id=%d", id));
} }
@ -51,7 +51,7 @@ public class ScheduleReadService {
} }
public ScheduleDto getDtoById(final long id) { public ScheduleDto getDtoById(final long id) {
return scheduleMapper.toDto(get(id)); return scheduleMapper.toDto(getById(id));
} }
} }

View File

@ -11,4 +11,6 @@ public interface ScheduleRepository extends CrudRepository<Schedule, Long> {
Schedule getByEntriesContaining(ScheduleEntry entry); Schedule getByEntriesContaining(ScheduleEntry entry);
boolean existsByName(String name);
} }

View File

@ -14,17 +14,40 @@ import java.util.function.BiConsumer;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ScheduleWriteService { public class ScheduleWriteService {
public static final String NAME_PREFIX = "Neu ";
private final ScheduleReadService scheduleReadService; private final ScheduleReadService scheduleReadService;
private final ScheduleCalculationService scheduleCalculationService; private final ScheduleCalculationService scheduleCalculationService;
private final ScheduleMapper scheduleMapper; private final ScheduleMapper scheduleMapper;
private final ScheduleRepository scheduleRepository;
public <T> ScheduleDto set(final long id, final BiConsumer<Schedule, T> setter, final T value) { public <T> ScheduleDto set(final long id, final BiConsumer<Schedule, T> setter, final T value) {
final Schedule schedule = scheduleReadService.get(id); final Schedule schedule = scheduleReadService.getById(id);
setter.accept(schedule, value); setter.accept(schedule, value);
scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now()); scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now());
return scheduleMapper.toDto(schedule); return scheduleMapper.toDto(schedule);
} }
public ScheduleDto create() {
final Schedule entry = new Schedule();
entry.setName(generateUnusedName());
return scheduleMapper.toDto(scheduleRepository.save(entry));
}
private String generateUnusedName() {
int index = 0;
String name = null;
while (name == null || scheduleRepository.existsByName(name)) {
name = ScheduleWriteService.NAME_PREFIX + ++index;
}
return name;
}
public void delete(final long id) {
scheduleRepository.deleteById(id);
}
} }

View File

@ -23,7 +23,7 @@ public class ScheduleEntry {
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
private Long id; private Long id;
private boolean enabled = true; private boolean enabled = false;
private boolean monday = true; private boolean monday = true;
@ -40,15 +40,15 @@ public class ScheduleEntry {
private boolean sunday = true; private boolean sunday = true;
@Column(nullable = false) @Column(nullable = false)
private ScheduleEntryType type = null; private ScheduleEntryType type = ScheduleEntryType.TIME;
private double zenith = Zenith.CIVIL.degrees().doubleValue(); private double zenith = Zenith.CIVIL.degrees().doubleValue();
private int hour; private int hour = 0;
private int minute; private int minute = 0;
private int second; private int second = 0;
private int fuzzySeconds = 0; private int fuzzySeconds = 0;

View File

@ -10,6 +10,16 @@ public class ScheduleEntryController {
private final ScheduleEntryWriteService scheduleEntryWriteService; private final ScheduleEntryWriteService scheduleEntryWriteService;
@GetMapping("create/{scheduleId}")
public ScheduleEntryDto create(@PathVariable final long scheduleId) {
return scheduleEntryWriteService.create(scheduleId);
}
@GetMapping("delete/{id}")
public void delete(@PathVariable final long id) {
scheduleEntryWriteService.delete(id);
}
@PostMapping("set/{id}/enabled") @PostMapping("set/{id}/enabled")
public ScheduleEntryDto setEnabled(@PathVariable final long id, @RequestBody final boolean value) { public ScheduleEntryDto setEnabled(@PathVariable final long id, @RequestBody final boolean value) {
return scheduleEntryWriteService.set(id, ScheduleEntry::setEnabled, value); return scheduleEntryWriteService.set(id, ScheduleEntry::setEnabled, value);

View File

@ -17,7 +17,7 @@ public class ScheduleEntryReadService {
private final ScheduleEntryRepository scheduleEntryRepository; private final ScheduleEntryRepository scheduleEntryRepository;
public ScheduleEntry get(final long id) { public ScheduleEntry getById(final long id) {
return scheduleEntryRepository.findById(id).orElseThrow(() -> new NotFoundException("ScheduleEntry.id=%d", id)); return scheduleEntryRepository.findById(id).orElseThrow(() -> new NotFoundException("ScheduleEntry.id=%d", id));
} }

View File

@ -25,12 +25,27 @@ public class ScheduleEntryWriteService {
private final ScheduleEntryMapper scheduleEntryMapper; private final ScheduleEntryMapper scheduleEntryMapper;
private final ScheduleEntryRepository scheduleEntryRepository;
public <T> ScheduleEntryDto set(final long id, final BiConsumer<ScheduleEntry, T> setter, final T value) { public <T> ScheduleEntryDto set(final long id, final BiConsumer<ScheduleEntry, T> setter, final T value) {
final ScheduleEntry entry = scheduleEntryReadService.get(id); final ScheduleEntry entry = scheduleEntryReadService.getById(id);
setter.accept(entry, value); setter.accept(entry, value);
final Schedule schedule = scheduleReadService.getByEntry(entry); final Schedule schedule = scheduleReadService.getByEntry(entry);
scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now()); scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now());
return scheduleEntryMapper.toDto(entry); return scheduleEntryMapper.toDto(entry);
} }
public ScheduleEntryDto create(final long scheduleId) {
final Schedule schedule = scheduleReadService.getById(scheduleId);
final ScheduleEntry entry = new ScheduleEntry();
schedule.getEntries().add(scheduleEntryRepository.save(entry));
return scheduleEntryMapper.toDto(entry);
}
public void delete(final long id) {
final ScheduleEntry entry = scheduleEntryReadService.getById(id);
scheduleReadService.getByEntry(entry).getEntries().remove(entry);
scheduleEntryRepository.delete(entry);
}
} }