You've already forked pigallery2
mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-07-07 00:57:28 +02:00
Adding job schedules to config #569
This commit is contained in:
294
src/frontend/app/ui/settings/workflow/workflow.component.ts
Normal file
294
src/frontend/app/ui/settings/workflow/workflow.component.ts
Normal file
@ -0,0 +1,294 @@
|
||||
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,
|
||||
PeriodicJobTrigger,
|
||||
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 {
|
||||
const d = new Date();
|
||||
d.setUTCHours(Math.floor(atTime / 60));
|
||||
d.setUTCMinutes(Math.floor(atTime % 60));
|
||||
return d;
|
||||
}
|
||||
|
||||
getConfigTemplate(JobName: string): ConfigTemplateEntry[] {
|
||||
const job = this.settingsService.availableJobs.value.find(
|
||||
(t) => t.Name === JobName
|
||||
);
|
||||
if (job && job.ConfigTemplate && job.ConfigTemplate.length > 0) {
|
||||
return job.ConfigTemplate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.jobsService.subscribeToProgress();
|
||||
this.settingsService.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.settingsService.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();
|
||||
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.settingsService.availableJobs.value[0].Name;
|
||||
this.newSchedule = new JobScheduleConfig('new job',
|
||||
jobName,
|
||||
new NeverJobTriggerConfig());
|
||||
|
||||
// setup job specific config
|
||||
const job = this.settingsService.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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user