1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-07-05 00:48:51 +02:00
Files
pigallery2/src/frontend/app/ui/settings/workflow/workflow.component.ts
2023-01-05 19:50:12 +01:00

291 lines
8.0 KiB
TypeScript

import {Component, OnDestroy, OnInit, QueryList, ViewChildren} from '@angular/core';
import {forwardRef} from '../../../../../../node_modules/@angular/core';
import {ModalDirective} from 'ngx-bootstrap/modal';
import {
AfterJobTrigger,
JobScheduleDTO,
JobScheduleDTOUtils,
JobTriggerType,
ScheduledJobTrigger
} from '../../../../../common/entities/job/JobScheduleDTO';
import {ScheduledJobsService} from '../scheduled-jobs.service';
import {BackendtextService} from '../../../model/backendtext.service';
import {SettingsService} from '../settings.service';
import {ConfigTemplateEntry} from '../../../../../common/entities/job/JobDTO';
import {JobProgressDTO, JobProgressStates} from '../../../../../common/entities/job/JobProgressDTO';
import {
AfterJobTriggerConfig,
JobScheduleConfig,
NeverJobTriggerConfig,
PeriodicJobTriggerConfig,
ScheduledJobTriggerConfig
} from '../../../../../common/config/private/PrivateConfig';
import {
ControlValueAccessor,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator
} from '../../../../../../node_modules/@angular/forms';
@Component({
selector: 'app-settings-workflow',
templateUrl: './workflow.component.html',
styleUrls: ['./workflow.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => WorkflowComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => WorkflowComponent),
multi: true,
},
],
})
export class WorkflowComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy {
public schedules: JobScheduleConfig[] = [];
@ViewChildren('jobModal') public jobModalQL: QueryList<ModalDirective>;
public disableButtons = false;
public JobTriggerTypeMap: { key: number; value: string }[];
public JobTriggerType = JobTriggerType;
public periods: string[] = [];
public showDetails: { [key: string]: boolean } = {};
public JobProgressStates = JobProgressStates;
public newSchedule: JobScheduleDTO = {
name: '',
config: null,
jobName: '',
trigger: {
type: JobTriggerType.never,
},
allowParallelRun: false,
};
error: string;
constructor(
public settingsService: SettingsService,
public jobsService: ScheduledJobsService,
public backendTextService: BackendtextService,
) {
this.JobTriggerTypeMap = [
{key: JobTriggerType.after, value: $localize`after`},
{key: JobTriggerType.never, value: $localize`never`},
{key: JobTriggerType.periodic, value: $localize`periodic`},
{key: JobTriggerType.scheduled, value: $localize`scheduled`},
];
this.periods = [
$localize`Monday`, // 0
$localize`Tuesday`, // 1
$localize`Wednesday`, // 2
$localize`Thursday`,
$localize`Friday`,
$localize`Saturday`,
$localize`Sunday`,
$localize`day`,
]; // 7
}
atTimeLocal(atTime: number): Date {
if (!atTime) {
return null;
}
const d = new Date();
d.setUTCHours(Math.floor(atTime / 60));
d.setUTCMinutes(Math.floor(atTime % 60));
return d;
}
ngOnInit(): void {
this.jobsService.subscribeToProgress();
this.jobsService.getAvailableJobs().catch(console.error);
}
ngOnDestroy(): void {
this.jobsService.unsubscribeFromProgress();
}
remove(schedule: JobScheduleDTO): void {
this.schedules.splice(
this.schedules.indexOf(schedule),
1
);
}
jobTypeChanged(schedule: JobScheduleDTO): void {
const job = this.jobsService.availableJobs.value.find(
(t) => t.Name === schedule.jobName
);
schedule.config = schedule.config || {};
if (job.ConfigTemplate) {
job.ConfigTemplate.forEach(
(ct) => (schedule.config[ct.id] = ct.defaultValue)
);
}
}
jobTriggerTypeChanged(
triggerType: JobTriggerType,
schedule: JobScheduleDTO
): void {
switch (triggerType) {
case JobTriggerType.never:
schedule.trigger = new NeverJobTriggerConfig();
break;
case JobTriggerType.scheduled:
schedule.trigger = new ScheduledJobTriggerConfig();
(schedule.trigger as unknown as ScheduledJobTrigger).time = Date.now();
break;
case JobTriggerType.periodic:
schedule.trigger = new PeriodicJobTriggerConfig();
schedule.trigger.periodicity = 7;
schedule.trigger.atTime = 0;
break;
case JobTriggerType.after:
schedule.trigger = new AfterJobTriggerConfig();
if (!(schedule.trigger as unknown as AfterJobTrigger).afterScheduleName && this.schedules.length > 1) {
(schedule.trigger as unknown as AfterJobTrigger).afterScheduleName = this.schedules.find(s => s.name !== schedule.name).name;
}
break;
}
}
setNumberArray(configElement: any, id: string, value: string): void {
value = value.replace(new RegExp(',', 'g'), ';');
value = value.replace(new RegExp(' ', 'g'), ';');
configElement[id] = value
.split(';')
.map((s: string) => parseInt(s, 10))
.filter((i: number) => !isNaN(i) && i > 0);
}
getNumberArray(configElement: Record<string, number[]>, id: string): string {
return configElement[id] ? configElement[id].join('; ') : '';
}
public shouldIdent(curr: JobScheduleDTO, prev: JobScheduleDTO): boolean {
return (
curr &&
curr.trigger.type === JobTriggerType.after &&
prev &&
prev.name === curr.trigger.afterScheduleName
);
}
public sortedSchedules(): JobScheduleDTO[] {
return (this.schedules || [])
.slice()
.sort((a: JobScheduleDTO, b: JobScheduleDTO) => {
return (
this.getNextRunningDate(a, this.schedules) -
this.getNextRunningDate(b, this.schedules)
);
});
}
prepareNewJob(): void {
const jobName = this.jobsService.availableJobs.value[0].Name;
this.newSchedule = new JobScheduleConfig('new job',
jobName,
new NeverJobTriggerConfig());
// setup job specific config
const job = this.jobsService.availableJobs.value.find(
(t) => t.Name === jobName
);
this.newSchedule.config = this.newSchedule.config || {};
if (job.ConfigTemplate) {
job.ConfigTemplate.forEach(
(ct) => (this.newSchedule.config[ct.id] = ct.defaultValue)
);
}
this.jobModalQL.first.show();
}
addNewJob(): void {
// make unique job name
const jobName = this.newSchedule.jobName;
const count = this.schedules.filter(
(s: JobScheduleDTO) => s.jobName === jobName
).length;
this.newSchedule.name =
count === 0
? jobName
: this.backendTextService.getJobName(jobName) + ' ' + (count + 1);
this.schedules.push(this.newSchedule);
this.jobModalQL.first.hide();
this.onChange(null); // trigger change detection after adding new job
}
getProgress(schedule: JobScheduleDTO): JobProgressDTO {
return this.jobsService.getProgress(schedule);
}
private getNextRunningDate(
sch: JobScheduleDTO,
list: JobScheduleDTO[],
depth = 0
): number {
if (depth > list.length) {
return 0;
}
if (sch.trigger.type === JobTriggerType.never) {
return (
list
.map((s) => s.name)
.sort()
.indexOf(sch.name) * -1
);
}
if (sch.trigger.type === JobTriggerType.after) {
const parent = list.find(
(s) => s.name === (sch.trigger as AfterJobTrigger).afterScheduleName
);
if (parent) {
return this.getNextRunningDate(parent, list, depth + 1) + 0.001;
}
}
const d = JobScheduleDTOUtils.getNextRunningDate(new Date(), sch);
return d !== null ? d.getTime() : 0;
}
validate(): ValidationErrors {
return null;
}
public onChange = (value: unknown): void => {
// empty
};
public onTouched = (): void => {
// empty
};
public writeValue(obj: JobScheduleConfig[]): void {
this.schedules = obj;
}
public registerOnChange(fn: (v: JobScheduleConfig[]) => void): void {
this.onChange = () => fn(this.schedules);
}
public registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
}