From ed2d5172bf401e0b327830dc0667c00ec60c291b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Thu, 28 Oct 2021 23:18:23 +0200 Subject: [PATCH] UI: splitted Schedule into list- and single-view --- src/main/angular/karma.conf.js | 40 +----- .../src/app/api/schedule/schedule.service.ts | 4 + .../angular/src/app/app-routing.module.ts | 2 + src/main/angular/src/app/app.component.html | 6 + src/main/angular/src/app/app.component.less | 4 + src/main/angular/src/app/app.module.ts | 2 + src/main/angular/src/app/data.service.ts | 11 ++ .../schedule-list.component.html | 135 ++---------------- .../schedule-list/schedule-list.component.ts | 21 +-- .../pages/schedule/schedule.component.html | 125 ++++++++++++++++ .../pages/schedule/schedule.component.less | 83 +++++++++++ .../pages/schedule/schedule.component.spec.ts | 25 ++++ .../app/pages/schedule/schedule.component.ts | 62 ++++++++ .../schedule/ScheduleController.java | 12 +- .../schedule/ScheduleReadService.java | 4 + .../schedule/ScheduleWriteService.java | 5 +- 16 files changed, 358 insertions(+), 183 deletions(-) create mode 100644 src/main/angular/src/app/pages/schedule/schedule.component.html create mode 100644 src/main/angular/src/app/pages/schedule/schedule.component.less create mode 100644 src/main/angular/src/app/pages/schedule/schedule.component.spec.ts create mode 100644 src/main/angular/src/app/pages/schedule/schedule.component.ts diff --git a/src/main/angular/karma.conf.js b/src/main/angular/karma.conf.js index 069d9fd..e77e607 100644 --- a/src/main/angular/karma.conf.js +++ b/src/main/angular/karma.conf.js @@ -2,43 +2,5 @@ // https://karma-runner.github.io/1.0/config/configuration-file.html module.exports = function (config) { - 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 - }); + config.set(); }; diff --git a/src/main/angular/src/app/api/schedule/schedule.service.ts b/src/main/angular/src/app/api/schedule/schedule.service.ts index f25751d..0cbaaac 100644 --- a/src/main/angular/src/app/api/schedule/schedule.service.ts +++ b/src/main/angular/src/app/api/schedule/schedule.service.ts @@ -21,4 +21,8 @@ export class ScheduleService { 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); + } + } diff --git a/src/main/angular/src/app/app-routing.module.ts b/src/main/angular/src/app/app-routing.module.ts index f85a9aa..bf7d9c3 100644 --- a/src/main/angular/src/app/app-routing.module.ts +++ b/src/main/angular/src/app/app-routing.module.ts @@ -1,8 +1,10 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {ScheduleListComponent} from "./pages/schedule-list/schedule-list.component"; +import {ScheduleComponent} from "./pages/schedule/schedule.component"; const routes: Routes = [ + {path: 'Schedule', component: ScheduleComponent}, {path: 'ScheduleList', component: ScheduleListComponent}, {path: '**', redirectTo: '/ScheduleList'}, ]; diff --git a/src/main/angular/src/app/app.component.html b/src/main/angular/src/app/app.component.html index c2c6df5..a8b1f0d 100644 --- a/src/main/angular/src/app/app.component.html +++ b/src/main/angular/src/app/app.component.html @@ -1,7 +1,13 @@
diff --git a/src/main/angular/src/app/app.component.less b/src/main/angular/src/app/app.component.less index 432091f..f4bbbdb 100644 --- a/src/main/angular/src/app/app.component.less +++ b/src/main/angular/src/app/app.component.less @@ -7,6 +7,10 @@ border-right: 1px solid black; } + .breadcrumb { + background-color: lightgray; + } + .itemActive { background-color: lightblue; } diff --git a/src/main/angular/src/app/app.module.ts b/src/main/angular/src/app/app.module.ts index 3094896..b9a730f 100644 --- a/src/main/angular/src/app/app.module.ts +++ b/src/main/angular/src/app/app.module.ts @@ -9,11 +9,13 @@ import {EditFieldComponent} from './shared/edit-field/edit-field.component'; import {ScheduleListComponent} from './pages/schedule-list/schedule-list.component'; import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; import {NumberComponent} from './shared/number/number.component'; +import {ScheduleComponent} from "./pages/schedule/schedule.component"; @NgModule({ declarations: [ AppComponent, EditFieldComponent, + ScheduleComponent, ScheduleListComponent, NumberComponent, ], diff --git a/src/main/angular/src/app/data.service.ts b/src/main/angular/src/app/data.service.ts index 4e43f91..b02899d 100644 --- a/src/main/angular/src/app/data.service.ts +++ b/src/main/angular/src/app/data.service.ts @@ -1,10 +1,21 @@ import {Injectable} from '@angular/core'; +import {Schedule} from "./api/schedule/Schedule"; @Injectable({ providedIn: 'root' }) export class DataService { + private _schedule?: Schedule; + + get schedule(): Schedule | undefined { + return this._schedule; + } + + set schedule(schedule: Schedule | undefined) { + this._schedule = schedule; + } + constructor() { } diff --git a/src/main/angular/src/app/pages/schedule-list/schedule-list.component.html b/src/main/angular/src/app/pages/schedule-list/schedule-list.component.html index 8948903..0e7db62 100644 --- a/src/main/angular/src/app/pages/schedule-list/schedule-list.component.html +++ b/src/main/angular/src/app/pages/schedule-list/schedule-list.component.html @@ -1,124 +1,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + +
 
{{schedule.name}}
 MoDiMiDoFrSaSoTypSonnenstandUhrzeitUnschärfeNächste Ausführung
- - - - - - : - - - - {{entry.nextClearTimestamp.dayName}}{{entry.nextClearTimestamp.timeString}}{{entry.nextFuzzyTimestamp.dayName}}{{entry.nextFuzzyTimestamp.timeString}}
 Bezeichnung
+ + + + {{schedule.name}} +
diff --git a/src/main/angular/src/app/pages/schedule-list/schedule-list.component.ts b/src/main/angular/src/app/pages/schedule-list/schedule-list.component.ts index 7f59fac..a1cf64c 100644 --- a/src/main/angular/src/app/pages/schedule-list/schedule-list.component.ts +++ b/src/main/angular/src/app/pages/schedule-list/schedule-list.component.ts @@ -1,8 +1,6 @@ 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'; @Component({ @@ -20,7 +18,6 @@ export class ScheduleListComponent implements OnInit { constructor( readonly scheduleService: ScheduleService, - readonly scheduleEntryService: ScheduleEntryService, ) { // nothing } @@ -29,12 +26,8 @@ export class ScheduleListComponent implements OnInit { this.scheduleService.findAll(schedules => this.schedules = schedules, Schedule.compareName); } - set(schedule: Schedule, entry: ScheduleEntry, key: string, value: any): void { - if (entry) { - this.scheduleEntryService.set(entry, key, value, entry => this.updateEntry(schedule, entry)); - } else { - this.scheduleService.set(schedule, key, value, schedule => this.updateSchedule(schedule)); - } + set(schedule: Schedule, key: string, value: any): void { + this.scheduleService.set(schedule, key, value, schedule => this.updateSchedule(schedule)); } private updateSchedule(schedule: Schedule): void { @@ -47,14 +40,4 @@ export class ScheduleListComponent implements OnInit { 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) - } - } diff --git a/src/main/angular/src/app/pages/schedule/schedule.component.html b/src/main/angular/src/app/pages/schedule/schedule.component.html new file mode 100644 index 0000000..04976b6 --- /dev/null +++ b/src/main/angular/src/app/pages/schedule/schedule.component.html @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
 MoDiMiDoFrSaSoTypSonnenstandUhrzeitUnschärfeNächste Ausführung
+ + + + + + : + + + + {{entry.nextClearTimestamp.dayName}}{{entry.nextClearTimestamp.timeString}}{{entry.nextFuzzyTimestamp.dayName}}{{entry.nextFuzzyTimestamp.timeString}}
+ +
diff --git a/src/main/angular/src/app/pages/schedule/schedule.component.less b/src/main/angular/src/app/pages/schedule/schedule.component.less new file mode 100644 index 0000000..da84fc9 --- /dev/null +++ b/src/main/angular/src/app/pages/schedule/schedule.component.less @@ -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; + } +} diff --git a/src/main/angular/src/app/pages/schedule/schedule.component.spec.ts b/src/main/angular/src/app/pages/schedule/schedule.component.spec.ts new file mode 100644 index 0000000..c841428 --- /dev/null +++ b/src/main/angular/src/app/pages/schedule/schedule.component.spec.ts @@ -0,0 +1,25 @@ +import {ComponentFixture, TestBed} from '@angular/core/testing'; + +import {ScheduleComponent} from './schedule.component'; + +describe('ScheduleComponent', () => { + let component: ScheduleComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ScheduleComponent] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ScheduleComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/main/angular/src/app/pages/schedule/schedule.component.ts b/src/main/angular/src/app/pages/schedule/schedule.component.ts new file mode 100644 index 0000000..7d7ad82 --- /dev/null +++ b/src/main/angular/src/app/pages/schedule/schedule.component.ts @@ -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) + } + +} diff --git a/src/main/java/de/ph87/homeautomation/schedule/ScheduleController.java b/src/main/java/de/ph87/homeautomation/schedule/ScheduleController.java index 62e5a84..0648337 100644 --- a/src/main/java/de/ph87/homeautomation/schedule/ScheduleController.java +++ b/src/main/java/de/ph87/homeautomation/schedule/ScheduleController.java @@ -20,6 +20,11 @@ public class ScheduleController { return scheduleReadService.findAllDtos(); } + @GetMapping("findById/{id}") + public ScheduleDto findById(@PathVariable final long id) { + return scheduleReadService.getDtoById(id); + } + @GetMapping("findAllNext") public List findAllNext() { return scheduleReadService.findAllNextExecutionDtos(); @@ -27,7 +32,12 @@ public class ScheduleController { @PostMapping("set/{id}/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); } } diff --git a/src/main/java/de/ph87/homeautomation/schedule/ScheduleReadService.java b/src/main/java/de/ph87/homeautomation/schedule/ScheduleReadService.java index f1df13f..105c33a 100644 --- a/src/main/java/de/ph87/homeautomation/schedule/ScheduleReadService.java +++ b/src/main/java/de/ph87/homeautomation/schedule/ScheduleReadService.java @@ -50,4 +50,8 @@ public class ScheduleReadService { return scheduleRepository.getByEntriesContaining(entry); } + public ScheduleDto getDtoById(final long id) { + return scheduleMapper.toDto(get(id)); + } + } diff --git a/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java b/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java index 0460532..1dffbfc 100644 --- a/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java +++ b/src/main/java/de/ph87/homeautomation/schedule/ScheduleWriteService.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.ZonedDateTime; +import java.util.function.BiConsumer; @Slf4j @Service @@ -19,9 +20,9 @@ public class ScheduleWriteService { private final ScheduleMapper scheduleMapper; - public ScheduleDto setEnabled(final long id, final boolean enabled) { + public ScheduleDto set(final long id, final BiConsumer setter, final T value) { final Schedule schedule = scheduleReadService.get(id); - schedule.setEnabled(enabled); + setter.accept(schedule, value); scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now()); return scheduleMapper.toDto(schedule); }