mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-02-05 13:25:08 +02:00
Improving config UI #569
This commit is contained in:
parent
36d4641e9d
commit
875d120df8
@ -1,14 +1,10 @@
|
|||||||
import {
|
import {ConfigTemplateEntry, DefaultsJobs,} from '../../../../common/entities/job/JobDTO';
|
||||||
ConfigTemplateEntry,
|
|
||||||
DefaultsJobs,
|
|
||||||
} from '../../../../common/entities/job/JobDTO';
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import {Job} from './Job';
|
import {Job} from './Job';
|
||||||
import {ProjectPath} from '../../../ProjectPath';
|
import {ProjectPath} from '../../../ProjectPath';
|
||||||
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
||||||
import {VideoProcessing} from '../../fileprocessing/VideoProcessing';
|
import {VideoProcessing} from '../../fileprocessing/VideoProcessing';
|
||||||
import {DiskMangerWorker} from '../../threading/DiskMangerWorker';
|
|
||||||
import {GPXProcessing} from '../../fileprocessing/GPXProcessing';
|
import {GPXProcessing} from '../../fileprocessing/GPXProcessing';
|
||||||
|
|
||||||
export class TempFolderCleaningJob extends Job {
|
export class TempFolderCleaningJob extends Job {
|
||||||
|
@ -331,8 +331,9 @@ export class ServerGPXCompressingConfig extends ClientGPXCompressingConfig {
|
|||||||
{
|
{
|
||||||
name: $localize`Min distance`,
|
name: $localize`Min distance`,
|
||||||
priority: ConfigPriority.underTheHood,
|
priority: ConfigPriority.underTheHood,
|
||||||
|
unit: 'm',
|
||||||
uiDisabled: (sc: ServerGPXCompressingConfig, c: ServerConfig) => !c.Map.enabled || !sc.enabled || !c.MetaFile.gpx
|
uiDisabled: (sc: ServerGPXCompressingConfig, c: ServerConfig) => !c.Map.enabled || !sc.enabled || !c.MetaFile.gpx
|
||||||
},
|
} as TAGS,
|
||||||
description: $localize`Filters out entry that are closer than this in meters.`
|
description: $localize`Filters out entry that are closer than this in meters.`
|
||||||
})
|
})
|
||||||
minDistance: number = 5;
|
minDistance: number = 5;
|
||||||
@ -356,8 +357,12 @@ export class ServerMetaFileConfig extends ClientMetaFileConfig {
|
|||||||
tags:
|
tags:
|
||||||
{
|
{
|
||||||
name: $localize`GPX compression`,
|
name: $localize`GPX compression`,
|
||||||
priority: ConfigPriority.advanced
|
priority: ConfigPriority.advanced,
|
||||||
}
|
uiJob: [{
|
||||||
|
job: DefaultsJobs[DefaultsJobs['GPX Compression']],
|
||||||
|
relevant: (c) => c.MetaFile.GPXCompressing.enabled
|
||||||
|
}]
|
||||||
|
} as TAGS
|
||||||
})
|
})
|
||||||
GPXCompressing: ServerGPXCompressingConfig = new ServerGPXCompressingConfig();
|
GPXCompressing: ServerGPXCompressingConfig = new ServerGPXCompressingConfig();
|
||||||
}
|
}
|
||||||
@ -419,8 +424,8 @@ export class ServerIndexingConfig {
|
|||||||
{
|
{
|
||||||
name: $localize`Exclude File List`,
|
name: $localize`Exclude File List`,
|
||||||
priority: ConfigPriority.advanced,
|
priority: ConfigPriority.advanced,
|
||||||
uiOptional: true
|
uiOptional: true,
|
||||||
|
hint: $localize`.ignore;.pg2ignore`
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
description: $localize`Files that mark a folder to be excluded from indexing. Any folder that contains a file with this name will be excluded from indexing.`,
|
description: $localize`Files that mark a folder to be excluded from indexing. Any folder that contains a file with this name will be excluded from indexing.`,
|
||||||
})
|
})
|
||||||
@ -610,7 +615,7 @@ export class ServerJobConfig {
|
|||||||
DefaultsJobs[DefaultsJobs.Indexing],
|
DefaultsJobs[DefaultsJobs.Indexing],
|
||||||
DefaultsJobs[DefaultsJobs.Indexing],
|
DefaultsJobs[DefaultsJobs.Indexing],
|
||||||
new NeverJobTriggerConfig(),
|
new NeverJobTriggerConfig(),
|
||||||
{indexChangesOnly: true} // set config explicitly so it not undefined on the UI
|
{indexChangesOnly: true} // set config explicitly so it is not undefined on the UI
|
||||||
),
|
),
|
||||||
new JobScheduleConfig(
|
new JobScheduleConfig(
|
||||||
DefaultsJobs[DefaultsJobs['Preview Filling']],
|
DefaultsJobs[DefaultsJobs['Preview Filling']],
|
||||||
@ -681,7 +686,7 @@ export class VideoTranscodingConfig {
|
|||||||
tags:
|
tags:
|
||||||
{
|
{
|
||||||
name: $localize`FPS`,
|
name: $localize`FPS`,
|
||||||
priority: ConfigPriority.advanced,
|
priority: ConfigPriority.underTheHood,
|
||||||
uiOptions: [24, 25, 30, 48, 50, 60]
|
uiOptions: [24, 25, 30, 48, 50, 60]
|
||||||
},
|
},
|
||||||
description: $localize`Target frame per second (fps) of the output video will be scaled down this this.`
|
description: $localize`Target frame per second (fps) of the output video will be scaled down this this.`
|
||||||
@ -700,7 +705,7 @@ export class VideoTranscodingConfig {
|
|||||||
tags:
|
tags:
|
||||||
{
|
{
|
||||||
name: $localize`MP4 codec`,
|
name: $localize`MP4 codec`,
|
||||||
priority: ConfigPriority.advanced,
|
priority: ConfigPriority.underTheHood,
|
||||||
uiOptions: ['libx264', 'libx265'],
|
uiOptions: ['libx264', 'libx265'],
|
||||||
relevant: (c: any) => c.format === 'mp4'
|
relevant: (c: any) => c.format === 'mp4'
|
||||||
}
|
}
|
||||||
@ -710,7 +715,7 @@ export class VideoTranscodingConfig {
|
|||||||
tags:
|
tags:
|
||||||
{
|
{
|
||||||
name: $localize`Webm Codec`,
|
name: $localize`Webm Codec`,
|
||||||
priority: ConfigPriority.advanced,
|
priority: ConfigPriority.underTheHood,
|
||||||
uiOptions: ['libvpx', 'libvpx-vp9'],
|
uiOptions: ['libvpx', 'libvpx-vp9'],
|
||||||
relevant: (c: any) => c.format === 'webm'
|
relevant: (c: any) => c.format === 'webm'
|
||||||
}
|
}
|
||||||
@ -782,6 +787,8 @@ export class PhotoConvertingConfig extends ClientPhotoConvertingConfig {
|
|||||||
tags: {
|
tags: {
|
||||||
name: $localize`Resolution`,
|
name: $localize`Resolution`,
|
||||||
priority: ConfigPriority.advanced,
|
priority: ConfigPriority.advanced,
|
||||||
|
uiOptions: [720, 1080, 1440, 2160, 4320],
|
||||||
|
unit: 'px',
|
||||||
uiDisabled: (sc: PhotoConvertingConfig) =>
|
uiDisabled: (sc: PhotoConvertingConfig) =>
|
||||||
!sc.enabled
|
!sc.enabled
|
||||||
},
|
},
|
||||||
@ -867,23 +874,34 @@ export class ServerMediaConfig extends ClientMediaConfig {
|
|||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Video`,
|
name: $localize`Video`,
|
||||||
priority: ConfigPriority.advanced
|
priority: ConfigPriority.advanced,
|
||||||
},
|
uiJob: [
|
||||||
|
{
|
||||||
|
job: DefaultsJobs[DefaultsJobs['Video Converting']],
|
||||||
|
relevant: (c) => c.Media.Video.enabled
|
||||||
|
}]
|
||||||
|
} as TAGS,
|
||||||
description: $localize`Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or the @ffmpeg-installer/ffmpeg and @ffprobe-installer/ffprobe optional node packages need to be installed.`
|
description: $localize`Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or the @ffmpeg-installer/ffmpeg and @ffprobe-installer/ffprobe optional node packages need to be installed.`
|
||||||
})
|
})
|
||||||
Video: ServerVideoConfig = new ServerVideoConfig();
|
Video: ServerVideoConfig = new ServerVideoConfig();
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Photo`,
|
name: $localize`Photo`,
|
||||||
priority: ConfigPriority.advanced
|
priority: ConfigPriority.advanced,
|
||||||
}
|
uiJob: [
|
||||||
|
{
|
||||||
|
job: DefaultsJobs[DefaultsJobs['Photo Converting']],
|
||||||
|
relevant: (c) => c.Media.Photo.Converting.enabled
|
||||||
|
}]
|
||||||
|
} as TAGS
|
||||||
})
|
})
|
||||||
Photo: ServerPhotoConfig = new ServerPhotoConfig();
|
Photo: ServerPhotoConfig = new ServerPhotoConfig();
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Thumbnail`,
|
name: $localize`Thumbnail`,
|
||||||
priority: ConfigPriority.advanced
|
priority: ConfigPriority.advanced,
|
||||||
}
|
uiJob: [{job: DefaultsJobs[DefaultsJobs['Thumbnail Generation']]}]
|
||||||
|
} as TAGS
|
||||||
})
|
})
|
||||||
Thumbnail: ServerThumbnailConfig = new ServerThumbnailConfig();
|
Thumbnail: ServerThumbnailConfig = new ServerThumbnailConfig();
|
||||||
}
|
}
|
||||||
@ -965,34 +983,99 @@ export class ServerConfig extends ClientConfig {
|
|||||||
@ConfigProperty({volatile: true})
|
@ConfigProperty({volatile: true})
|
||||||
Environment: ServerEnvironmentConfig = new ServerEnvironmentConfig();
|
Environment: ServerEnvironmentConfig = new ServerEnvironmentConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Server`,
|
||||||
|
uiIcon: 'cog'
|
||||||
|
} as TAGS,
|
||||||
|
})
|
||||||
Server: ServerServiceConfig = new ServerServiceConfig();
|
Server: ServerServiceConfig = new ServerServiceConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Database`,
|
||||||
|
uiIcon: 'list'
|
||||||
|
} as TAGS
|
||||||
|
})
|
||||||
Database: ServerDataBaseConfig = new ServerDataBaseConfig();
|
Database: ServerDataBaseConfig = new ServerDataBaseConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Users`,
|
||||||
|
uiIcon: 'person'
|
||||||
|
} as TAGS,
|
||||||
|
})
|
||||||
Users: ServerUserConfig = new ServerUserConfig();
|
Users: ServerUserConfig = new ServerUserConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Indexing`,
|
||||||
|
uiIcon: 'pie-chart',
|
||||||
|
uiJob: [
|
||||||
|
{
|
||||||
|
job: DefaultsJobs[DefaultsJobs.Indexing],
|
||||||
|
description: $localize`If you add a new folder to your gallery, the site indexes it automatically. If you would like to trigger indexing manually, click index button. (Note: search only works among the indexed directories.)`
|
||||||
|
}, {
|
||||||
|
job: DefaultsJobs[DefaultsJobs['Database Reset']],
|
||||||
|
hideProgress: true
|
||||||
|
}]
|
||||||
|
} as TAGS
|
||||||
|
})
|
||||||
Indexing: ServerIndexingConfig = new ServerIndexingConfig();
|
Indexing: ServerIndexingConfig = new ServerIndexingConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Media`,
|
||||||
|
uiIcon: 'camera-slr'
|
||||||
|
} as TAGS,
|
||||||
|
})
|
||||||
Media: ServerMediaConfig = new ServerMediaConfig();
|
Media: ServerMediaConfig = new ServerMediaConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Meta file`,
|
||||||
|
uiIcon: 'file'
|
||||||
|
} as TAGS,
|
||||||
|
})
|
||||||
MetaFile: ServerMetaFileConfig = new ServerMetaFileConfig();
|
MetaFile: ServerMetaFileConfig = new ServerMetaFileConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Preview`,
|
||||||
|
uiIcon: 'image',
|
||||||
|
uiJob: [
|
||||||
|
{
|
||||||
|
job: DefaultsJobs[DefaultsJobs['Preview Filling']],
|
||||||
|
}, {
|
||||||
|
job: DefaultsJobs[DefaultsJobs['Preview Reset']],
|
||||||
|
hideProgress: true
|
||||||
|
}]
|
||||||
|
} as TAGS
|
||||||
|
})
|
||||||
Preview: ServerPreviewConfig = new ServerPreviewConfig();
|
Preview: ServerPreviewConfig = new ServerPreviewConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Sharing`,
|
||||||
|
uiIcon: 'share'
|
||||||
|
} as TAGS,
|
||||||
|
})
|
||||||
Sharing: ServerSharingConfig = new ServerSharingConfig();
|
Sharing: ServerSharingConfig = new ServerSharingConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Duplicates`,
|
||||||
|
uiIcon: 'layers'
|
||||||
|
} as TAGS
|
||||||
|
})
|
||||||
Duplicates: ServerDuplicatesConfig = new ServerDuplicatesConfig();
|
Duplicates: ServerDuplicatesConfig = new ServerDuplicatesConfig();
|
||||||
|
|
||||||
@ConfigProperty()
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Jobs`,
|
||||||
|
uiIcon: 'project'
|
||||||
|
} as TAGS
|
||||||
|
})
|
||||||
Jobs: ServerJobConfig = new ServerJobConfig();
|
Jobs: ServerJobConfig = new ServerJobConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,18 @@ export type TAGS = {
|
|||||||
secret?: boolean, // these config properties should never travel out of the server
|
secret?: boolean, // these config properties should never travel out of the server
|
||||||
experimental?: boolean, //is it a beta feature
|
experimental?: boolean, //is it a beta feature
|
||||||
unit?: string, // Unit info to display on UI
|
unit?: string, // Unit info to display on UI
|
||||||
|
uiIcon?: string,
|
||||||
uiType?: 'SearchQuery', // Hint for the UI about the type
|
uiType?: 'SearchQuery', // Hint for the UI about the type
|
||||||
uiOptions?: (string | number)[], //Hint for the UI about the recommended options
|
uiOptions?: (string | number)[], //Hint for the UI about the recommended options
|
||||||
uiAllowSpaces?: boolean
|
uiAllowSpaces?: boolean
|
||||||
uiOptional?: boolean; //makes the tag not "required"
|
uiOptional?: boolean; //makes the tag not "required"
|
||||||
uiDisabled?: (subConfig: any, config: ClientConfig) => boolean
|
uiDisabled?: (subConfig: any, config: ClientConfig) => boolean
|
||||||
|
uiJob?: {
|
||||||
|
job: string,
|
||||||
|
hideProgress: boolean,
|
||||||
|
relevant?: (c: ClientConfig) => boolean,
|
||||||
|
description: string
|
||||||
|
}[]
|
||||||
};
|
};
|
||||||
|
|
||||||
@SubConfigClass<TAGS>({tags: {client: true}})
|
@SubConfigClass<TAGS>({tags: {client: true}})
|
||||||
@ -278,7 +285,7 @@ export class ClientMapConfig {
|
|||||||
tags: {
|
tags: {
|
||||||
name: $localize`Max Preview Markers`,
|
name: $localize`Max Preview Markers`,
|
||||||
priority: ConfigPriority.underTheHood
|
priority: ConfigPriority.underTheHood
|
||||||
},
|
} as TAGS,
|
||||||
description: $localize`Maximum number of markers to be shown on the map preview on the gallery page.`,
|
description: $localize`Maximum number of markers to be shown on the map preview on the gallery page.`,
|
||||||
})
|
})
|
||||||
maxPreviewMarkers: number = 50;
|
maxPreviewMarkers: number = 50;
|
||||||
@ -289,7 +296,8 @@ export class ClientThumbnailConfig {
|
|||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt', max: 100,
|
type: 'unsignedInt', max: 100,
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Max Preview Markers`,
|
name: $localize`Map Icon size`,
|
||||||
|
unit: 'px',
|
||||||
priority: ConfigPriority.underTheHood
|
priority: ConfigPriority.underTheHood
|
||||||
},
|
},
|
||||||
description: $localize`Icon size (used on maps).`,
|
description: $localize`Icon size (used on maps).`,
|
||||||
@ -298,6 +306,7 @@ export class ClientThumbnailConfig {
|
|||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
type: 'unsignedInt', tags: {
|
type: 'unsignedInt', tags: {
|
||||||
name: $localize`Person thumbnail size`,
|
name: $localize`Person thumbnail size`,
|
||||||
|
unit: 'px',
|
||||||
priority: ConfigPriority.underTheHood
|
priority: ConfigPriority.underTheHood
|
||||||
},
|
},
|
||||||
description: $localize`Person (face) thumbnail size.`,
|
description: $localize`Person (face) thumbnail size.`,
|
||||||
@ -732,8 +741,9 @@ export class ClientServiceConfig {
|
|||||||
description: $localize`If you access the page form local network its good to know the public url for creating sharing link.`,
|
description: $localize`If you access the page form local network its good to know the public url for creating sharing link.`,
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Page public url`,
|
name: $localize`Page public url`,
|
||||||
|
hint: typeof window !== 'undefined' ? window?.origin : '',
|
||||||
uiOptional: true
|
uiOptional: true
|
||||||
}
|
} as TAGS
|
||||||
})
|
})
|
||||||
publicUrl: string = '';
|
publicUrl: string = '';
|
||||||
|
|
||||||
@ -804,72 +814,57 @@ export class ClientUserConfig {
|
|||||||
@SubConfigClass<TAGS>({tags: {client: true}})
|
@SubConfigClass<TAGS>({tags: {client: true}})
|
||||||
export class ClientConfig {
|
export class ClientConfig {
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty()
|
||||||
tags: {
|
|
||||||
name: $localize`Server`
|
|
||||||
} as TAGS,
|
|
||||||
})
|
|
||||||
Server: ClientServiceConfig = new ClientServiceConfig();
|
Server: ClientServiceConfig = new ClientServiceConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty()
|
||||||
tags: {
|
|
||||||
name: $localize`Users`
|
|
||||||
} as TAGS,
|
|
||||||
})
|
|
||||||
Users: ClientUserConfig = new ClientUserConfig();
|
Users: ClientUserConfig = new ClientUserConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Gallery`
|
name: $localize`Gallery`,
|
||||||
|
uiIcon: 'browser'
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
})
|
})
|
||||||
Gallery: ClientGalleryConfig = new ClientGalleryConfig();
|
Gallery: ClientGalleryConfig = new ClientGalleryConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty()
|
||||||
tags: {
|
|
||||||
name: $localize`Media`
|
|
||||||
} as TAGS,
|
|
||||||
})
|
|
||||||
Media: ClientMediaConfig = new ClientMediaConfig();
|
Media: ClientMediaConfig = new ClientMediaConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty()
|
||||||
tags: {
|
|
||||||
name: $localize`Meta file`
|
|
||||||
} as TAGS,
|
|
||||||
})
|
|
||||||
MetaFile: ClientMetaFileConfig = new ClientMetaFileConfig();
|
MetaFile: ClientMetaFileConfig = new ClientMetaFileConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Album`
|
name: $localize`Album`,
|
||||||
|
uiIcon: 'grid-two-up'
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
})
|
})
|
||||||
Album: ClientAlbumConfig = new ClientAlbumConfig();
|
Album: ClientAlbumConfig = new ClientAlbumConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Search`
|
name: $localize`Search`,
|
||||||
|
uiIcon: 'magnifying-glass'
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
})
|
})
|
||||||
Search: ClientSearchConfig = new ClientSearchConfig();
|
Search: ClientSearchConfig = new ClientSearchConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty()
|
||||||
tags: {
|
|
||||||
name: $localize`Sharing`
|
|
||||||
} as TAGS,
|
|
||||||
})
|
|
||||||
Sharing: ClientSharingConfig = new ClientSharingConfig();
|
Sharing: ClientSharingConfig = new ClientSharingConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Map`
|
name: $localize`Map`,
|
||||||
|
uiIcon: 'map-marker'
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
})
|
})
|
||||||
Map: ClientMapConfig = new ClientMapConfig();
|
Map: ClientMapConfig = new ClientMapConfig();
|
||||||
|
|
||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Faces`
|
name: $localize`Faces`,
|
||||||
|
uiIcon: 'people'
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
})
|
})
|
||||||
Faces: ClientFacesConfig = new ClientFacesConfig();
|
Faces: ClientFacesConfig = new ClientFacesConfig();
|
||||||
@ -877,6 +872,7 @@ export class ClientConfig {
|
|||||||
@ConfigProperty({
|
@ConfigProperty({
|
||||||
tags: {
|
tags: {
|
||||||
name: $localize`Random photo`,
|
name: $localize`Random photo`,
|
||||||
|
uiIcon: 'random',
|
||||||
githubIssue: 392
|
githubIssue: 392
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
description: $localize`This feature enables you to generate 'random photo' urls. That URL returns a photo random selected from your gallery. You can use the url with 3rd party application like random changing desktop background. Note: With the current implementation, random link also requires login.`
|
description: $localize`This feature enables you to generate 'random photo' urls. That URL returns a photo random selected from your gallery. You can use the url with 3rd party application like random changing desktop background. Note: With the current implementation, random link also requires login.`
|
||||||
|
@ -49,8 +49,7 @@ export interface RecursiveState extends ConfigState {
|
|||||||
@Directive()
|
@Directive()
|
||||||
export abstract class SettingsComponentDirective<
|
export abstract class SettingsComponentDirective<
|
||||||
T extends RecursiveState> implements OnInit, OnDestroy, ISettingsComponent {
|
T extends RecursiveState> implements OnInit, OnDestroy, ISettingsComponent {
|
||||||
|
public icon: string;
|
||||||
@Input() icon: string;
|
|
||||||
@Input() ConfigPath: string;
|
@Input() ConfigPath: string;
|
||||||
|
|
||||||
@ViewChild('settingsForm', {static: true})
|
@ViewChild('settingsForm', {static: true})
|
||||||
@ -72,7 +71,7 @@ export abstract class SettingsComponentDirective<
|
|||||||
private navigation: NavigationService,
|
private navigation: NavigationService,
|
||||||
public settingsService: AbstractSettingsService,
|
public settingsService: AbstractSettingsService,
|
||||||
protected notification: NotificationService,
|
protected notification: NotificationService,
|
||||||
protected globalSettingsService: SettingsService,
|
public globalSettingsService: SettingsService,
|
||||||
sliceFN?: (s: IWebConfigClassPrivate<TAGS> & WebConfig) => T
|
sliceFN?: (s: IWebConfigClassPrivate<TAGS> & WebConfig) => T
|
||||||
) {
|
) {
|
||||||
this.setSliceFN(sliceFN);
|
this.setSliceFN(sliceFN);
|
||||||
@ -108,6 +107,7 @@ export abstract class SettingsComponentDirective<
|
|||||||
if (state.volatile) {
|
if (state.volatile) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.tags &&
|
if (state.tags &&
|
||||||
((state.tags.relevant && !state.tags.relevant(parent.value))
|
((state.tags.relevant && !state.tags.relevant(parent.value))
|
||||||
|| state.tags.secret)) {
|
|| state.tags.secret)) {
|
||||||
@ -139,8 +139,7 @@ export abstract class SettingsComponentDirective<
|
|||||||
Utils.equalsFilter(state.value, state.default,
|
Utils.equalsFilter(state.value, state.default,
|
||||||
['__propPath', '__created', '__prototype', '__rootConfig']) &&
|
['__propPath', '__created', '__prototype', '__rootConfig']) &&
|
||||||
Utils.equalsFilter(state.original, state.default,
|
Utils.equalsFilter(state.original, state.default,
|
||||||
['__propPath', '__created', '__prototype', '__rootConfig'])
|
['__propPath', '__created', '__prototype', '__rootConfig']));
|
||||||
);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,6 +163,7 @@ export abstract class SettingsComponentDirective<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
instrument(this.states, null);
|
instrument(this.states, null);
|
||||||
|
this.icon = this.states.tags?.uiIcon;
|
||||||
};
|
};
|
||||||
|
|
||||||
onOptionChange = () => {
|
onOptionChange = () => {
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
|
|
||||||
|
|
||||||
<app-gallery-search-field
|
<app-gallery-search-field
|
||||||
*ngIf="Type === 'SearchQuery'"
|
*ngIf="Type === 'SearchQuery'"
|
||||||
[(ngModel)]="state.value"
|
[(ngModel)]="state.value"
|
||||||
@ -296,7 +294,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<small class="form-text text-muted" *ngIf="description">{{description}}
|
<small class="form-text text-muted" *ngIf="description">{{description}}
|
||||||
<span *ngIf="Type==='array' && (state.arrayType === 'string' || isNumberArray)" i18n>';' separated list.</span>
|
<span *ngIf="Type==='array' && (state.arrayType === 'string' || isNumberArray)" i18n>';' separated list.</span>
|
||||||
<a *ngIf="link" [href]="link">{{linkText || link}}</a>
|
<a *ngIf="state.tags?.githubIssue"
|
||||||
|
[href]="'https://github.com/bpatrik/pigallery2/issues/'+state.tags?.githubIssue">See
|
||||||
|
#{{state.tags?.githubIssue}}.</a>
|
||||||
</small>
|
</small>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,22 +1,9 @@
|
|||||||
import {Component, forwardRef, Input, OnChanges} from '@angular/core';
|
import {Component, forwardRef, Input, OnChanges} from '@angular/core';
|
||||||
import {
|
import {ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator,} from '@angular/forms';
|
||||||
ControlValueAccessor,
|
|
||||||
FormControl,
|
|
||||||
NG_VALIDATORS,
|
|
||||||
NG_VALUE_ACCESSOR,
|
|
||||||
ValidationErrors,
|
|
||||||
Validator,
|
|
||||||
} from '@angular/forms';
|
|
||||||
import {Utils} from '../../../../../../common/Utils';
|
import {Utils} from '../../../../../../common/Utils';
|
||||||
import {IConfigClass, propertyTypes} from 'typeconfig/common';
|
import {propertyTypes} from 'typeconfig/common';
|
||||||
import {SearchQueryParserService} from '../../../gallery/search/search-query-parser.service';
|
import {SearchQueryParserService} from '../../../gallery/search/search-query-parser.service';
|
||||||
import {
|
import {MapLayers, NavigationLinkConfig, NavigationLinkTypes, TAGS} from '../../../../../../common/config/public/ClientConfig';
|
||||||
ClientThumbnailConfig,
|
|
||||||
ConfigPriority,
|
|
||||||
MapLayers,
|
|
||||||
NavigationLinkConfig, NavigationLinkTypes,
|
|
||||||
TAGS
|
|
||||||
} from '../../../../../../common/config/public/ClientConfig';
|
|
||||||
import {SettingsService} from '../../settings.service';
|
import {SettingsService} from '../../settings.service';
|
||||||
import {WebConfig} from '../../../../../../common/config/private/WebConfig';
|
import {WebConfig} from '../../../../../../common/config/private/WebConfig';
|
||||||
import {JobScheduleConfig, UserConfig} from '../../../../../../common/config/private/PrivateConfig';
|
import {JobScheduleConfig, UserConfig} from '../../../../../../common/config/private/PrivateConfig';
|
||||||
@ -61,16 +48,12 @@ interface IState {
|
|||||||
})
|
})
|
||||||
export class SettingsEntryComponent
|
export class SettingsEntryComponent
|
||||||
implements ControlValueAccessor, Validator, OnChanges {
|
implements ControlValueAccessor, Validator, OnChanges {
|
||||||
@Input() defaultName: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
@Input() required: boolean;
|
required: boolean;
|
||||||
@Input() dockerWarning: boolean;
|
dockerWarning: boolean;
|
||||||
@Input() placeholder: string;
|
placeholder: string;
|
||||||
@Input() allowSpaces = false;
|
allowSpaces = false;
|
||||||
@Input() description: string;
|
description: string;
|
||||||
@Input() link: string;
|
|
||||||
@Input() linkText: string;
|
|
||||||
@Input() typeOverride: 'SearchQuery';
|
|
||||||
state: IState;
|
state: IState;
|
||||||
isNumberArray = false;
|
isNumberArray = false;
|
||||||
isNumber = false;
|
isNumber = false;
|
||||||
@ -89,13 +72,14 @@ export class SettingsEntryComponent
|
|||||||
if (this.Disabled) {
|
if (this.Disabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.isConfigArrayType) {
|
if (this.state.isConfigArrayType) {
|
||||||
for (let i = 0; i < this.state.value?.length; ++i) {
|
for (let i = 0; i < this.state.value?.length; ++i) {
|
||||||
for (const k of Object.keys(this.state.value[i].__state)) {
|
for (const k of Object.keys(this.state.value[i].__state)) {
|
||||||
if (!Utils.equalsFilter(
|
if (!Utils.equalsFilter(
|
||||||
this.state.value[i]?.__state[k]?.value,
|
this.state.value[i]?.__state[k]?.value,
|
||||||
this.state.default[i]?.__state[k]?.value,
|
this.state.default[i]?.__state[k]?.value,
|
||||||
['__propPath', '__created', '__prototype', '__rootConfig'])) {
|
['default', '__propPath', '__created', '__prototype', '__rootConfig'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,7 +112,7 @@ export class SettingsEntryComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
get Type(): string | object {
|
get Type(): string | object {
|
||||||
return this.typeOverride || this.state.tags?.uiType || this.state.type;
|
return this.state.tags?.uiType || this.state.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
get ArrayType(): string {
|
get ArrayType(): string {
|
||||||
@ -216,7 +200,7 @@ export class SettingsEntryComponent
|
|||||||
this.title = $localize`readonly` + ', ';
|
this.title = $localize`readonly` + ', ';
|
||||||
}
|
}
|
||||||
this.title += $localize`default value` + ': ' + this.defaultStr;
|
this.title += $localize`default value` + ': ' + this.defaultStr;
|
||||||
this.name = this.state?.tags?.name || this.defaultName;
|
this.name = this.state?.tags?.name;
|
||||||
if (this.name) {
|
if (this.name) {
|
||||||
this.idName =
|
this.idName =
|
||||||
this.GUID + this.name.toLowerCase().replace(new RegExp(' ', 'gm'), '-');
|
this.GUID + this.name.toLowerCase().replace(new RegExp(' ', 'gm'), '-');
|
||||||
@ -245,10 +229,6 @@ export class SettingsEntryComponent
|
|||||||
if (typeof this.dockerWarning === 'undefined') {
|
if (typeof this.dockerWarning === 'undefined') {
|
||||||
this.dockerWarning = this.state.tags.dockerSensitive && this.settingsService.settings.value.Environment.isDocker;
|
this.dockerWarning = this.state.tags.dockerSensitive && this.settingsService.settings.value.Environment.isDocker;
|
||||||
}
|
}
|
||||||
if (this.state.tags.githubIssue) {
|
|
||||||
this.link = `https://github.com/bpatrik/pigallery2/issues/` + this.state.tags.githubIssue;
|
|
||||||
this.linkText = $localize`See` + ' ' + this.state.tags.githubIssue;
|
|
||||||
}
|
|
||||||
this.name = this.name || this.state.tags.name;
|
this.name = this.name || this.state.tags.name;
|
||||||
this.allowSpaces = this.allowSpaces || this.state.tags.uiAllowSpaces;
|
this.allowSpaces = this.allowSpaces || this.state.tags.uiAllowSpaces;
|
||||||
this.required = this.required || !this.state.tags.uiOptional;
|
this.required = this.required || !this.state.tags.uiOptional;
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
:host {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
.panel-info {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
@ -24,9 +24,7 @@
|
|||||||
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
<ng-container *ngIf="states.value.enabled !== false">
|
<ng-container *ngIf="states.value.enabled !== false">
|
||||||
|
|
||||||
<div class="alert alert-secondary" role="alert" *ngIf="states.description">
|
|
||||||
{{states.description}}
|
|
||||||
</div>
|
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngTemplateOutlet="Recursion; context:{ rStates: states,skipEnabled:true,confPath:ConfigPath }"
|
*ngTemplateOutlet="Recursion; context:{ rStates: states,skipEnabled:true,confPath:ConfigPath }"
|
||||||
></ng-container>
|
></ng-container>
|
||||||
@ -48,16 +46,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #Recursion let-rStates="rStates" let-skipEnabled="skipEnabled" let-confPath="confPath">
|
<ng-template #Recursion let-rStates="rStates" let-skipEnabled="skipEnabled" let-confPath="confPath">
|
||||||
|
<div class="alert alert-secondary" role="alert" *ngIf="rStates.description">
|
||||||
|
{{rStates.description}}
|
||||||
|
</div>
|
||||||
<ng-container *ngFor="let ck of getKeys(rStates)">
|
<ng-container *ngFor="let ck of getKeys(rStates)">
|
||||||
<ng-container *ngIf="!(rStates.value.__state[ck].shouldHide && rStates.value.__state[ck].shouldHide())">
|
<ng-container *ngIf="!(rStates.value.__state[ck].shouldHide && rStates.value.__state[ck].shouldHide())">
|
||||||
<app-settings-entry
|
<app-settings-entry
|
||||||
*ngIf="(ck!=='enabled' || !skipEnabled) && !rStates.value.__state[ck].isConfigType"
|
*ngIf="(ck!=='enabled' || !skipEnabled) && !rStates.value.__state[ck].isConfigType"
|
||||||
[name]="confPath+'_'+ck"
|
[name]="confPath+'_'+ck"
|
||||||
[defaultName]="ck"
|
|
||||||
[ngModel]="rStates?.value.__state[ck]">
|
[ngModel]="rStates?.value.__state[ck]">
|
||||||
</app-settings-entry>
|
</app-settings-entry>
|
||||||
<ng-container *ngIf="rStates.value.__state[ck].isConfigType">
|
<ng-container *ngIf="rStates.value.__state[ck].isConfigType">
|
||||||
<div class="row">
|
<div class="row mt-2">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<h5>{{rStates?.value.__state[ck].tags?.name || ck}}</h5>
|
<h5>{{rStates?.value.__state[ck].tags?.name || ck}}</h5>
|
||||||
</div>
|
</div>
|
||||||
@ -66,9 +66,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<div class="alert alert-secondary" role="alert" *ngIf="rStates.value.__state[ck]?.description">
|
|
||||||
{{rStates.value.__state[ck]?.description}}
|
|
||||||
</div>
|
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
||||||
></ng-container>
|
></ng-container>
|
||||||
@ -76,6 +73,31 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<div *ngIf="rStates.tags?.uiJob">
|
||||||
|
<ng-container *ngFor="let job of rStates.tags?.uiJob; let i = index">
|
||||||
|
<div class="alert alert-secondary" role="alert" *ngIf="job.description">
|
||||||
|
{{job.description}}
|
||||||
|
</div>
|
||||||
|
<app-settings-job-button
|
||||||
|
*ngIf="!job.relevant || job.relevant(globalSettingsService.settings | async)"
|
||||||
|
class="mt-2 mb-1 mb-md-0 mt-md-0 float-left me-2"
|
||||||
|
[soloRun]="true"
|
||||||
|
(jobError)="error=$event"
|
||||||
|
[allowParallelRun]="false"
|
||||||
|
[danger]="i>0"
|
||||||
|
[jobName]="job.job"></app-settings-job-button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngFor="let job of rStates.tags?.uiJob">
|
||||||
|
<ng-container
|
||||||
|
*ngIf="getProgress(job.job) && !job.hideProgress && (!job.relevant || job.relevant(globalSettingsService.settings | async))">
|
||||||
|
<hr class="mt-1"/>
|
||||||
|
<app-settings-job-progress
|
||||||
|
class="d-block mb-2"
|
||||||
|
[progress]="getProgress(job.job)"></app-settings-job-progress>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {Component, Input, OnInit} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {AuthenticationService} from '../../../model/network/authentication.service';
|
import {AuthenticationService} from '../../../model/network/authentication.service';
|
||||||
import {NavigationService} from '../../../model/navigation.service';
|
import {NavigationService} from '../../../model/navigation.service';
|
||||||
import {NotificationService} from '../../../model/notification.service';
|
import {NotificationService} from '../../../model/notification.service';
|
||||||
@ -6,6 +6,9 @@ import {SettingsComponentDirective} from '../_abstract/abstract.settings.compone
|
|||||||
import {SettingsService} from '../settings.service';
|
import {SettingsService} from '../settings.service';
|
||||||
import {WebConfig} from '../../../../../common/config/private/WebConfig';
|
import {WebConfig} from '../../../../../common/config/private/WebConfig';
|
||||||
import {AbstractSettingsService} from '../_abstract/abstract.settings.service';
|
import {AbstractSettingsService} from '../_abstract/abstract.settings.service';
|
||||||
|
import {JobProgressDTO} from '../../../../../common/entities/job/JobProgressDTO';
|
||||||
|
import {JobDTOUtils} from '../../../../../common/entities/job/JobDTO';
|
||||||
|
import {ScheduledJobsService} from '../scheduled-jobs.service';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -22,7 +25,8 @@ export class TemplateComponent extends SettingsComponentDirective<any> implement
|
|||||||
navigation: NavigationService,
|
navigation: NavigationService,
|
||||||
notification: NotificationService,
|
notification: NotificationService,
|
||||||
settingsService: AbstractSettingsService,
|
settingsService: AbstractSettingsService,
|
||||||
globalSettingsService: SettingsService
|
globalSettingsService: SettingsService,
|
||||||
|
public jobsService: ScheduledJobsService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
authService,
|
authService,
|
||||||
@ -66,4 +70,7 @@ export class TemplateComponent extends SettingsComponentDirective<any> implement
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProgress(jobName: string): JobProgressDTO {
|
||||||
|
return this.jobsService.progress.value[JobDTOUtils.getHashName(jobName)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
.form-control {
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-info {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.buttons-row {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ import {
|
|||||||
JobScheduleDTO,
|
JobScheduleDTO,
|
||||||
JobScheduleDTOUtils,
|
JobScheduleDTOUtils,
|
||||||
JobTriggerType,
|
JobTriggerType,
|
||||||
PeriodicJobTrigger,
|
|
||||||
ScheduledJobTrigger
|
ScheduledJobTrigger
|
||||||
} from '../../../../../common/entities/job/JobScheduleDTO';
|
} from '../../../../../common/entities/job/JobScheduleDTO';
|
||||||
import {ScheduledJobsService} from '../scheduled-jobs.service';
|
import {ScheduledJobsService} from '../scheduled-jobs.service';
|
||||||
@ -96,6 +95,9 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
|||||||
}
|
}
|
||||||
|
|
||||||
atTimeLocal(atTime: number): Date {
|
atTimeLocal(atTime: number): Date {
|
||||||
|
if (!atTime) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
d.setUTCHours(Math.floor(atTime / 60));
|
d.setUTCHours(Math.floor(atTime / 60));
|
||||||
d.setUTCMinutes(Math.floor(atTime % 60));
|
d.setUTCMinutes(Math.floor(atTime % 60));
|
||||||
@ -156,6 +158,8 @@ export class WorkflowComponent implements ControlValueAccessor, Validator, OnIni
|
|||||||
|
|
||||||
case JobTriggerType.periodic:
|
case JobTriggerType.periodic:
|
||||||
schedule.trigger = new PeriodicJobTriggerConfig();
|
schedule.trigger = new PeriodicJobTriggerConfig();
|
||||||
|
schedule.trigger.periodicity = 7;
|
||||||
|
schedule.trigger.atTime = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JobTriggerType.after:
|
case JobTriggerType.after:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user