From 3e060e2b8d715c15d5d1a2e2f279607048608d0d Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Sun, 29 Dec 2019 16:43:43 +0100 Subject: [PATCH] improving job settings ui --- src/backend/model/jobs/JobProgressManager.ts | 43 +++++---- src/backend/model/jobs/jobs/JobProgress.ts | 9 +- src/common/entities/job/JobProgressDTO.ts | 8 +- .../jobs/jobs.settings.component.html | 10 +-- .../settings/jobs/jobs.settings.component.ts | 14 ++- .../job-progress.settings.component.css | 5 ++ .../job-progress.settings.component.html | 90 +++++++++++++++---- .../job-progress.settings.component.ts | 20 ++++- .../app/ui/settings/scheduled-jobs.service.ts | 21 +++-- 9 files changed, 162 insertions(+), 58 deletions(-) diff --git a/src/backend/model/jobs/JobProgressManager.ts b/src/backend/model/jobs/JobProgressManager.ts index 70a57fe6..cd665cec 100644 --- a/src/backend/model/jobs/JobProgressManager.ts +++ b/src/backend/model/jobs/JobProgressManager.ts @@ -5,7 +5,14 @@ import {Config} from '../../../common/config/private/Config'; import {JobProgressDTO, JobProgressStates} from '../../../common/entities/job/JobProgressDTO'; export class JobProgressManager { - db: { [key: string]: { progress: JobProgressDTO, timestamp: number } } = {}; + private static readonly VERSION = 1; + db: { + version: number, + db: { [key: string]: { progress: JobProgressDTO, timestamp: number } } + } = { + version: JobProgressManager.VERSION, + db: {} + }; private readonly dbPath: string; private timer: NodeJS.Timeout = null; @@ -16,9 +23,9 @@ export class JobProgressManager { get Running(): { [key: string]: JobProgressDTO } { const m: { [key: string]: JobProgressDTO } = {}; - for (const key of Object.keys(this.db)) { - if (this.db[key].progress.state === JobProgressStates.running) { - m[key] = this.db[key].progress; + for (const key of Object.keys(this.db.db)) { + if (this.db.db[key].progress.state === JobProgressStates.running) { + m[key] = this.db.db[key].progress; m[key].time.end = Date.now(); } } @@ -27,16 +34,16 @@ export class JobProgressManager { get Finished(): { [key: string]: JobProgressDTO } { const m: { [key: string]: JobProgressDTO } = {}; - for (const key of Object.keys(this.db)) { - if (this.db[key].progress.state !== JobProgressStates.running) { - m[key] = this.db[key].progress; + for (const key of Object.keys(this.db.db)) { + if (this.db.db[key].progress.state !== JobProgressStates.running) { + m[key] = this.db.db[key].progress; } } return m; } onJobProgressUpdate(progress: JobProgressDTO) { - this.db[progress.HashName] = {progress: progress, timestamp: Date.now()}; + this.db.db[progress.HashName] = {progress: progress, timestamp: Date.now()}; this.delayedSave(); } @@ -47,21 +54,25 @@ export class JobProgressManager { return; } const data = await fsp.readFile(this.dbPath, 'utf8'); - this.db = JSON.parse(data); + const db = JSON.parse(data); + if (db.version !== JobProgressManager.VERSION) { + return; + } + this.db = db; - while (Object.keys(this.db).length > Config.Server.Jobs.maxSavedProgress) { + while (Object.keys(this.db.db).length > Config.Server.Jobs.maxSavedProgress) { let min: string = null; - for (const key of Object.keys(this.db)) { - if (min === null || this.db[min].timestamp > this.db[key].timestamp) { + for (const key of Object.keys(this.db.db)) { + if (min === null || this.db.db[min].timestamp > this.db.db[key].timestamp) { min = key; } } - delete this.db[min]; + delete this.db.db[min]; } - for (const key of Object.keys(this.db)) { - if (this.db[key].progress.state === JobProgressStates.running) { - this.db[key].progress.state = JobProgressStates.interrupted; + for (const key of Object.keys(this.db.db)) { + if (this.db.db[key].progress.state === JobProgressStates.running) { + this.db.db[key].progress.state = JobProgressStates.interrupted; } } } diff --git a/src/backend/model/jobs/jobs/JobProgress.ts b/src/backend/model/jobs/jobs/JobProgress.ts index 3f71007b..f521208c 100644 --- a/src/backend/model/jobs/jobs/JobProgress.ts +++ b/src/backend/model/jobs/jobs/JobProgress.ts @@ -1,4 +1,4 @@ -import {JobProgressDTO, JobProgressStates} from '../../../../common/entities/job/JobProgressDTO'; +import {JobProgressDTO, JobProgressLogDTO, JobProgressStates} from '../../../../common/entities/job/JobProgressDTO'; export class JobProgress { @@ -12,7 +12,8 @@ export class JobProgress { start: Date.now(), end: null, }; - private logs: string[] = []; + private logCounter = 0; + private logs: { id: number, timestamp: string, comment: string }[] = []; constructor(public readonly HashName: string) { @@ -72,7 +73,7 @@ export class JobProgress { this.onChange(this); } - get Logs(): string[] { + get Logs(): JobProgressLogDTO[] { return this.logs; } @@ -83,7 +84,7 @@ export class JobProgress { while (this.logs.length > 10) { this.logs.shift(); } - this.logs.push(log); + this.logs.push({id: this.logCounter++, timestamp: (new Date()).toISOString(), comment: log}); this.onChange(this); } diff --git a/src/common/entities/job/JobProgressDTO.ts b/src/common/entities/job/JobProgressDTO.ts index e03fde5c..d889f1e5 100644 --- a/src/common/entities/job/JobProgressDTO.ts +++ b/src/common/entities/job/JobProgressDTO.ts @@ -3,6 +3,12 @@ export enum JobProgressStates { } +export interface JobProgressLogDTO { + id: number; + timestamp: string; + comment: string; +} + export interface JobProgressDTO { HashName: string; steps: { @@ -11,7 +17,7 @@ export interface JobProgressDTO { skipped: number, }; state: JobProgressStates; - logs: string[]; + logs: JobProgressLogDTO[]; time: { start: number, end: number diff --git a/src/frontend/app/ui/settings/jobs/jobs.settings.component.html b/src/frontend/app/ui/settings/jobs/jobs.settings.component.html index 4eb9e68a..014340b8 100644 --- a/src/frontend/app/ui/settings/jobs/jobs.settings.component.html +++ b/src/frontend/app/ui/settings/jobs/jobs.settings.component.html @@ -36,7 +36,7 @@ @@ -129,7 +129,7 @@ @@ -181,7 +181,8 @@ - ';' separated integers. + ';' separated integers. + {{backendtextService.get(configEntry.description)}} @@ -194,8 +195,7 @@ + [progress]="getProgress(schedule) || getLastRun(schedule)"> diff --git a/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts b/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts index 9fb52f68..e64321dc 100644 --- a/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts +++ b/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts @@ -17,10 +17,10 @@ import { } from '../../../../../common/entities/job/JobScheduleDTO'; import {Utils} from '../../../../../common/Utils'; import {ServerConfig} from '../../../../../common/config/private/IPrivateConfig'; -import {ConfigTemplateEntry, JobDTO} from '../../../../../common/entities/job/JobDTO'; +import {ConfigTemplateEntry} from '../../../../../common/entities/job/JobDTO'; import {Job} from '../../../../../backend/model/jobs/jobs/Job'; import {ModalDirective} from 'ngx-bootstrap/modal'; -import {JobProgressStates} from '../../../../../common/entities/job/JobProgressDTO'; +import {JobProgressDTO, JobProgressStates} from '../../../../../common/entities/job/JobProgressDTO'; import {BackendtextService} from '../../../model/backendtext.service'; @Component({ @@ -181,8 +181,6 @@ export class JobsSettingsComponent extends SettingsComponent +
Last run:
-
+
- {{lastRun.time.start | date:'medium'}} - {{lastRun.time.end | date:'mediumTime'}} + {{progress.time.start | date:'medium'}} - {{progress.time.end | date:'mediumTime'}}
-
+
- {{lastRun.steps.processed}}+{{lastRun.steps.skipped}}/{{lastRun.steps.all}} + {{progress.steps.processed}}+{{progress.steps.skipped}}/{{progress.steps.all}}
-
+
- {{JobProgressStates[lastRun.state]}} + {{JobProgressStates[progress.state]}}
-
+
- - + +
-
{{TimeElapsed| duration:':'}}
-
{{TimeAll| duration:':'}}
+
{{TimeElapsed| duration:':'}}
+
{{TimeAll| duration:':'}}
+ + + + + + + diff --git a/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.ts b/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.ts index e8a4e351..f1775994 100644 --- a/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.ts +++ b/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.ts @@ -1,6 +1,7 @@ -import {Component, Input, OnChanges, OnDestroy} from '@angular/core'; +import {Component, Input, OnChanges, OnDestroy, TemplateRef} from '@angular/core'; import {JobProgressDTO, JobProgressStates} from '../../../../../../common/entities/job/JobProgressDTO'; import {Subscription, timer} from 'rxjs'; +import {BsModalRef, BsModalService} from 'ngx-bootstrap'; @Component({ selector: 'app-settings-job-progress', @@ -10,12 +11,16 @@ import {Subscription, timer} from 'rxjs'; export class JobProgressComponent implements OnDestroy, OnChanges { @Input() progress: JobProgressDTO; - @Input() lastRun: JobProgressDTO; JobProgressStates = JobProgressStates; timeCurrentCopy: number; + modalRef: BsModalRef; private timerSub: Subscription; - constructor() { + constructor(private modalService: BsModalService) { + } + + get Name(): string { + return this.progress.HashName; } get TimeAll(): number { @@ -26,6 +31,10 @@ export class JobProgressComponent implements OnDestroy, OnChanges { (this.progress.steps.processed + this.progress.steps.skipped) * this.progress.steps.all; } + get IsRunning() { + return this.progress.state === JobProgressStates.running || this.progress.state === JobProgressStates.canceled; + } + get TimeLeft(): number { if (!this.progress) { return 0; @@ -40,6 +49,11 @@ export class JobProgressComponent implements OnDestroy, OnChanges { return (this.timeCurrentCopy - this.progress.time.start); } + + openModal(template: TemplateRef) { + this.modalRef = this.modalService.show(template, {class: 'modal-lg'}); + } + ngOnChanges(): void { if (!this.progress) { return; diff --git a/src/frontend/app/ui/settings/scheduled-jobs.service.ts b/src/frontend/app/ui/settings/scheduled-jobs.service.ts index 1922384c..4cf01370 100644 --- a/src/frontend/app/ui/settings/scheduled-jobs.service.ts +++ b/src/frontend/app/ui/settings/scheduled-jobs.service.ts @@ -1,14 +1,16 @@ import {EventEmitter, Injectable} from '@angular/core'; import {BehaviorSubject} from 'rxjs'; -import {JobProgressDTO, JobProgressStates} from '../../../../common/entities/job/JobProgressDTO'; +import {JobProgressDTO} from '../../../../common/entities/job/JobProgressDTO'; import {NetworkService} from '../../model/network/network.service'; +import {JobScheduleDTO} from '../../../../common/entities/job/JobScheduleDTO'; +import {JobDTO} from '../../../../common/entities/job/JobDTO'; @Injectable() export class ScheduledJobsService { public progress: BehaviorSubject<{ [key: string]: JobProgressDTO }>; - public lastRuns: BehaviorSubject<{ [key: string]: { [key: string]: JobProgressStates } }>; + public lastRuns: BehaviorSubject<{ [key: string]: JobProgressDTO }>; public onJobFinish: EventEmitter = new EventEmitter(); timer: number = null; private subscribers = 0; @@ -18,6 +20,13 @@ export class ScheduledJobsService { this.lastRuns = new BehaviorSubject({}); } + getProgress(schedule: JobScheduleDTO): JobProgressDTO { + return this.progress.value[JobDTO.getHashName(schedule.jobName, schedule.config)]; + } + + getLastRun(schedule: JobScheduleDTO): JobProgressDTO { + return this.lastRuns.value[JobDTO.getHashName(schedule.jobName, schedule.config)]; + } subscribeToProgress(): void { this.incSubscribers(); @@ -28,7 +37,7 @@ export class ScheduledJobsService { } public async forceUpdate(): Promise { - return await this.getProgress(); + return await this.loadProgress(); } public async start(id: string, config?: any): Promise { @@ -41,10 +50,10 @@ export class ScheduledJobsService { this.forceUpdate(); } - protected async getProgress(): Promise { + protected async loadProgress(): Promise { const prevPrg = this.progress.value; this.progress.next(await this._networkService.getJson<{ [key: string]: JobProgressDTO }>('/admin/jobs/scheduled/progress')); - this.lastRuns.next(await this._networkService.getJson<{ [key: string]: { [key: string]: JobProgressStates } }>('/admin/jobs/scheduled/lastRun')); + this.lastRuns.next(await this._networkService.getJson<{ [key: string]: JobProgressDTO }>('/admin/jobs/scheduled/lastRun')); for (const prg in prevPrg) { if (!this.progress.value.hasOwnProperty(prg)) { this.onJobFinish.emit(prg); @@ -65,7 +74,7 @@ export class ScheduledJobsService { this.timer = null; this.getProgressPeriodically(); }, repeatTime); - this.getProgress().catch(console.error); + this.loadProgress().catch(console.error); } private incSubscribers() {