mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
Add info panel to jobs #587
This commit is contained in:
parent
71c9df2d26
commit
07328a7ae2
@ -142,6 +142,7 @@ import {
|
||||
ionHammerOutline,
|
||||
ionImageOutline,
|
||||
ionImagesOutline,
|
||||
ionInformationCircleOutline,
|
||||
ionInformationOutline,
|
||||
ionLinkOutline,
|
||||
ionLocationOutline,
|
||||
@ -204,7 +205,7 @@ export class MyHammerConfig extends HammerGestureConfig {
|
||||
|
||||
export class CustomUrlSerializer implements UrlSerializer {
|
||||
private defaultUrlSerializer: DefaultUrlSerializer =
|
||||
new DefaultUrlSerializer();
|
||||
new DefaultUrlSerializer();
|
||||
|
||||
parse(url: string): UrlTree {
|
||||
// Encode parentheses
|
||||
@ -215,9 +216,9 @@ export class CustomUrlSerializer implements UrlSerializer {
|
||||
|
||||
serialize(tree: UrlTree): string {
|
||||
return this.defaultUrlSerializer
|
||||
.serialize(tree)
|
||||
.replace(/%28/g, '(')
|
||||
.replace(/%29/g, ')');
|
||||
.serialize(tree)
|
||||
.replace(/%28/g, '(')
|
||||
.replace(/%29/g, ')');
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,6 +246,7 @@ Marker.prototype.options.icon = MarkerFactory.defIcon;
|
||||
ionTextOutline, ionFolderOutline, ionDocumentOutline, ionImageOutline,
|
||||
ionPricetagOutline, ionLocationOutline,
|
||||
ionSunnyOutline, ionMoonOutline, ionVideocamOutline,
|
||||
ionInformationCircleOutline,
|
||||
ionInformationOutline, ionContractOutline, ionExpandOutline, ionCloseOutline,
|
||||
ionTimerOutline,
|
||||
ionPlayOutline, ionPauseOutline, ionVolumeMediumOutline, ionVolumeMuteOutline,
|
||||
|
@ -1,6 +1,8 @@
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import {BackendtextService} from './backendtext.service';
|
||||
import {backendTexts} from '../../../common/BackendTexts';
|
||||
import {Utils} from '../../../common/Utils';
|
||||
import {DefaultsJobs} from '../../../common/entities/job/JobDTO';
|
||||
|
||||
describe('BackendTextService', () => {
|
||||
beforeEach(() => {
|
||||
@ -10,18 +12,31 @@ describe('BackendTextService', () => {
|
||||
});
|
||||
|
||||
it('should have valid text for all keys', inject(
|
||||
[BackendtextService],
|
||||
(backendTextService: BackendtextService) => {
|
||||
const getTexts = (obj: any) => {
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (typeof obj[key] === 'object') {
|
||||
getTexts(obj[key]);
|
||||
continue;
|
||||
}
|
||||
expect(backendTextService.get(obj[key])).not.toEqual(null, 'Error for key: ' + obj[key] + ', ' + key);
|
||||
[BackendtextService],
|
||||
(backendTextService: BackendtextService) => {
|
||||
const getTexts = (obj: any) => {
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (typeof obj[key] === 'object') {
|
||||
getTexts(obj[key]);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
getTexts(backendTexts);
|
||||
expect(backendTextService.get(obj[key])).not.toEqual(null, 'Error for key: ' + obj[key] + ', ' + key);
|
||||
}
|
||||
};
|
||||
getTexts(backendTexts);
|
||||
}
|
||||
));
|
||||
|
||||
it('should have valid text for all jobs', inject(
|
||||
[BackendtextService],
|
||||
(backendTextService: BackendtextService) => {
|
||||
|
||||
const allJobs = Utils.enumToArray(DefaultsJobs);
|
||||
|
||||
for (let i = 0; i < allJobs.length; ++i){
|
||||
expect(backendTextService.getJobName(allJobs[i].value)).not.toEqual(null, 'Cant find job name: ' + allJobs[i].value);
|
||||
expect(backendTextService.getJobDescription(allJobs[i].value)).not.toEqual(null, 'Cant find job name: ' + allJobs[i].value);
|
||||
}
|
||||
}
|
||||
));
|
||||
});
|
||||
|
@ -60,13 +60,51 @@ export class BackendtextService {
|
||||
case DefaultsJobs['Temp Folder Cleaning']:
|
||||
return $localize`Temp folder cleaning`;
|
||||
case DefaultsJobs['Album Cover Filling']:
|
||||
return $localize`Album cover filling`;
|
||||
return $localize`Cover filling`;
|
||||
case DefaultsJobs['Album Cover Reset']:
|
||||
return $localize`Album cover reset`;
|
||||
return $localize`Cover reset`;
|
||||
case DefaultsJobs['GPX Compression']:
|
||||
return $localize`GPX compression`;
|
||||
case DefaultsJobs['Delete Compressed GPX']:
|
||||
return $localize`Delete Compressed GPX`;
|
||||
case DefaultsJobs['Top Pick Sending']:
|
||||
return $localize`Top Pick Sending`;
|
||||
default:
|
||||
return DefaultsJobs[job as DefaultsJobs];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public getJobDescription(job: DefaultsJobs | string): string {
|
||||
if (typeof job === 'string') {
|
||||
job = DefaultsJobs[job as any];
|
||||
}
|
||||
switch (job as DefaultsJobs) {
|
||||
case DefaultsJobs.Indexing:
|
||||
return $localize`Scans the whole gallery from disk and indexes it to the DB.`;
|
||||
case DefaultsJobs['Gallery Reset']:
|
||||
return $localize`Deletes all directories, photos and videos from the DB.`;
|
||||
case DefaultsJobs['Album Reset']:
|
||||
return $localize`Removes all albums from the DB`;
|
||||
case DefaultsJobs['Thumbnail Generation']:
|
||||
return $localize`Generates thumbnails from all media files and stores them in the tmp folder.`;
|
||||
case DefaultsJobs['Photo Converting']:
|
||||
return $localize`Generates high res photos from all media files and stores them in the tmp folder.`;
|
||||
case DefaultsJobs['Video Converting']:
|
||||
return $localize`Transcodes all videos and stores them in the tmp folder.`;
|
||||
case DefaultsJobs['Temp Folder Cleaning']:
|
||||
return $localize`Removes unnecessary files from the tmp folder.`;
|
||||
case DefaultsJobs['Album Cover Filling']:
|
||||
return $localize`Updates the cover photo of all albums (both directories and saved searches) and and faces.`;
|
||||
case DefaultsJobs['Album Cover Reset']:
|
||||
return $localize`Deletes the cover photo of all albums and faces`;
|
||||
case DefaultsJobs['GPX Compression']:
|
||||
return $localize`Compresses all gpx files`;
|
||||
case DefaultsJobs['Delete Compressed GPX']:
|
||||
return $localize`Deletes all compressed GPX files`;
|
||||
case DefaultsJobs['Top Pick Sending']:
|
||||
return $localize`Gets the top photos of the selected search queries and sends them over email. You need to set up the SMTP server connection send e-mails.`;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@
|
||||
let-confPath="confPath">
|
||||
<div class="alert alert-secondary" role="alert"
|
||||
*ngIf="rStates.description && settingsService.configStyle == ConfigStyle.full">
|
||||
{{rStates.description}}
|
||||
<ng-icon size="1.3em" name="ionInformationCircleOutline"></ng-icon> {{rStates.description}}
|
||||
<a *ngIf="rStates.tags?.githubIssue"
|
||||
[href]="'https://github.com/bpatrik/pigallery2/issues/'+rStates.tags?.githubIssue">
|
||||
<ng-container i18n>See</ng-container>
|
||||
@ -130,7 +130,7 @@
|
||||
<ng-container *ngFor="let job of uiJob; let i = index">
|
||||
<div class="alert alert-secondary" role="alert"
|
||||
*ngIf="job.description && settingsService.configStyle == ConfigStyle.full">
|
||||
{{job.description}}
|
||||
<ng-icon size="1.3em" name="ionInformationCircleOutline"></ng-icon> {{job.description}}
|
||||
</div>
|
||||
<app-settings-job-button
|
||||
*ngIf="!job.relevant || job.relevant(settingsService.settings | async)"
|
||||
|
@ -40,6 +40,10 @@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-secondary" role="alert"
|
||||
*ngIf="settingsService.configStyle == ConfigStyle.full">
|
||||
<ng-icon size="1.3em" name="ionInformationCircleOutline"></ng-icon> {{getJobDescription(schedule.jobName)}}
|
||||
</div>
|
||||
<div class="mb-1 row">
|
||||
<label class="col-md-2 control-label" i18n>Job:</label>
|
||||
<div class="col-md-4">
|
||||
|
@ -70,9 +70,9 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
error: string;
|
||||
|
||||
constructor(
|
||||
public settingsService: SettingsService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
public backendTextService: BackendtextService,
|
||||
public settingsService: SettingsService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
public backendTextService: BackendtextService,
|
||||
) {
|
||||
this.JobTriggerTypeMap = [
|
||||
{key: JobTriggerType.after, value: $localize`after`},
|
||||
@ -116,27 +116,27 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
|
||||
remove(schedule: JobScheduleDTO): void {
|
||||
this.schedules.splice(
|
||||
this.schedules.indexOf(schedule),
|
||||
1
|
||||
this.schedules.indexOf(schedule),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
jobTypeChanged(schedule: JobScheduleDTO): void {
|
||||
const job = this.jobsService.availableJobs.value.find(
|
||||
(t) => t.Name === schedule.jobName
|
||||
(t) => t.Name === schedule.jobName
|
||||
);
|
||||
schedule.config = schedule.config || {};
|
||||
if (job.ConfigTemplate) {
|
||||
job.ConfigTemplate.forEach(
|
||||
(ct) => (schedule.config[ct.id] = ct.defaultValue)
|
||||
(ct) => (schedule.config[ct.id] = ct.defaultValue)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jobTriggerTypeChanged(
|
||||
triggerType: JobTriggerType,
|
||||
schedule: JobScheduleDTO
|
||||
triggerType: JobTriggerType,
|
||||
schedule: JobScheduleDTO
|
||||
): void {
|
||||
switch (triggerType) {
|
||||
case JobTriggerType.never:
|
||||
@ -166,7 +166,7 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
value = value.replace(new RegExp(',', 'g'), ';');
|
||||
value = value.replace(new RegExp(' ', 'g'), ';');
|
||||
configElement[id] = value
|
||||
.split(';').filter((i: string) => i != '');
|
||||
.split(';').filter((i: string) => i != '');
|
||||
}
|
||||
|
||||
getArray(configElement: Record<string, number[]>, id: string): string {
|
||||
@ -177,46 +177,46 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
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);
|
||||
.split(';')
|
||||
.map((s: string) => parseInt(s, 10))
|
||||
.filter((i: number) => !isNaN(i) && i > 0);
|
||||
}
|
||||
|
||||
|
||||
public shouldIdent(curr: JobScheduleDTO, prev: JobScheduleDTO): boolean {
|
||||
return (
|
||||
curr &&
|
||||
curr.trigger.type === JobTriggerType.after &&
|
||||
prev &&
|
||||
prev.name === curr.trigger.afterScheduleName
|
||||
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)
|
||||
);
|
||||
});
|
||||
.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());
|
||||
jobName,
|
||||
new NeverJobTriggerConfig());
|
||||
|
||||
// setup job specific config
|
||||
const job = this.jobsService.availableJobs.value.find(
|
||||
(t) => t.Name === jobName
|
||||
(t) => t.Name === jobName
|
||||
);
|
||||
this.newSchedule.config = this.newSchedule.config || {};
|
||||
if (job.ConfigTemplate) {
|
||||
job.ConfigTemplate.forEach(
|
||||
(ct) => (this.newSchedule.config[ct.id] = ct.defaultValue)
|
||||
(ct) => (this.newSchedule.config[ct.id] = ct.defaultValue)
|
||||
);
|
||||
}
|
||||
this.jobModalQL.first.show();
|
||||
@ -226,12 +226,12 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
// make unique job name
|
||||
const jobName = this.newSchedule.jobName;
|
||||
const count = this.schedules.filter(
|
||||
(s: JobScheduleDTO) => s.jobName === jobName
|
||||
(s: JobScheduleDTO) => s.jobName === jobName
|
||||
).length;
|
||||
this.newSchedule.name =
|
||||
count === 0
|
||||
? jobName
|
||||
: this.backendTextService.getJobName(jobName) + ' ' + (count + 1);
|
||||
count === 0
|
||||
? jobName
|
||||
: this.backendTextService.getJobName(jobName) + ' ' + (count + 1);
|
||||
this.schedules.push(this.newSchedule);
|
||||
|
||||
this.jobModalQL.first.hide();
|
||||
@ -243,24 +243,24 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
}
|
||||
|
||||
private getNextRunningDate(
|
||||
sch: JobScheduleDTO,
|
||||
list: JobScheduleDTO[],
|
||||
depth = 0
|
||||
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
|
||||
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
|
||||
(s) => s.name === (sch.trigger as AfterJobTrigger).afterScheduleName
|
||||
);
|
||||
if (parent) {
|
||||
return this.getNextRunningDate(parent, list, depth + 1) + 0.001;
|
||||
@ -282,6 +282,10 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
||||
// empty
|
||||
};
|
||||
|
||||
getJobDescription(jobName: string): string {
|
||||
return this.backendTextService.getJobDescription(jobName);
|
||||
}
|
||||
|
||||
public writeValue(obj: JobScheduleConfig[]): void {
|
||||
this.schedules = obj;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user