UI: splitted Schedule into list- and single-view
This commit is contained in:
parent
255d03da4e
commit
ed2d5172bf
@ -2,43 +2,5 @@
|
|||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
config.set({
|
config.set();
|
||||||
basePath: '',
|
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
||||||
plugins: [
|
|
||||||
require('karma-jasmine'),
|
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
jasmine: {
|
|
||||||
// you can add configuration options for Jasmine here
|
|
||||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
|
||||||
// for example, you can disable the random execution with `random: false`
|
|
||||||
// or set a specific seed with `seed: 4321`
|
|
||||||
},
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
|
||||||
jasmineHtmlReporter: {
|
|
||||||
suppressAll: true // removes the duplicated traces
|
|
||||||
},
|
|
||||||
coverageReporter: {
|
|
||||||
dir: require('path').join(__dirname, './coverage/angular'),
|
|
||||||
subdir: '.',
|
|
||||||
reporters: [
|
|
||||||
{type: 'html'},
|
|
||||||
{type: 'text-summary'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: false,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,4 +21,8 @@ export class ScheduleService {
|
|||||||
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, errorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findById(id: number, next: (item: Schedule) => void, errorHandler: (error: any) => void = NO_OP): void {
|
||||||
|
this.api.getItem("schedule/findById/" + id, Schedule.fromJson, next, errorHandler);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {ScheduleListComponent} from "./pages/schedule-list/schedule-list.component";
|
import {ScheduleListComponent} from "./pages/schedule-list/schedule-list.component";
|
||||||
|
import {ScheduleComponent} from "./pages/schedule/schedule.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
|
{path: 'Schedule', component: ScheduleComponent},
|
||||||
{path: 'ScheduleList', component: ScheduleListComponent},
|
{path: 'ScheduleList', component: ScheduleListComponent},
|
||||||
{path: '**', redirectTo: '/ScheduleList'},
|
{path: '**', redirectTo: '/ScheduleList'},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
<div class="menubar">
|
<div class="menubar">
|
||||||
|
|
||||||
<div class="item" routerLink="/ScheduleList" routerLinkActive="itemActive">
|
<div class="item" routerLink="/ScheduleList" routerLinkActive="itemActive">
|
||||||
Zeitplan
|
Zeitplan
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="item breadcrumb" [routerLink]="['/Schedule', {id: dataService.schedule.id}]" routerLinkActive="itemActive" *ngIf="dataService.schedule">
|
||||||
|
{{dataService.schedule.name}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|||||||
@ -7,6 +7,10 @@
|
|||||||
border-right: 1px solid black;
|
border-right: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
background-color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
.itemActive {
|
.itemActive {
|
||||||
background-color: lightblue;
|
background-color: lightblue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,11 +9,13 @@ import {EditFieldComponent} from './shared/edit-field/edit-field.component';
|
|||||||
import {ScheduleListComponent} from './pages/schedule-list/schedule-list.component';
|
import {ScheduleListComponent} from './pages/schedule-list/schedule-list.component';
|
||||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||||
import {NumberComponent} from './shared/number/number.component';
|
import {NumberComponent} from './shared/number/number.component';
|
||||||
|
import {ScheduleComponent} from "./pages/schedule/schedule.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
EditFieldComponent,
|
EditFieldComponent,
|
||||||
|
ScheduleComponent,
|
||||||
ScheduleListComponent,
|
ScheduleListComponent,
|
||||||
NumberComponent,
|
NumberComponent,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,10 +1,21 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
import {Schedule} from "./api/schedule/Schedule";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService {
|
export class DataService {
|
||||||
|
|
||||||
|
private _schedule?: Schedule;
|
||||||
|
|
||||||
|
get schedule(): Schedule | undefined {
|
||||||
|
return this._schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
set schedule(schedule: Schedule | undefined) {
|
||||||
|
this._schedule = schedule;
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,124 +1,15 @@
|
|||||||
<ng-template #boolean let-schedule="schedule" let-entry="entry" let-value="value" let-key="key">
|
|
||||||
<td class="boolean" (click)="set(schedule, entry, key, !value)" [class.true]="value" [class.false]="!value">
|
|
||||||
<fa-icon *ngIf="value" [icon]="faCheck"></fa-icon>
|
|
||||||
<fa-icon *ngIf="!value" [icon]="faTimes"></fa-icon>
|
|
||||||
</td>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<ng-container *ngFor="let schedule of schedules; let first = first; trackBy: Schedule.trackBy">
|
<tr>
|
||||||
<tr *ngIf="!first" class="blank">
|
<th> </th>
|
||||||
<td colspan="21"> </td>
|
<th>Bezeichnung</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="header">
|
<tr *ngFor="let schedule of schedules; trackBy: Schedule.trackBy">
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, value: schedule.enabled, key:'enabled'}"></ng-container>
|
<td class="boolean" (click)="set(schedule, 'enabled', !schedule.enabled)" [class.true]="schedule.enabled" [class.false]="!schedule.enabled">
|
||||||
<td colspan="20">{{schedule.name}}</td>
|
<fa-icon *ngIf="schedule.enabled" [icon]="faCheck"></fa-icon>
|
||||||
</tr>
|
<fa-icon *ngIf="!schedule.enabled" [icon]="faTimes"></fa-icon>
|
||||||
<tr [class.disabled]="!schedule.enabled">
|
</td>
|
||||||
<th> </th>
|
<td [routerLink]="['/Schedule', {id: schedule.id}]">
|
||||||
<th>Mo</th>
|
{{schedule.name}}
|
||||||
<th>Di</th>
|
</td>
|
||||||
<th>Mi</th>
|
</tr>
|
||||||
<th>Do</th>
|
|
||||||
<th>Fr</th>
|
|
||||||
<th>Sa</th>
|
|
||||||
<th>So</th>
|
|
||||||
<th>Typ</th>
|
|
||||||
<th>Sonnenstand</th>
|
|
||||||
<th colspan="3">Uhrzeit</th>
|
|
||||||
<th>Unschärfe</th>
|
|
||||||
<th colspan="6">Nächste Ausführung</th>
|
|
||||||
</tr>
|
|
||||||
<tr *ngFor="let entry of schedule.entries" [class.disabled]="entry.nextClearTimestamp === null">
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.enabled, key:'enabled'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.monday, key:'monday'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.tuesday, key:'tuesday'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.wednesday, key:'wednesday'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.thursday, key:'thursday'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.friday, key:'friday'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.saturday, key:'saturday'}"></ng-container>
|
|
||||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, entry: entry, value: entry.sunday, key:'sunday'}"></ng-container>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<select [(ngModel)]="entry.type" (ngModelChange)="set(schedule, entry, 'type', entry.type)">
|
|
||||||
<option value="TIME">Uhrzeit</option>
|
|
||||||
<option value="SUNRISE">Sonnenaufgang</option>
|
|
||||||
<option value="SUNSET">Sonnenuntergang</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<ng-container *ngIf="entry.type === 'SUNRISE' || entry.type === 'SUNSET'">
|
|
||||||
<td>
|
|
||||||
<select class="number" [(ngModel)]="entry.zenith" (ngModelChange)="set(schedule, entry, 'zenith', entry.zenith)">
|
|
||||||
<option value="90.8333">
|
|
||||||
<ng-container *ngIf="entry.type === 'SUNRISE'">Sonnenaufgang</ng-container>
|
|
||||||
<ng-container *ngIf="entry.type === 'SUNSET'">Sonnenuntergang</ng-container>
|
|
||||||
[ 90°]
|
|
||||||
</option>
|
|
||||||
<option value="93">[ 93°]</option>
|
|
||||||
<option value="96">Bürgerliche Dämmerung [ 96°]</option>
|
|
||||||
<option value="99">[ 99°]</option>
|
|
||||||
<option value="102">Nautische Dämmerung [102°]</option>
|
|
||||||
<option value="105">[105°]</option>
|
|
||||||
<option value="108">Astronomische Dämmerung [108°]</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
<td *ngIf="entry.type !== 'SUNRISE' && entry.type !== 'SUNSET'" class="empty"></td>
|
|
||||||
|
|
||||||
<ng-container *ngIf="entry.type === 'TIME'">
|
|
||||||
<td class="first">
|
|
||||||
<select class="number" [(ngModel)]="entry.hour" (ngModelChange)="set(schedule, entry, 'hour', entry.hour)">
|
|
||||||
<option *ngFor="let _ of [].constructor(60); let value = index" [ngValue]="value">{{value}}</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td class="middle">:</td>
|
|
||||||
<td class="last">
|
|
||||||
<select class="number" [(ngModel)]="entry.minute" (ngModelChange)="set(schedule, entry, 'minute', entry.minute)">
|
|
||||||
<option *ngFor="let _ of [].constructor(60); let value = index" [ngValue]="value">{{value | number:'2.0'}}</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
<td *ngIf="entry.type !== 'TIME'" colspan="3" class="empty"></td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<select class="number" [(ngModel)]="entry.fuzzySeconds" (ngModelChange)="set(schedule, entry, 'fuzzySeconds', entry.fuzzySeconds)">
|
|
||||||
<option [ngValue]="0">Keine</option>
|
|
||||||
<option [ngValue]="60">1 Minute</option>
|
|
||||||
<option [ngValue]="300">5 Minuten</option>
|
|
||||||
<option [ngValue]="600">10 Minuten</option>
|
|
||||||
<option [ngValue]="1800">30 Minuten</option>
|
|
||||||
<option [ngValue]="3600">1 Stunde</option>
|
|
||||||
<option [ngValue]="7200">2 Stunden</option>
|
|
||||||
<option [ngValue]="10800">3 Stunden</option>
|
|
||||||
<option [ngValue]="21600">6 Stunden</option>
|
|
||||||
<option [ngValue]="43200">12 Stunden</option>
|
|
||||||
<option [ngValue]="86400">1 Tag</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<ng-container *ngIf="entry.nextClearTimestamp">
|
|
||||||
<td class="number first" [class.empty]="entry.fuzzySeconds > 0">{{entry.nextClearTimestamp.dayName}}</td>
|
|
||||||
<td class="number middle" [class.empty]="entry.fuzzySeconds > 0">: </td>
|
|
||||||
<td class="number last" [class.empty]="entry.fuzzySeconds > 0">{{entry.nextClearTimestamp.timeString}}</td>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="!entry.nextClearTimestamp">
|
|
||||||
<td class="empty first"></td>
|
|
||||||
<td class="empty middle"></td>
|
|
||||||
<td class="empty last"></td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="entry.nextFuzzyTimestamp && entry.fuzzySeconds > 0">
|
|
||||||
<td class="number first">{{entry.nextFuzzyTimestamp.dayName}}</td>
|
|
||||||
<td class="number middle">: </td>
|
|
||||||
<td class="number last">{{entry.nextFuzzyTimestamp.timeString}}</td>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="!entry.nextFuzzyTimestamp || entry.fuzzySeconds <= 0">
|
|
||||||
<td class="empty first"></td>
|
|
||||||
<td class="empty middle"></td>
|
|
||||||
<td class="empty last"></td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</ng-container>
|
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
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 {ScheduleEntry} from "../../api/schedule/entry/ScheduleEntry";
|
|
||||||
import {ScheduleEntryService} from "../../api/schedule/entry/schedule-entry.service";
|
|
||||||
import {faCheck, faTimes} from '@fortawesome/free-solid-svg-icons';
|
import {faCheck, faTimes} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -20,7 +18,6 @@ export class ScheduleListComponent implements OnInit {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly scheduleService: ScheduleService,
|
readonly scheduleService: ScheduleService,
|
||||||
readonly scheduleEntryService: ScheduleEntryService,
|
|
||||||
) {
|
) {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
@ -29,12 +26,8 @@ export class ScheduleListComponent implements OnInit {
|
|||||||
this.scheduleService.findAll(schedules => this.schedules = schedules, Schedule.compareName);
|
this.scheduleService.findAll(schedules => this.schedules = schedules, Schedule.compareName);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(schedule: Schedule, entry: ScheduleEntry, key: string, value: any): void {
|
set(schedule: Schedule, key: string, value: any): void {
|
||||||
if (entry) {
|
this.scheduleService.set(schedule, key, value, schedule => this.updateSchedule(schedule));
|
||||||
this.scheduleEntryService.set(entry, key, value, entry => this.updateEntry(schedule, entry));
|
|
||||||
} else {
|
|
||||||
this.scheduleService.set(schedule, key, value, schedule => this.updateSchedule(schedule));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateSchedule(schedule: Schedule): void {
|
private updateSchedule(schedule: Schedule): void {
|
||||||
@ -47,14 +40,4 @@ export class ScheduleListComponent implements OnInit {
|
|||||||
this.schedules = this.schedules.sort(Schedule.compareName)
|
this.schedules = this.schedules.sort(Schedule.compareName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateEntry(schedule: Schedule, entry: ScheduleEntry): void {
|
|
||||||
const index: number = schedule.entries.findIndex(s => s.id === entry.id);
|
|
||||||
if (index < 0) {
|
|
||||||
schedule.entries.push(entry);
|
|
||||||
} else {
|
|
||||||
schedule.entries[index] = entry;
|
|
||||||
}
|
|
||||||
schedule.entries = schedule.entries.sort(ScheduleEntry.compareId)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
125
src/main/angular/src/app/pages/schedule/schedule.component.html
Normal file
125
src/main/angular/src/app/pages/schedule/schedule.component.html
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<ng-container *ngIf="dataService.schedule">
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<fa-icon *ngIf="value" [icon]="faCheck"></fa-icon>
|
||||||
|
<fa-icon *ngIf="!value" [icon]="faTimes"></fa-icon>
|
||||||
|
</td>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr class="header">
|
||||||
|
<ng-container *ngTemplateOutlet="boolean;context:{schedule: dataService.schedule, value: dataService.schedule.enabled, key:'enabled'}"></ng-container>
|
||||||
|
<td colspan="20">
|
||||||
|
<app-edit-field [initial]="dataService.schedule.name" (valueChange)="set(null, 'name', $event)"></app-edit-field>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr [class.disabled]="!dataService.schedule.enabled">
|
||||||
|
<th> </th>
|
||||||
|
<th>Mo</th>
|
||||||
|
<th>Di</th>
|
||||||
|
<th>Mi</th>
|
||||||
|
<th>Do</th>
|
||||||
|
<th>Fr</th>
|
||||||
|
<th>Sa</th>
|
||||||
|
<th>So</th>
|
||||||
|
<th>Typ</th>
|
||||||
|
<th>Sonnenstand</th>
|
||||||
|
<th colspan="3">Uhrzeit</th>
|
||||||
|
<th>Unschärfe</th>
|
||||||
|
<th colspan="6">Nächste Ausführung</th>
|
||||||
|
</tr>
|
||||||
|
<tr *ngFor="let entry of dataService.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.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.wednesday, key:'wednesday'}"></ng-container>
|
||||||
|
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.thursday, key:'thursday'}"></ng-container>
|
||||||
|
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.friday, key:'friday'}"></ng-container>
|
||||||
|
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.saturday, key:'saturday'}"></ng-container>
|
||||||
|
<ng-container *ngTemplateOutlet="boolean;context:{entry: entry, value: entry.sunday, key:'sunday'}"></ng-container>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<select [(ngModel)]="entry.type" (ngModelChange)="set(entry, 'type', entry.type)">
|
||||||
|
<option value="TIME">Uhrzeit</option>
|
||||||
|
<option value="SUNRISE">Sonnenaufgang</option>
|
||||||
|
<option value="SUNSET">Sonnenuntergang</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<ng-container *ngIf="entry.type === 'SUNRISE' || entry.type === 'SUNSET'">
|
||||||
|
<td>
|
||||||
|
<select class="number" [(ngModel)]="entry.zenith" (ngModelChange)="set(entry, 'zenith', entry.zenith)">
|
||||||
|
<option value="90.8333">
|
||||||
|
<ng-container *ngIf="entry.type === 'SUNRISE'">Sonnenaufgang</ng-container>
|
||||||
|
<ng-container *ngIf="entry.type === 'SUNSET'">Sonnenuntergang</ng-container>
|
||||||
|
[ 90°]
|
||||||
|
</option>
|
||||||
|
<option value="93">[ 93°]</option>
|
||||||
|
<option value="96">Bürgerliche Dämmerung [ 96°]</option>
|
||||||
|
<option value="99">[ 99°]</option>
|
||||||
|
<option value="102">Nautische Dämmerung [102°]</option>
|
||||||
|
<option value="105">[105°]</option>
|
||||||
|
<option value="108">Astronomische Dämmerung [108°]</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<td *ngIf="entry.type !== 'SUNRISE' && entry.type !== 'SUNSET'" class="empty"></td>
|
||||||
|
|
||||||
|
<ng-container *ngIf="entry.type === 'TIME'">
|
||||||
|
<td class="first">
|
||||||
|
<select class="number" [(ngModel)]="entry.hour" (ngModelChange)="set(entry, 'hour', entry.hour)">
|
||||||
|
<option *ngFor="let _ of [].constructor(60); let value = index" [ngValue]="value">{{value}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td class="middle">:</td>
|
||||||
|
<td class="last">
|
||||||
|
<select class="number" [(ngModel)]="entry.minute" (ngModelChange)="set(entry, 'minute', entry.minute)">
|
||||||
|
<option *ngFor="let _ of [].constructor(60); let value = index" [ngValue]="value">{{value | number:'2.0'}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<td *ngIf="entry.type !== 'TIME'" colspan="3" class="empty"></td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<select class="number" [(ngModel)]="entry.fuzzySeconds" (ngModelChange)="set(entry, 'fuzzySeconds', entry.fuzzySeconds)">
|
||||||
|
<option [ngValue]="0">Keine</option>
|
||||||
|
<option [ngValue]="60">1 Minute</option>
|
||||||
|
<option [ngValue]="300">5 Minuten</option>
|
||||||
|
<option [ngValue]="600">10 Minuten</option>
|
||||||
|
<option [ngValue]="1800">30 Minuten</option>
|
||||||
|
<option [ngValue]="3600">1 Stunde</option>
|
||||||
|
<option [ngValue]="7200">2 Stunden</option>
|
||||||
|
<option [ngValue]="10800">3 Stunden</option>
|
||||||
|
<option [ngValue]="21600">6 Stunden</option>
|
||||||
|
<option [ngValue]="43200">12 Stunden</option>
|
||||||
|
<option [ngValue]="86400">1 Tag</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<ng-container *ngIf="entry.nextClearTimestamp">
|
||||||
|
<td class="number first" [class.empty]="entry.fuzzySeconds > 0">{{entry.nextClearTimestamp.dayName}}</td>
|
||||||
|
<td class="number middle" [class.empty]="entry.fuzzySeconds > 0">: </td>
|
||||||
|
<td class="number last" [class.empty]="entry.fuzzySeconds > 0">{{entry.nextClearTimestamp.timeString}}</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="!entry.nextClearTimestamp">
|
||||||
|
<td class="empty first"></td>
|
||||||
|
<td class="empty middle"></td>
|
||||||
|
<td class="empty last"></td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="entry.nextFuzzyTimestamp && entry.fuzzySeconds > 0">
|
||||||
|
<td class="number first">{{entry.nextFuzzyTimestamp.dayName}}</td>
|
||||||
|
<td class="number middle">: </td>
|
||||||
|
<td class="number last">{{entry.nextFuzzyTimestamp.timeString}}</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="!entry.nextFuzzyTimestamp || entry.fuzzySeconds <= 0">
|
||||||
|
<td class="empty first"></td>
|
||||||
|
<td class="empty middle"></td>
|
||||||
|
<td class="empty last"></td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
select {
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.blank {
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.header {
|
||||||
|
|
||||||
|
th:not(:first-child), td:not(:first-child) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
text-align: center;
|
||||||
|
color: gray;
|
||||||
|
background-color: #DDDDDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boolean {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.true {
|
||||||
|
background-color: palegreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.false {
|
||||||
|
background-color: indianred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first {
|
||||||
|
border-right-width: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minute {
|
||||||
|
border-right-width: 0;
|
||||||
|
border-left-width: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.last {
|
||||||
|
border-left-width: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middle {
|
||||||
|
border-right-width: 0;
|
||||||
|
border-left-width: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
* {
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {ScheduleComponent} from './schedule.component';
|
||||||
|
|
||||||
|
describe('ScheduleComponent', () => {
|
||||||
|
let component: ScheduleComponent;
|
||||||
|
let fixture: ComponentFixture<ScheduleComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ScheduleComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ScheduleComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {ScheduleService} from "../../api/schedule/schedule.service";
|
||||||
|
import {Schedule} from "../../api/schedule/Schedule";
|
||||||
|
import {ScheduleEntry} from "../../api/schedule/entry/ScheduleEntry";
|
||||||
|
import {ScheduleEntryService} from "../../api/schedule/entry/schedule-entry.service";
|
||||||
|
import {faCheck, faTimes} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import {ActivatedRoute} from "@angular/router";
|
||||||
|
import {DataService} from "../../data.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-schedule',
|
||||||
|
templateUrl: './schedule.component.html',
|
||||||
|
styleUrls: ['./schedule.component.less']
|
||||||
|
})
|
||||||
|
export class ScheduleComponent implements OnInit {
|
||||||
|
|
||||||
|
readonly faCheck = faCheck;
|
||||||
|
readonly faTimes = faTimes;
|
||||||
|
readonly Schedule = Schedule;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly activatedRoute: ActivatedRoute,
|
||||||
|
readonly scheduleService: ScheduleService,
|
||||||
|
readonly scheduleEntryService: ScheduleEntryService,
|
||||||
|
readonly dataService: DataService,
|
||||||
|
) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.dataService.schedule = undefined;
|
||||||
|
this.activatedRoute.params.subscribe(params => this.scheduleService.findById(params.id, schedule => this.setSchedule(schedule)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private setSchedule(schedule: Schedule): void {
|
||||||
|
this.dataService.schedule = schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(entry: ScheduleEntry | null, key: string, value: any): void {
|
||||||
|
if (entry) {
|
||||||
|
this.scheduleEntryService.set(entry, key, value, entry => this.updateEntry(entry));
|
||||||
|
} else {
|
||||||
|
if (this.dataService.schedule) {
|
||||||
|
this.scheduleService.set(this.dataService.schedule, key, value, schedule => this.dataService.schedule = schedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEntry(entry: ScheduleEntry): void {
|
||||||
|
if (!this.dataService.schedule) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const index: number = this.dataService.schedule.entries.findIndex(s => s.id === entry.id);
|
||||||
|
if (index < 0) {
|
||||||
|
this.dataService.schedule.entries.push(entry);
|
||||||
|
} else {
|
||||||
|
this.dataService.schedule.entries[index] = entry;
|
||||||
|
}
|
||||||
|
this.dataService.schedule.entries = this.dataService.schedule.entries.sort(ScheduleEntry.compareId)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -20,6 +20,11 @@ public class ScheduleController {
|
|||||||
return scheduleReadService.findAllDtos();
|
return scheduleReadService.findAllDtos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("findById/{id}")
|
||||||
|
public ScheduleDto findById(@PathVariable final long id) {
|
||||||
|
return scheduleReadService.getDtoById(id);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("findAllNext")
|
@GetMapping("findAllNext")
|
||||||
public List<ScheduleNextExecutionDto> findAllNext() {
|
public List<ScheduleNextExecutionDto> findAllNext() {
|
||||||
return scheduleReadService.findAllNextExecutionDtos();
|
return scheduleReadService.findAllNextExecutionDtos();
|
||||||
@ -27,7 +32,12 @@ public class ScheduleController {
|
|||||||
|
|
||||||
@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.setEnabled(id, enabled);
|
return scheduleWriteService.set(id, Schedule::setEnabled, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("set/{id}/name")
|
||||||
|
public ScheduleDto setName(@PathVariable final long id, @RequestBody final String name) {
|
||||||
|
return scheduleWriteService.set(id, Schedule::setName, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,4 +50,8 @@ public class ScheduleReadService {
|
|||||||
return scheduleRepository.getByEntriesContaining(entry);
|
return scheduleRepository.getByEntriesContaining(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ScheduleDto getDtoById(final long id) {
|
||||||
|
return scheduleMapper.toDto(get(id));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -19,9 +20,9 @@ public class ScheduleWriteService {
|
|||||||
|
|
||||||
private final ScheduleMapper scheduleMapper;
|
private final ScheduleMapper scheduleMapper;
|
||||||
|
|
||||||
public ScheduleDto setEnabled(final long id, final boolean enabled) {
|
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.get(id);
|
||||||
schedule.setEnabled(enabled);
|
setter.accept(schedule, value);
|
||||||
scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now());
|
scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now());
|
||||||
return scheduleMapper.toDto(schedule);
|
return scheduleMapper.toDto(schedule);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user