mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-23 01:27:14 +02:00
Cleaning up config and performance improvement #569
This commit is contained in:
parent
c191549270
commit
c5e80f2d84
@ -910,7 +910,10 @@ export class ServerMediaConfig extends ClientMediaConfig {
|
||||
export class ServerServiceConfig extends ClientServiceConfig {
|
||||
@ConfigProperty({
|
||||
arrayType: 'string',
|
||||
tags: {secret: true}
|
||||
tags: {
|
||||
secret: true,
|
||||
name: 'sessionSecret'
|
||||
}
|
||||
})
|
||||
sessionSecret: string[] = [];
|
||||
|
||||
|
@ -4,8 +4,8 @@ import {ServerConfig} from './PrivateConfig';
|
||||
import {WebConfigClass} from 'typeconfig/web';
|
||||
import {ConfigState} from 'typeconfig/common';
|
||||
import {WebConfigClassBuilder} from '../../../../node_modules/typeconfig/src/decorators/builders/WebConfigClassBuilder';
|
||||
import {IWebConfigClass} from '../../../../node_modules/typeconfig/src/decorators/class/IWebConfigClass';
|
||||
import { TAGS } from '../public/ClientConfig';
|
||||
import {IWebConfigClassPrivate} from '../../../../node_modules/typeconfig/src/decorators/class/IWebConfigClass';
|
||||
import {TAGS} from '../public/ClientConfig';
|
||||
|
||||
|
||||
@WebConfigClass({softReadonly: true})
|
||||
@ -13,9 +13,9 @@ export class WebConfig extends ServerConfig {
|
||||
@ConfigState()
|
||||
State: any;
|
||||
|
||||
clone(): IWebConfigClass<TAGS> & WebConfig {
|
||||
const wcg = WebConfigClassBuilder.attachInterface(new WebConfig());
|
||||
wcg.load(WebConfigClassBuilder.attachInterface(this).toJSON());
|
||||
clone(): IWebConfigClassPrivate<TAGS> & WebConfig {
|
||||
const wcg = WebConfigClassBuilder.attachPrivateInterface(new WebConfig());
|
||||
wcg.load(WebConfigClassBuilder.attachPrivateInterface(this).toJSON());
|
||||
return wcg;
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,6 @@ import {ScheduledJobsService} from './ui/settings/scheduled-jobs.service';
|
||||
import {BackendtextService} from './model/backendtext.service';
|
||||
import {ErrorInterceptor} from './model/network/helper/error.interceptor';
|
||||
import {CSRFInterceptor} from './model/network/helper/csrf.interceptor';
|
||||
import {SettingsEntryComponent} from './ui/settings/_abstract/settings-entry/settings-entry.component';
|
||||
import {GallerySearchQueryEntryComponent} from './ui/gallery/search/query-enrty/query-entry.search.gallery.component';
|
||||
import {StringifySearchQuery} from './pipes/StringifySearchQuery';
|
||||
import {AutoCompleteService} from './ui/gallery/search/autocomplete.service';
|
||||
@ -99,11 +98,11 @@ import {GalleryFilterComponent} from './ui/gallery/filter/filter.gallery.compone
|
||||
import {GallerySortingService} from './ui/gallery/navigator/sorting.service';
|
||||
import {FilterService} from './ui/gallery/filter/filter.service';
|
||||
import {TemplateComponent} from './ui/settings/template/template.component';
|
||||
import {AbstractSettingsService} from './ui/settings/_abstract/abstract.settings.service';
|
||||
import {WorkflowComponent} from './ui/settings/workflow/workflow.component';
|
||||
import {JobProgressComponent} from './ui/settings/jobs/progress/job-progress.settings.component';
|
||||
import {JobButtonComponent} from './ui/settings/jobs/button/job-button.settings.component';
|
||||
import {GalleryStatisticComponent} from './ui/settings/gallery-statistic/gallery-statistic.component';
|
||||
import { JobButtonComponent } from './ui/settings/workflow/button/job-button.settings.component';
|
||||
import { JobProgressComponent } from './ui/settings/workflow/progress/job-progress.settings.component';
|
||||
import {SettingsEntryComponent} from './ui/settings/template/settings-entry/settings-entry.component';
|
||||
|
||||
@Injectable()
|
||||
export class MyHammerConfig extends HammerGestureConfig {
|
||||
@ -271,8 +270,7 @@ Marker.prototype.options.icon = iconDefault;
|
||||
VersionService,
|
||||
ScheduledJobsService,
|
||||
BackendtextService,
|
||||
CookieService,
|
||||
AbstractSettingsService
|
||||
CookieService
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
@ -89,7 +89,6 @@
|
||||
*ngFor="let cp of configPaths"
|
||||
#setting
|
||||
#tmpl
|
||||
icon="list"
|
||||
[ConfigPath]="cp"
|
||||
[hidden]="!tmpl.HasAvailableSettings">
|
||||
<ng-container
|
||||
@ -99,62 +98,6 @@
|
||||
<app-settings-gallery-statistic></app-settings-gallery-statistic>
|
||||
</ng-container>
|
||||
</app-settings-template>
|
||||
<!-- <app-settings-template #setting #server
|
||||
icon="list"
|
||||
[ConfigPath]="'Server'"
|
||||
[hidden]="!server.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #users
|
||||
icon="person"
|
||||
[ConfigPath]="'Users'"
|
||||
[hidden]="!users.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #db
|
||||
icon="list"
|
||||
[ConfigPath]="'Database'"
|
||||
[hidden]="!db.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #media
|
||||
icon="camera-slr"
|
||||
[ConfigPath]="'Media'"
|
||||
[hidden]="!media.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #gallery
|
||||
icon="browser"
|
||||
[ConfigPath]="'Gallery'"
|
||||
[hidden]="!gallery.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #preview
|
||||
icon="image"
|
||||
[ConfigPath]="'Preview'"
|
||||
[hidden]="!preview.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #metafile
|
||||
icon="file"
|
||||
[ConfigPath]="'MetaFile'"
|
||||
[hidden]="!metafile.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #map
|
||||
icon="map-marker"
|
||||
[ConfigPath]="'Map'"
|
||||
[hidden]="!map.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #sharing
|
||||
icon="share"
|
||||
[ConfigPath]="'Sharing'"
|
||||
[hidden]="!sharing.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #faces
|
||||
icon="people"
|
||||
[ConfigPath]="'Faces'"
|
||||
[hidden]="!faces.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #album
|
||||
icon="grid-two-up"
|
||||
[ConfigPath]="'Album'"
|
||||
[hidden]="!album.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #randomPhoto
|
||||
icon="random"
|
||||
[ConfigPath]="'RandomPhoto'"
|
||||
[hidden]="!randomPhoto.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #duplicates
|
||||
icon="layers"
|
||||
[ConfigPath]="'Duplicates'"
|
||||
[hidden]="!duplicates.HasAvailableSettings"></app-settings-template>
|
||||
<app-settings-template #setting #indexing
|
||||
icon="pie-chart"
|
||||
[ConfigPath]="'Indexing'"
|
||||
[hidden]="!indexing.HasAvailableSettings"></app-settings-template>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -4,12 +4,13 @@ import {UserRoles} from '../../../../common/entities/UserDTO';
|
||||
import {NotificationService} from '../../model/notification.service';
|
||||
import {NotificationType} from '../../../../common/entities/NotificationDTO';
|
||||
import {NavigationService} from '../../model/navigation.service';
|
||||
import {ISettingsComponent} from '../settings/_abstract/ISettingsComponent';
|
||||
import {PageHelper} from '../../model/page.helper';
|
||||
import {SettingsService} from '../settings/settings.service';
|
||||
import {ConfigPriority} from '../../../../common/config/public/ClientConfig';
|
||||
import {Utils} from '../../../../common/Utils';
|
||||
import {WebConfig} from '../../../../common/config/private/WebConfig';
|
||||
import {ISettingsComponent} from '../settings/template/ISettingsComponent';
|
||||
import {WebConfigClassBuilder} from '../../../../../node_modules/typeconfig/src/decorators/builders/WebConfigClassBuilder';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin',
|
||||
@ -32,7 +33,9 @@ export class AdminComponent implements OnInit, AfterViewInit {
|
||||
public settingsService: SettingsService,
|
||||
) {
|
||||
this.configPriorities = Utils.enumToArray(ConfigPriority);
|
||||
this.configPaths = Object.keys((new WebConfig()).State);
|
||||
const wc = WebConfigClassBuilder.attachPrivateInterface(new WebConfig());
|
||||
this.configPaths = Object.keys(wc.State)
|
||||
.filter(s => !wc.__state[s].volatile);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
|
@ -1,28 +0,0 @@
|
||||
.title {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
.switch-wrapper {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
padding: 0;
|
||||
float: right;
|
||||
margin-top: -4px;
|
||||
margin-bottom: -4px;
|
||||
|
||||
}
|
||||
|
||||
.changed-settings input {
|
||||
border-color: var(--bs-primary);
|
||||
border-width: 1.5px;
|
||||
}
|
||||
|
||||
.changed-settings label {
|
||||
color: var(--bs-primary);
|
||||
font-weight: bold;
|
||||
}
|
@ -1,261 +0,0 @@
|
||||
import {Directive, Input, OnDestroy, OnInit, ViewChild,} from '@angular/core';
|
||||
import {AuthenticationService} from '../../../model/network/authentication.service';
|
||||
import {UserRoles} from '../../../../../common/entities/UserDTO';
|
||||
import {Utils} from '../../../../../common/Utils';
|
||||
import {ErrorDTO} from '../../../../../common/entities/Error';
|
||||
import {NotificationService} from '../../../model/notification.service';
|
||||
import {NavigationService} from '../../../model/navigation.service';
|
||||
import {AbstractSettingsService} from './abstract.settings.service';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {ISettingsComponent} from './ISettingsComponent';
|
||||
import {WebConfig} from '../../../../../common/config/private/WebConfig';
|
||||
import {FormControl} from '@angular/forms';
|
||||
import {ConfigPriority, TAGS} from '../../../../../common/config/public/ClientConfig';
|
||||
import {SettingsService} from '../settings.service';
|
||||
import {IWebConfigClassPrivate} from '../../../../../../node_modules/typeconfig/src/decorators/class/IWebConfigClass';
|
||||
import {WebConfigClassBuilder} from '../../../../../../node_modules/typeconfig/src/decorators/builders/WebConfigClassBuilder';
|
||||
|
||||
interface ConfigState<T = unknown> {
|
||||
value: T;
|
||||
original: T;
|
||||
default: T;
|
||||
readonly: boolean;
|
||||
tags: TAGS;
|
||||
onChange: () => unknown;
|
||||
isEnumType: boolean;
|
||||
isConfigType: boolean;
|
||||
isConfigArrayType: boolean;
|
||||
toJSON: () => T;
|
||||
}
|
||||
|
||||
export interface RecursiveState extends ConfigState {
|
||||
shouldHide: any;
|
||||
volatile: any;
|
||||
tags: any;
|
||||
isConfigType: any;
|
||||
isConfigArrayType: any;
|
||||
onChange: any;
|
||||
isEnumType: any;
|
||||
value: any;
|
||||
original: any;
|
||||
default: any;
|
||||
readonly: any;
|
||||
toJSON: any;
|
||||
|
||||
[key: string]: RecursiveState;
|
||||
}
|
||||
|
||||
|
||||
@Directive()
|
||||
export abstract class SettingsComponentDirective<
|
||||
T extends RecursiveState> implements OnInit, OnDestroy, ISettingsComponent {
|
||||
public icon: string;
|
||||
@Input() ConfigPath: string;
|
||||
|
||||
@ViewChild('settingsForm', {static: true})
|
||||
form: FormControl;
|
||||
|
||||
|
||||
public inProgress = false;
|
||||
public error: string = null;
|
||||
public changed = false;
|
||||
public states: RecursiveState = {} as RecursiveState;
|
||||
protected name: string;
|
||||
|
||||
private subscription: Subscription = null;
|
||||
private settingsSubscription: Subscription = null;
|
||||
protected sliceFN?: (s: WebConfig) => T;
|
||||
|
||||
protected constructor(
|
||||
protected authService: AuthenticationService,
|
||||
private navigation: NavigationService,
|
||||
public settingsService: AbstractSettingsService,
|
||||
protected notification: NotificationService,
|
||||
public globalSettingsService: SettingsService,
|
||||
sliceFN?: (s: IWebConfigClassPrivate<TAGS> & WebConfig) => T
|
||||
) {
|
||||
this.setSliceFN(sliceFN);
|
||||
}
|
||||
|
||||
setSliceFN(sliceFN?: (s: IWebConfigClassPrivate<TAGS> & WebConfig) => T) {
|
||||
if (sliceFN) {
|
||||
this.sliceFN = sliceFN;
|
||||
this.settingsSubscription = this.settingsService.Settings.subscribe(
|
||||
this.onNewSettings
|
||||
);
|
||||
this.onNewSettings(this.settingsService.settingsService.settings.value);
|
||||
}
|
||||
}
|
||||
|
||||
get Name(): string {
|
||||
return this.changed ? this.name + '*' : this.name;
|
||||
}
|
||||
|
||||
get Changed(): boolean {
|
||||
return this.changed;
|
||||
}
|
||||
|
||||
get HasAvailableSettings(): boolean {
|
||||
return !this.states?.shouldHide || !this.states?.shouldHide();
|
||||
}
|
||||
|
||||
onNewSettings = (s: WebConfig) => {
|
||||
this.states = this.sliceFN(s.clone()) as RecursiveState;
|
||||
const instrument = (st: RecursiveState, parent: RecursiveState) => {
|
||||
const shouldHide = (state: RecursiveState) => {
|
||||
return () => {
|
||||
if (state.volatile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state.tags &&
|
||||
((state.tags.relevant && !state.tags.relevant(parent.value))
|
||||
|| state.tags.secret)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if all sub elements are hidden, hide the parent too.
|
||||
if (state.isConfigType) {
|
||||
if (state.value.__state &&
|
||||
Object.keys(state.value.__state).findIndex(k => !st.value.__state[k].shouldHide()) === -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (state.isConfigArrayType) {
|
||||
for (let i = 0; i < state.value?.length; ++i) {
|
||||
if (state.value[i].__state &&
|
||||
Object.keys(state.value[i].__state).findIndex(k => !(st.value[i].__state[k].shouldHide && st.value[i].__state[k].shouldHide())) === -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
(state.tags?.priority > this.globalSettingsService.configPriority ||
|
||||
(this.globalSettingsService.configPriority === ConfigPriority.basic &&
|
||||
state.tags?.dockerSensitive && this.globalSettingsService.settings.value.Environment.isDocker)) && //if this value should not change in Docker, lets hide it
|
||||
Utils.equalsFilter(state.value, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']) &&
|
||||
Utils.equalsFilter(state.original, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']));
|
||||
};
|
||||
};
|
||||
|
||||
st.shouldHide = shouldHide(st);
|
||||
st.onChange = this.onOptionChange;
|
||||
st.rootConfig = parent?.value;
|
||||
if (typeof st.value !== 'undefined') {
|
||||
st.original = Utils.clone(st.value);
|
||||
}
|
||||
if (st.isConfigType) {
|
||||
for (const k of Object.keys(st.value.__state)) {
|
||||
instrument(st.value.__state[k], st);
|
||||
}
|
||||
}
|
||||
if (st.isConfigArrayType) {
|
||||
for (let i = 0; i < st.value?.length; ++i) {
|
||||
for (const k of Object.keys(st.value[i].__state)) {
|
||||
instrument(st.value[i].__state[k], st);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
instrument(this.states, null);
|
||||
this.icon = this.states.tags?.uiIcon;
|
||||
};
|
||||
|
||||
onOptionChange = () => {
|
||||
setTimeout(() => {
|
||||
const settingsSame = (state: RecursiveState): boolean => {
|
||||
if (typeof state === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
if (typeof state.original === 'object') {
|
||||
return Utils.equalsFilter(state.value, state.original,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig', '__state']);
|
||||
}
|
||||
if (typeof state.original !== 'undefined') {
|
||||
return state.value === state.original;
|
||||
}
|
||||
|
||||
const keys = Object.keys(state);
|
||||
|
||||
for (const key of keys) {
|
||||
if (settingsSame(state[key]) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.changed = !settingsSame(this.states);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
if (
|
||||
!this.authService.isAuthenticated() ||
|
||||
this.authService.user.value.role < UserRoles.Admin
|
||||
) {
|
||||
this.navigation.toLogin();
|
||||
return;
|
||||
}
|
||||
this.getSettings();
|
||||
|
||||
// TODO: fix after this issue is fixed: https://github.com/angular/angular/issues/24818
|
||||
this.subscription = this.form.valueChanges.subscribe(() => {
|
||||
this.onOptionChange();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.subscription != null) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
if (this.settingsSubscription != null) {
|
||||
this.settingsSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
stateToSettings(): T {
|
||||
return WebConfigClassBuilder.attachInterface(this.states.value).toJSON();
|
||||
}
|
||||
|
||||
public async save(): Promise<boolean> {
|
||||
this.inProgress = true;
|
||||
this.error = '';
|
||||
try {
|
||||
await this.settingsService.updateSettings(this.stateToSettings(), this.ConfigPath);
|
||||
await this.getSettings();
|
||||
this.notification.success(
|
||||
this.Name + ' ' + $localize`settings saved`,
|
||||
$localize`Success`
|
||||
);
|
||||
this.inProgress = false;
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err.message) {
|
||||
this.error = (err as ErrorDTO).message;
|
||||
}
|
||||
}
|
||||
|
||||
this.inProgress = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private async getSettings(): Promise<void> {
|
||||
await this.settingsService.getSettings();
|
||||
this.changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {SettingsService} from '../settings.service';
|
||||
import {WebConfig} from '../../../../../common/config/private/WebConfig';
|
||||
import {NetworkService} from '../../../model/network/network.service';
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class AbstractSettingsService {
|
||||
constructor(public settingsService: SettingsService,
|
||||
private networkService: NetworkService) {
|
||||
}
|
||||
|
||||
get Settings(): BehaviorSubject<WebConfig> {
|
||||
return this.settingsService.settings;
|
||||
}
|
||||
|
||||
public getSettings(): Promise<void> {
|
||||
return this.settingsService.getSettings();
|
||||
}
|
||||
|
||||
public updateSettings(settings: Record<string, any>, settingsPath: string): Promise<void> {
|
||||
return this.networkService.putJson('/settings', {settings, settingsPath});
|
||||
}
|
||||
}
|
@ -4,17 +4,18 @@ import {NetworkService} from '../../model/network/network.service';
|
||||
|
||||
import {WebConfig} from '../../../../common/config/private/WebConfig';
|
||||
import {WebConfigClassBuilder} from 'typeconfig/src/decorators/builders/WebConfigClassBuilder';
|
||||
import {ConfigPriority} from '../../../../common/config/public/ClientConfig';
|
||||
import {ConfigPriority, TAGS} from '../../../../common/config/public/ClientConfig';
|
||||
import {CookieNames} from '../../../../common/CookieNames';
|
||||
import {CookieService} from 'ngx-cookie-service';
|
||||
import {DefaultsJobs, JobDTO} from '../../../../common/entities/job/JobDTO';
|
||||
import {StatisticDTO} from '../../../../common/entities/settings/StatisticDTO';
|
||||
import {ScheduledJobsService} from './scheduled-jobs.service';
|
||||
import {IWebConfigClassPrivate} from '../../../../../node_modules/typeconfig/src/decorators/class/IWebConfigClass';
|
||||
|
||||
@Injectable()
|
||||
export class SettingsService {
|
||||
public configPriority = ConfigPriority.basic;
|
||||
public settings: BehaviorSubject<WebConfig>;
|
||||
public settings: BehaviorSubject<IWebConfigClassPrivate<TAGS> & WebConfig>;
|
||||
private fetchingSettings = false;
|
||||
public availableJobs: BehaviorSubject<JobDTO[]>;
|
||||
public statistic: BehaviorSubject<StatisticDTO>;
|
||||
@ -24,7 +25,7 @@ export class SettingsService {
|
||||
private cookieService: CookieService) {
|
||||
this.statistic = new BehaviorSubject(null);
|
||||
this.availableJobs = new BehaviorSubject([]);
|
||||
this.settings = new BehaviorSubject<WebConfig>(new WebConfig());
|
||||
this.settings = new BehaviorSubject<IWebConfigClassPrivate<TAGS> & WebConfig>(WebConfigClassBuilder.attachPrivateInterface(new WebConfig()));
|
||||
this.getSettings().catch(console.error);
|
||||
|
||||
if (this.cookieService.check(CookieNames.configPriority)) {
|
||||
@ -59,7 +60,7 @@ export class SettingsService {
|
||||
}
|
||||
this.fetchingSettings = true;
|
||||
try {
|
||||
const wcg = WebConfigClassBuilder.attachInterface(new WebConfig());
|
||||
const wcg = WebConfigClassBuilder.attachPrivateInterface(new WebConfig());
|
||||
wcg.load(
|
||||
await this.networkService.getJson<Promise<WebConfig>>('/settings')
|
||||
);
|
||||
@ -70,6 +71,11 @@ export class SettingsService {
|
||||
this.fetchingSettings = false;
|
||||
}
|
||||
|
||||
|
||||
public updateSettings(settings: Record<string, any>, settingsPath: string): Promise<void> {
|
||||
return this.networkService.putJson('/settings', {settings, settingsPath});
|
||||
}
|
||||
|
||||
configPriorityChanged(): void {
|
||||
// save it for some years
|
||||
this.cookieService.set(
|
||||
|
@ -12,9 +12,9 @@
|
||||
<label class="col-md-2 control-label" [for]="idName">{{name}}</label>
|
||||
<div class="col-md-10">
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group" [ngSwitch]="uiType">
|
||||
<app-gallery-search-field
|
||||
*ngIf="Type === 'SearchQuery'"
|
||||
*ngSwitchCase="'SearchQuery'"
|
||||
[(ngModel)]="state.value"
|
||||
[id]="idName"
|
||||
[name]="idName"
|
||||
@ -24,18 +24,11 @@
|
||||
placeholder="Search Query">
|
||||
</app-gallery-search-field>
|
||||
|
||||
<div class="input-group">
|
||||
<div class="input-group"
|
||||
*ngSwitchCase="'StringInput'">
|
||||
<input
|
||||
*ngIf="!state.isEnumType &&
|
||||
!state.isEnumArrayType &&
|
||||
Type !== 'boolean' &&
|
||||
Type !== 'SearchQuery' &&
|
||||
ArrayType !== 'MapLayers' &&
|
||||
ArrayType !== 'NavigationLinkConfig' &&
|
||||
ArrayType !== 'JobScheduleConfig' &&
|
||||
ArrayType !== 'UserConfig'"
|
||||
[type]="type" [min]="state.min" [max]="state.max" class="form-control"
|
||||
[placeholder]="PlaceHolder"
|
||||
[type]="HTMLInputType" [min]="state.min" [max]="state.max" class="form-control"
|
||||
[placeholder]="placeholder"
|
||||
[title]="title"
|
||||
[(ngModel)]="StringValue"
|
||||
(ngModelChange)="onChange($event)"
|
||||
@ -49,7 +42,7 @@
|
||||
</div>
|
||||
|
||||
<select
|
||||
*ngIf="state.isEnumType"
|
||||
*ngSwitchCase="'EnumType'"
|
||||
[id]="idName"
|
||||
[name]="idName"
|
||||
[title]="title"
|
||||
@ -62,7 +55,7 @@
|
||||
|
||||
|
||||
<bSwitch
|
||||
*ngIf="Type === 'boolean'"
|
||||
*ngSwitchCase="'Boolean'"
|
||||
class="switch"
|
||||
[id]="idName"
|
||||
[name]="idName"
|
||||
@ -83,7 +76,7 @@
|
||||
|
||||
<app-settings-workflow
|
||||
class="w-100"
|
||||
*ngIf="ArrayType === 'JobScheduleConfig'"
|
||||
*ngSwitchCase="'JobScheduleConfig'"
|
||||
[(ngModel)]="state.value"
|
||||
[id]="idName"
|
||||
[name]="idName"
|
||||
@ -91,7 +84,7 @@
|
||||
(ngModelChange)="onChange($event)">
|
||||
</app-settings-workflow>
|
||||
|
||||
<ng-container *ngIf="ArrayType === 'MapLayers'">
|
||||
<ng-container *ngSwitchCase="'MapLayers'">
|
||||
<div class="container">
|
||||
<table class="table">
|
||||
<thead>
|
||||
@ -131,7 +124,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="ArrayType === 'NavigationLinkConfig'">
|
||||
<ng-container *ngSwitchCase="'NavigationLinkConfig'">
|
||||
<div class="container">
|
||||
<div class="row mt-1 mb-1 bg-light" *ngFor="let link of state.value; let i = index">
|
||||
<div class="col ps-0">
|
||||
@ -194,7 +187,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="ArrayType === 'UserConfig'">
|
||||
<ng-container *ngSwitchCase="'UserConfig'">
|
||||
<div class="container ps-0 pe-0">
|
||||
<div class="row ms-0 me-0 mt-1 mb-1 bg-light" *ngFor="let item of state.value; let i = index">
|
||||
<div class="col ps-0">
|
||||
@ -239,14 +232,14 @@
|
||||
<div class="row me-0">
|
||||
<div class="col pe-0">
|
||||
<button class="btn btn-primary float-end"
|
||||
(click)="AddNew()" i18n>+ Add Link
|
||||
(click)="AddNew()" i18n>+ Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="state.isEnumArrayType">
|
||||
<ng-container *ngSwitchCase="'EnumArray'">
|
||||
<ng-container *ngFor="let _ of state.value; let i=index">
|
||||
<div class="row col-12 mt-1 m-0 p-0">
|
||||
<div class="col p-0">
|
||||
@ -263,7 +256,7 @@
|
||||
|
||||
|
||||
</div>
|
||||
<ng-container *ngIf="state.type === 'array'">
|
||||
<ng-container>
|
||||
<div class="col-auto pe-0">
|
||||
<button class="btn btn-secondary float-end"
|
||||
[id]="'list_btn_'+idName+i"
|
||||
@ -274,12 +267,12 @@
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="state.type === 'array'">
|
||||
<ng-container>
|
||||
<div class="col-12 p-0">
|
||||
<button class="btn btn-primary mt-1 float-end"
|
||||
[id]="'btn_add_'+idName"
|
||||
[name]="'btn_add_'+idName"
|
||||
(click)="AddNew()">+Add
|
||||
(click)="AddNew()" i18n>+Add
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
@ -292,13 +285,14 @@
|
||||
class="oi oi-warning text-warning warning-icon ms-2" *ngIf="dockerWarning && changed"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="state.tags?.githubIssue"
|
||||
[href]="'https://github.com/bpatrik/pigallery2/issues/'+state.tags?.githubIssue">See
|
||||
[href]="'https://github.com/bpatrik/pigallery2/issues/'+state.tags?.githubIssue">
|
||||
<ng-container i18n>See</ng-container>
|
||||
#{{state.tags?.githubIssue}}.</a>
|
||||
</small>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
@ -1,4 +1,4 @@
|
||||
import {Component, forwardRef, Input, OnChanges} from '@angular/core';
|
||||
import {Component, forwardRef, OnChanges} from '@angular/core';
|
||||
import {ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator,} from '@angular/forms';
|
||||
import {Utils} from '../../../../../../common/Utils';
|
||||
import {propertyTypes} from 'typeconfig/common';
|
||||
@ -57,11 +57,15 @@ export class SettingsEntryComponent
|
||||
state: IState;
|
||||
isNumberArray = false;
|
||||
isNumber = false;
|
||||
type = 'text';
|
||||
HTMLInputType = 'text';
|
||||
title: string;
|
||||
idName: string;
|
||||
private readonly GUID = Utils.GUID();
|
||||
NavigationLinkTypes = NavigationLinkTypes;
|
||||
public type: string | object;
|
||||
public arrayType: string;
|
||||
public uiType: string;
|
||||
|
||||
|
||||
constructor(private searchQueryParserService: SearchQueryParserService,
|
||||
public settingsService: SettingsService,
|
||||
@ -93,12 +97,8 @@ export class SettingsEntryComponent
|
||||
return this.state.shouldHide && this.state.shouldHide();
|
||||
}
|
||||
|
||||
get PlaceHolder(): string {
|
||||
return this.placeholder || this.state.tags?.hint || this.state.default;
|
||||
}
|
||||
|
||||
get defaultStr(): string {
|
||||
if (this.Type === 'SearchQuery') {
|
||||
if (this.type === 'SearchQuery') {
|
||||
return (
|
||||
'\'' + this.searchQueryParserService.stringify(this.state.default) + '\''
|
||||
);
|
||||
@ -111,26 +111,6 @@ export class SettingsEntryComponent
|
||||
return this.state.default;
|
||||
}
|
||||
|
||||
get Type(): string | object {
|
||||
return this.state.tags?.uiType || this.state.type;
|
||||
}
|
||||
|
||||
get ArrayType(): string {
|
||||
if (this.state.arrayType === MapLayers) {
|
||||
return 'MapLayers';
|
||||
}
|
||||
if (this.state.arrayType === NavigationLinkConfig) {
|
||||
return 'NavigationLinkConfig';
|
||||
}
|
||||
if (this.state.arrayType === UserConfig) {
|
||||
return 'UserConfig';
|
||||
}
|
||||
if (this.state.arrayType === JobScheduleConfig) {
|
||||
return 'JobScheduleConfig';
|
||||
}
|
||||
|
||||
this.state.arrayType;
|
||||
}
|
||||
|
||||
get StringValue(): string {
|
||||
if (
|
||||
@ -192,6 +172,44 @@ export class SettingsEntryComponent
|
||||
if (!this.state) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cache type overrides
|
||||
this.type = this.state.tags?.uiType || this.state.type;
|
||||
this.arrayType = null;
|
||||
if (this.state.arrayType === MapLayers) {
|
||||
this.arrayType = 'MapLayers';
|
||||
} else if (this.state.arrayType === NavigationLinkConfig) {
|
||||
this.arrayType = 'NavigationLinkConfig';
|
||||
} else if (this.state.arrayType === UserConfig) {
|
||||
this.arrayType = 'UserConfig';
|
||||
} else if (this.state.arrayType === JobScheduleConfig) {
|
||||
this.arrayType = 'JobScheduleConfig';
|
||||
} else {
|
||||
this.arrayType = this.state.arrayType;
|
||||
}
|
||||
this.uiType = this.arrayType;
|
||||
if (!this.state.isEnumType &&
|
||||
!this.state.isEnumArrayType &&
|
||||
this.type !== 'boolean' &&
|
||||
this.type !== 'SearchQuery' &&
|
||||
this.arrayType !== 'MapLayers' &&
|
||||
this.arrayType !== 'NavigationLinkConfig' &&
|
||||
this.arrayType !== 'JobScheduleConfig' &&
|
||||
this.arrayType !== 'UserConfig') {
|
||||
this.uiType = 'StringInput';
|
||||
}
|
||||
if (this.type === 'SearchQuery') {
|
||||
this.uiType = 'SearchQuery';
|
||||
} else if (this.state.isEnumType) {
|
||||
this.uiType = 'EnumType';
|
||||
} else if (this.type === 'boolean') {
|
||||
this.uiType = 'Boolean';
|
||||
} else if (this.state.isEnumArrayType) {
|
||||
this.uiType = 'EnumArray';
|
||||
}
|
||||
|
||||
this.placeholder = this.state.tags?.hint || this.state.default;
|
||||
|
||||
if (this.state.tags?.uiOptions) {
|
||||
this.state.isEnumType = true;
|
||||
}
|
||||
@ -218,11 +236,11 @@ export class SettingsEntryComponent
|
||||
|
||||
|
||||
if (this.isNumber) {
|
||||
this.type = 'number';
|
||||
this.HTMLInputType = 'number';
|
||||
} else if (this.state.type === 'password') {
|
||||
this.type = 'password';
|
||||
this.HTMLInputType = 'password';
|
||||
} else {
|
||||
this.type = 'text';
|
||||
this.HTMLInputType = 'text';
|
||||
}
|
||||
this.description = this.description || this.state.description;
|
||||
if (this.state.tags) {
|
@ -0,0 +1,28 @@
|
||||
.title {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
.switch-wrapper {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
padding: 0;
|
||||
float: right;
|
||||
margin-top: -4px;
|
||||
margin-bottom: -4px;
|
||||
|
||||
}
|
||||
|
||||
.changed-settings input {
|
||||
border-color: var(--bs-primary);
|
||||
border-width: 1.5px;
|
||||
}
|
||||
|
||||
.changed-settings label {
|
||||
color: var(--bs-primary);
|
||||
font-weight: bold;
|
||||
}
|
@ -84,7 +84,7 @@
|
||||
{{job.description}}
|
||||
</div>
|
||||
<app-settings-job-button
|
||||
*ngIf="!job.relevant || job.relevant(globalSettingsService.settings | async)"
|
||||
*ngIf="!job.relevant || job.relevant(settingsService.settings | async)"
|
||||
class="mt-2 mb-1 mb-md-0 mt-md-0 float-left me-2"
|
||||
[soloRun]="true"
|
||||
(jobError)="error=$event"
|
||||
@ -95,7 +95,7 @@
|
||||
|
||||
<ng-container *ngFor="let job of rStates.tags?.uiJob">
|
||||
<ng-container
|
||||
*ngIf="getProgress(job.job) && !job.hideProgress && (!job.relevant || job.relevant(globalSettingsService.settings | async))">
|
||||
*ngIf="getProgress(job.job) && !job.hideProgress && (!job.relevant || job.relevant(settingsService.settings | async))">
|
||||
<hr class="mt-1"/>
|
||||
<app-settings-job-progress
|
||||
class="d-block mb-2"
|
||||
|
@ -1,59 +1,284 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
||||
import {AuthenticationService} from '../../../model/network/authentication.service';
|
||||
import {NavigationService} from '../../../model/navigation.service';
|
||||
import {NotificationService} from '../../../model/notification.service';
|
||||
import {SettingsComponentDirective} from '../_abstract/abstract.settings.component';
|
||||
import {SettingsService} from '../settings.service';
|
||||
import {WebConfig} from '../../../../../common/config/private/WebConfig';
|
||||
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';
|
||||
import {FormControl} from '../../../../../../node_modules/@angular/forms';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {IWebConfigClassPrivate} from '../../../../../../node_modules/typeconfig/src/decorators/class/IWebConfigClass';
|
||||
import {ConfigPriority, TAGS} from '../../../../../common/config/public/ClientConfig';
|
||||
import {Utils} from '../../../../../common/Utils';
|
||||
import {UserRoles} from '../../../../../common/entities/UserDTO';
|
||||
import {WebConfigClassBuilder} from '../../../../../../node_modules/typeconfig/src/decorators/builders/WebConfigClassBuilder';
|
||||
import {ErrorDTO} from '../../../../../common/entities/Error';
|
||||
import {ISettingsComponent} from './ISettingsComponent';
|
||||
|
||||
|
||||
interface ConfigState {
|
||||
value: {
|
||||
[key: string]: RecursiveState;
|
||||
};
|
||||
default: {
|
||||
[key: string]: RecursiveState;
|
||||
};
|
||||
readonly?: boolean;
|
||||
tags?: TAGS;
|
||||
volatile?: boolean;
|
||||
isEnumType?: boolean;
|
||||
isConfigType?: boolean;
|
||||
isConfigArrayType?: boolean;
|
||||
}
|
||||
|
||||
export interface RecursiveState extends ConfigState {
|
||||
value: any;
|
||||
default: any;
|
||||
volatile?: any;
|
||||
tags?: any;
|
||||
isConfigType?: any;
|
||||
isConfigArrayType?: any;
|
||||
isEnumType?: any;
|
||||
readonly?: any;
|
||||
toJSON?: any;
|
||||
onChange?: any;
|
||||
original?: any;
|
||||
shouldHide?: any;
|
||||
|
||||
[key: string]: RecursiveState;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-template',
|
||||
templateUrl: './template.component.html',
|
||||
styleUrls: ['./template.component.css',
|
||||
'../_abstract/abstract.settings.component.css']
|
||||
styleUrls: ['./template.component.css']
|
||||
})
|
||||
export class TemplateComponent extends SettingsComponentDirective<any> implements OnInit {
|
||||
export class TemplateComponent implements OnInit, OnDestroy, ISettingsComponent {
|
||||
|
||||
public icon: string;
|
||||
@Input() ConfigPath: string;
|
||||
|
||||
@ViewChild('settingsForm', {static: true})
|
||||
form: FormControl;
|
||||
|
||||
|
||||
public inProgress = false;
|
||||
public error: string = null;
|
||||
public changed = false;
|
||||
public states: RecursiveState = {} as RecursiveState;
|
||||
protected name: string;
|
||||
|
||||
private subscription: Subscription = null;
|
||||
private settingsSubscription: Subscription = null;
|
||||
protected sliceFN?: (s: IWebConfigClassPrivate<TAGS> & WebConfig) => ConfigState;
|
||||
|
||||
constructor(
|
||||
authService: AuthenticationService,
|
||||
navigation: NavigationService,
|
||||
notification: NotificationService,
|
||||
settingsService: AbstractSettingsService,
|
||||
globalSettingsService: SettingsService,
|
||||
protected authService: AuthenticationService,
|
||||
private navigation: NavigationService,
|
||||
protected notification: NotificationService,
|
||||
public settingsService: SettingsService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
) {
|
||||
super(
|
||||
authService,
|
||||
navigation,
|
||||
settingsService,
|
||||
notification,
|
||||
globalSettingsService
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
|
||||
if (
|
||||
!this.authService.isAuthenticated() ||
|
||||
this.authService.user.value.role < UserRoles.Admin
|
||||
) {
|
||||
this.navigation.toLogin();
|
||||
return;
|
||||
}
|
||||
this.getSettings();
|
||||
|
||||
// TODO: fix after this issue is fixed: https://github.com/angular/angular/issues/24818
|
||||
this.subscription = this.form.valueChanges.subscribe(() => {
|
||||
this.onOptionChange();
|
||||
});
|
||||
|
||||
if (!this.ConfigPath) {
|
||||
this.setSliceFN(c => ({value: c, isConfigType: true, type: WebConfig}));
|
||||
this.setSliceFN(c => ({value: c as any, isConfigType: true, type: WebConfig} as any));
|
||||
} else {
|
||||
this.setSliceFN(c => c.__state[this.ConfigPath]);
|
||||
}
|
||||
this.name = this.states.tags?.name || this.ConfigPath;
|
||||
}
|
||||
|
||||
getKeys(states: any) {
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.subscription != null) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
if (this.settingsSubscription != null) {
|
||||
this.settingsSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setSliceFN(sliceFN?: (s: IWebConfigClassPrivate<TAGS> & WebConfig) => ConfigState) {
|
||||
if (sliceFN) {
|
||||
this.sliceFN = sliceFN;
|
||||
this.settingsSubscription = this.settingsService.settings.subscribe(
|
||||
this.onNewSettings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
get Name(): string {
|
||||
return this.changed ? this.name + '*' : this.name;
|
||||
}
|
||||
|
||||
get Changed(): boolean {
|
||||
return this.changed;
|
||||
}
|
||||
|
||||
get HasAvailableSettings(): boolean {
|
||||
return !this.states?.shouldHide || !this.states?.shouldHide();
|
||||
}
|
||||
|
||||
onNewSettings = (s: IWebConfigClassPrivate<TAGS> & WebConfig) => {
|
||||
this.states = this.sliceFN(s.clone()) as RecursiveState;
|
||||
|
||||
const instrument = (st: RecursiveState, parent: RecursiveState) => {
|
||||
const shouldHide = (state: RecursiveState) => {
|
||||
return () => {
|
||||
if (state.volatile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state.tags &&
|
||||
((state.tags.relevant && !state.tags.relevant(parent.value))
|
||||
|| state.tags.secret)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if all sub elements are hidden, hide the parent too.
|
||||
if (state.isConfigType) {
|
||||
if (state.value.__state &&
|
||||
Object.keys(state.value.__state).findIndex(k => !st.value.__state[k].shouldHide()) === -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (state.isConfigArrayType) {
|
||||
for (let i = 0; i < state.value?.length; ++i) {
|
||||
if (state.value[i].__state &&
|
||||
Object.keys(state.value[i].__state).findIndex(k => !(st.value[i].__state[k].shouldHide && st.value[i].__state[k].shouldHide())) === -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
(state.tags?.priority > this.settingsService.configPriority ||
|
||||
(this.settingsService.configPriority === ConfigPriority.basic &&
|
||||
state.tags?.dockerSensitive && this.settingsService.settings.value.Environment.isDocker)) && //if this value should not change in Docker, lets hide it
|
||||
Utils.equalsFilter(state.value, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']) &&
|
||||
Utils.equalsFilter(state.original, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']));
|
||||
};
|
||||
};
|
||||
|
||||
st.shouldHide = shouldHide(st);
|
||||
st.onChange = this.onOptionChange;
|
||||
st.rootConfig = parent?.value;
|
||||
if (typeof st.value !== 'undefined') {
|
||||
st.original = Utils.clone(st.value);
|
||||
}
|
||||
|
||||
if (st.isConfigType) {
|
||||
for (const k of Object.keys(st.value.__state)) {
|
||||
instrument(st.value.__state[k], st);
|
||||
}
|
||||
}
|
||||
if (st.isConfigArrayType) {
|
||||
for (let i = 0; i < st.value?.length; ++i) {
|
||||
for (const k of Object.keys(st.value[i].__state)) {
|
||||
instrument(st.value[i].__state[k], st);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
instrument(this.states, null);
|
||||
this.icon = this.states.tags?.uiIcon;
|
||||
};
|
||||
|
||||
onOptionChange = () => {
|
||||
setTimeout(() => {
|
||||
const settingsSame = (state: RecursiveState): boolean => {
|
||||
if (typeof state === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
if (typeof state.original === 'object') {
|
||||
return Utils.equalsFilter(state.value, state.original,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig', '__state']);
|
||||
}
|
||||
if (typeof state.original !== 'undefined') {
|
||||
return state.value === state.original;
|
||||
}
|
||||
|
||||
const keys = Object.keys(state);
|
||||
|
||||
for (const key of keys) {
|
||||
if (settingsSame(state[key]) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.changed = !settingsSame(this.states);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
public reset(): void {
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
|
||||
public async save(): Promise<boolean> {
|
||||
this.inProgress = true;
|
||||
this.error = '';
|
||||
try {
|
||||
const state = WebConfigClassBuilder.attachInterface(this.states.value).toJSON();
|
||||
await this.settingsService.updateSettings(state, this.ConfigPath);
|
||||
await this.getSettings();
|
||||
this.notification.success(
|
||||
this.Name + ' ' + $localize`settings saved`,
|
||||
$localize`Success`
|
||||
);
|
||||
this.inProgress = false;
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err.message) {
|
||||
this.error = (err as ErrorDTO).message;
|
||||
}
|
||||
}
|
||||
|
||||
this.inProgress = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private async getSettings(): Promise<void> {
|
||||
await this.settingsService.getSettings();
|
||||
this.changed = false;
|
||||
}
|
||||
|
||||
getKeys(states: any): string[] {
|
||||
if (states.keys) {
|
||||
return states.keys;
|
||||
}
|
||||
const s = states.value.__state;
|
||||
return Object.keys(s).sort((a, b) => {
|
||||
const keys = Object.keys(s).sort((a, b) => {
|
||||
if ((s[a].isConfigType || s[a].isConfigArrayType) !== (s[b].isConfigType || s[b].isConfigArrayType)) {
|
||||
if (s[a].isConfigType || s[a].isConfigArrayType) {
|
||||
return 1;
|
||||
@ -68,6 +293,8 @@ export class TemplateComponent extends SettingsComponentDirective<any> implement
|
||||
return (s[a].tags?.name as string || a).localeCompare(s[b].tags?.name || b);
|
||||
|
||||
});
|
||||
states.keys = keys;
|
||||
return states.keys;
|
||||
}
|
||||
|
||||
getProgress(jobName: string): JobProgressDTO {
|
||||
|
Loading…
Reference in New Issue
Block a user