mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-23 01:27:14 +02:00
Add basic extension UI #784
This commit is contained in:
parent
850fb7b48b
commit
d33e29cd82
11
package-lock.json
generated
11
package-lock.json
generated
@ -29,7 +29,7 @@
|
||||
"sharp": "0.31.3",
|
||||
"ts-exif-parser": "0.2.2",
|
||||
"ts-node-iptc": "1.0.11",
|
||||
"typeconfig": "2.1.2",
|
||||
"typeconfig": "2.2.7",
|
||||
"typeorm": "0.3.12",
|
||||
"xml2js": "0.6.2"
|
||||
},
|
||||
@ -20385,8 +20385,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typeconfig": {
|
||||
"version": "2.1.2",
|
||||
"license": "MIT",
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/typeconfig/-/typeconfig-2.2.7.tgz",
|
||||
"integrity": "sha512-xxMJky/XUsmWss8HM99uPeN+sZYF67AAht3Gajtnbp4k5bxBwplnahU+1N1GUKhmvFuqQoIQbiXsu9WpvznI1g==",
|
||||
"dependencies": {
|
||||
"minimist": "1.2.8"
|
||||
}
|
||||
@ -35319,7 +35320,9 @@
|
||||
}
|
||||
},
|
||||
"typeconfig": {
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/typeconfig/-/typeconfig-2.2.7.tgz",
|
||||
"integrity": "sha512-xxMJky/XUsmWss8HM99uPeN+sZYF67AAht3Gajtnbp4k5bxBwplnahU+1N1GUKhmvFuqQoIQbiXsu9WpvznI1g==",
|
||||
"requires": {
|
||||
"minimist": "1.2.8"
|
||||
}
|
||||
|
@ -56,7 +56,7 @@
|
||||
"sharp": "0.31.3",
|
||||
"ts-exif-parser": "0.2.2",
|
||||
"ts-node-iptc": "1.0.11",
|
||||
"typeconfig": "2.1.2",
|
||||
"typeconfig": "2.2.7",
|
||||
"typeorm": "0.3.12",
|
||||
"xml2js": "0.6.2"
|
||||
},
|
||||
|
@ -119,6 +119,7 @@ export class RenderingMWs {
|
||||
skipTags: {secret: true} as TAGS
|
||||
}) as PrivateConfigClass
|
||||
);
|
||||
console.log(message.result.Extensions.extensions);
|
||||
res.json(message);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {ConfigProperty, IConfigClass} from 'typeconfig/common';
|
||||
import {IConfigClass} from 'typeconfig/common';
|
||||
import {Config, PrivateConfigClass} from '../../../common/config/private/Config';
|
||||
import {ConfigClassBuilder} from 'typeconfig/node';
|
||||
import {IExtensionConfig} from './IExtension';
|
||||
@ -32,22 +32,14 @@ export class ExtensionConfig<C> implements IExtensionConfig<C> {
|
||||
constructor(private readonly extensionFolder: string) {
|
||||
}
|
||||
|
||||
private findConfig(config: PrivateConfigClass) {
|
||||
let c = (config.Extensions.extensions || []).find(e => e.path === this.extensionFolder);
|
||||
if (!c) {
|
||||
c = new ServerExtensionsEntryConfig(this.extensionFolder);
|
||||
config.Extensions.extensions.push(c);
|
||||
}
|
||||
private findConfig(config: PrivateConfigClass): ServerExtensionsEntryConfig {
|
||||
let c = (config.Extensions.extensions || []).find(e => e.path === this.extensionFolder);
|
||||
if (!c) {
|
||||
c = new ServerExtensionsEntryConfig(this.extensionFolder);
|
||||
config.Extensions.extensions.push(c);
|
||||
}
|
||||
return c;
|
||||
|
||||
if (!config.Extensions.extensions2[this.extensionFolder]) {
|
||||
Object.defineProperty(config.Extensions.extensions2, this.extensionFolder,
|
||||
ConfigProperty({type: ServerExtensionsEntryConfig})(config.Extensions.extensions2, this.extensionFolder));
|
||||
// config.Extensions.extensions2[this.extensionFolder] = c as any;
|
||||
|
||||
config.Extensions.extensions2[this.extensionFolder] = c;
|
||||
|
||||
}
|
||||
return config.Extensions.extensions2[this.extensionFolder];
|
||||
}
|
||||
|
||||
public getConfig(): C {
|
||||
@ -67,11 +59,12 @@ export class ExtensionConfig<C> implements IExtensionConfig<C> {
|
||||
const confTemplate = ConfigClassBuilder.attachPrivateInterface(new this.template());
|
||||
const extConf = this.findConfig(config);
|
||||
// confTemplate.__loadJSONObject(Utils.clone(extConf.configs || {}));
|
||||
//extConf.configs = confTemplate;
|
||||
Object.defineProperty(config.Extensions.extensions2[this.extensionFolder].configs, this.extensionFolder,
|
||||
ConfigProperty({type: this.template})(config.Extensions.extensions2[this.extensionFolder], this.extensionFolder));
|
||||
console.log(config.Extensions.extensions2[this.extensionFolder].configs);
|
||||
config.Extensions.extensions2[this.extensionFolder].configs = confTemplate as any;
|
||||
console.log(config.Extensions.extensions2[this.extensionFolder].configs);
|
||||
extConf.configs = confTemplate;
|
||||
console.log(((config as any).toJSON({attachState: true})).Extensions.extensions);
|
||||
/* Object.defineProperty(config.Extensions.extensions2[this.extensionFolder].configs, this.extensionFolder,
|
||||
ConfigProperty({type: this.template})(config.Extensions.extensions2[this.extensionFolder], this.extensionFolder));
|
||||
console.log(config.Extensions.extensions2[this.extensionFolder].configs);
|
||||
config.Extensions.extensions2[this.extensionFolder].configs = confTemplate as any;
|
||||
console.log(config.Extensions.extensions2[this.extensionFolder].configs);*/
|
||||
}
|
||||
}
|
||||
|
@ -73,10 +73,10 @@ export class ExtensionManager implements IObjectManager {
|
||||
|
||||
|
||||
const extList = fs
|
||||
.readdirSync(ProjectPath.ExtensionFolder)
|
||||
.filter((f): boolean =>
|
||||
fs.statSync(path.join(ProjectPath.ExtensionFolder, f)).isDirectory()
|
||||
);
|
||||
.readdirSync(ProjectPath.ExtensionFolder)
|
||||
.filter((f): boolean =>
|
||||
fs.statSync(path.join(ProjectPath.ExtensionFolder, f)).isDirectory()
|
||||
);
|
||||
extList.sort();
|
||||
|
||||
// delete not existing extensions
|
||||
@ -85,7 +85,7 @@ export class ExtensionManager implements IObjectManager {
|
||||
// Add new extensions
|
||||
const ePaths = Config.Extensions.extensions.map(ec => ec.path);
|
||||
extList.filter(ep => ePaths.indexOf(ep) === -1).forEach(ep =>
|
||||
Config.Extensions.extensions.push(new ServerExtensionsEntryConfig(ep)));
|
||||
Config.Extensions.extensions.push(new ServerExtensionsEntryConfig(ep)));
|
||||
|
||||
Logger.debug(LOG_TAG, 'Extensions found ', JSON.stringify(Config.Extensions.extensions.map(ec => ec.path)));
|
||||
}
|
||||
@ -118,10 +118,14 @@ export class ExtensionManager implements IObjectManager {
|
||||
}
|
||||
|
||||
if (fs.existsSync(packageJsonPath)) {
|
||||
Logger.silly(LOG_TAG, `Running: "npm install --prefer-offline --no-audit --progress=false --omit=dev" in ${extPath}`);
|
||||
await exec('npm install --no-audit --progress=false --omit=dev', {
|
||||
cwd: extPath
|
||||
});
|
||||
if (fs.existsSync(path.join(extPath, 'node_modules'))) {
|
||||
Logger.debug(LOG_TAG, `node_modules folder exists. Skipping "npm install".`);
|
||||
} else {
|
||||
Logger.silly(LOG_TAG, `Running: "npm install --prefer-offline --no-audit --progress=false --omit=dev" in ${extPath}`);
|
||||
await exec('npm install --no-audit --progress=false --omit=dev', {
|
||||
cwd: extPath
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const pkg = require(packageJsonPath);
|
||||
if (pkg.name) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
||||
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
|
||||
import {ClientExtensionsConfig, ConfigPriority, TAGS} from '../../public/ClientConfig';
|
||||
import {IConfigClassPrivate} from '../../../../../node_modules/typeconfig/src/decorators/class/IConfigClass';
|
||||
import {GenericConfigType} from 'typeconfig/src/GenericConfigType';
|
||||
|
||||
@SubConfigClass<TAGS>({softReadonly: true})
|
||||
export class ServerExtensionsEntryConfig {
|
||||
@ -28,12 +28,13 @@ export class ServerExtensionsEntryConfig {
|
||||
path: string = '';
|
||||
|
||||
@ConfigProperty({
|
||||
type: GenericConfigType,
|
||||
tags: {
|
||||
name: $localize`Config`,
|
||||
priority: ConfigPriority.advanced
|
||||
}
|
||||
})
|
||||
configs: IConfigClassPrivate<unknown>;
|
||||
configs: GenericConfigType;
|
||||
}
|
||||
|
||||
@SubConfigClass<TAGS>({softReadonly: true})
|
||||
@ -59,13 +60,6 @@ export class ServerExtensionsConfig extends ClientExtensionsConfig {
|
||||
})
|
||||
extensions: ServerExtensionsEntryConfig[] = [];
|
||||
|
||||
@ConfigProperty({
|
||||
tags: {
|
||||
name: $localize`Installed extensions2`,
|
||||
priority: ConfigPriority.advanced
|
||||
}
|
||||
})
|
||||
extensions2: Record<string, ServerExtensionsEntryConfig> = {};
|
||||
|
||||
@ConfigProperty({
|
||||
tags: {
|
||||
|
@ -11,7 +11,7 @@ declare let $localize: (s: TemplateStringsArray) => string;
|
||||
if (typeof $localize === 'undefined') {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
global.$localize = (s) => s;
|
||||
global.$localize = (s) => s[0];
|
||||
}
|
||||
|
||||
|
||||
@ -1034,7 +1034,6 @@ export class ThemesConfig {
|
||||
name: $localize`Selected theme css`, //this is a 'hack' to the UI settings. UI will only show the selected setting's css
|
||||
uiDisabled: (sb: ThemesConfig) => !sb.enabled,
|
||||
relevant: (c: ThemesConfig) => c.selectedTheme !== 'default',
|
||||
uiType: 'SelectedThemeSettings'
|
||||
} as TAGS,
|
||||
description: $localize`Adds these css settings as it is to the end of the body tag of the page.`
|
||||
})
|
||||
|
@ -30,12 +30,12 @@ export class AdminComponent implements OnInit, AfterViewInit {
|
||||
public readonly configPaths: string[] = [];
|
||||
|
||||
constructor(
|
||||
private authService: AuthenticationService,
|
||||
private navigation: NavigationService,
|
||||
public viewportScroller: ViewportScroller,
|
||||
public notificationService: NotificationService,
|
||||
public settingsService: SettingsService,
|
||||
private piTitleService: PiTitleService
|
||||
private authService: AuthenticationService,
|
||||
private navigation: NavigationService,
|
||||
public viewportScroller: ViewportScroller,
|
||||
public notificationService: NotificationService,
|
||||
public settingsService: SettingsService,
|
||||
private piTitleService: PiTitleService
|
||||
) {
|
||||
this.configPriorities = enumToTranslatedArray(ConfigPriority);
|
||||
this.configStyles = enumToTranslatedArray(ConfigStyle);
|
||||
@ -50,8 +50,8 @@ export class AdminComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
if (
|
||||
!this.authService.isAuthenticated() ||
|
||||
this.authService.user.value.role < UserRoles.Admin
|
||||
!this.authService.isAuthenticated() ||
|
||||
this.authService.user.value.role < UserRoles.Admin
|
||||
) {
|
||||
this.navigation.toLogin();
|
||||
return;
|
||||
|
@ -1,5 +1,15 @@
|
||||
import {propertyTypes} from 'typeconfig/common';
|
||||
import {ClientGroupingConfig, ClientSortingConfig, SVGIconConfig} from '../../../../../common/config/public/ClientConfig';
|
||||
import {
|
||||
ClientGroupingConfig,
|
||||
ClientSortingConfig,
|
||||
MapLayers,
|
||||
MapPathGroupConfig,
|
||||
MapPathGroupThemeConfig,
|
||||
NavigationLinkConfig,
|
||||
SVGIconConfig,
|
||||
ThemeConfig
|
||||
} from '../../../../../common/config/public/ClientConfig';
|
||||
import {JobScheduleConfig, UserConfig} from '../../../../../common/config/private/PrivateConfig';
|
||||
|
||||
/**
|
||||
* Configuration in these class have a custom UI
|
||||
@ -8,6 +18,13 @@ export class CustomSettingsEntries {
|
||||
public static readonly entries = [
|
||||
{c: ClientSortingConfig, name: 'ClientSortingConfig'},
|
||||
{c: ClientGroupingConfig, name: 'ClientGroupingConfig'},
|
||||
{c: MapLayers, name: 'MapLayers'},
|
||||
{c: JobScheduleConfig, name: 'JobScheduleConfig'},
|
||||
{c: UserConfig, name: 'UserConfig'},
|
||||
{c: NavigationLinkConfig, name: 'NavigationLinkConfig'},
|
||||
{c: MapPathGroupThemeConfig, name: 'MapPathGroupThemeConfig'},
|
||||
{c: MapPathGroupConfig, name: 'MapPathGroupConfig'},
|
||||
{c: ThemeConfig, name: 'ThemeConfig'},
|
||||
{c: SVGIconConfig, name: 'SVGIconConfig'},
|
||||
];
|
||||
|
||||
@ -46,7 +63,7 @@ export class CustomSettingsEntries {
|
||||
return cN;
|
||||
}
|
||||
|
||||
public static iS(s: { tags?: { uiType?: string }, type?: propertyTypes }) {
|
||||
public static iS(s: { tags?: { uiType?: string }, type?: propertyTypes, arrayType?: propertyTypes }) {
|
||||
const c = this.getConfigName(s);
|
||||
return this.entries.findIndex(e => e.name == c) !== -1;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
[hidden]="shouldHide">
|
||||
<label class="col-sm-3 col-md-2 control-label" [for]="idName">{{name}}</label>
|
||||
<div class="col-12 col-sm">
|
||||
|
||||
<div class="input-group" [ngSwitch]="uiType">
|
||||
<app-gallery-search-field
|
||||
*ngSwitchCase="'SearchQuery'"
|
||||
@ -29,7 +28,9 @@
|
||||
style="flex: 1"
|
||||
*ngSwitchCase="'StringInput'">
|
||||
<input
|
||||
[type]="HTMLInputType" [min]="state.min" [max]="state.max" class="form-control"
|
||||
[type]="HTMLInputType"
|
||||
[min]="state.min"
|
||||
[max]="state.max" class="form-control"
|
||||
[placeholder]="placeholder"
|
||||
[title]="title"
|
||||
[(ngModel)]="StringValue"
|
||||
@ -131,7 +132,7 @@
|
||||
|
||||
<textarea
|
||||
rows="5"
|
||||
*ngSwitchCase="'SelectedThemeSettings'"
|
||||
*ngSwitchCase="'ThemeConfig-Array'"
|
||||
type="text"
|
||||
class="form-control"
|
||||
[title]="title"
|
||||
@ -168,7 +169,7 @@
|
||||
|
||||
<app-settings-workflow
|
||||
class="w-100"
|
||||
*ngSwitchCase="'JobScheduleConfig'"
|
||||
*ngSwitchCase="'JobScheduleConfig-Array'"
|
||||
[(ngModel)]="state.value"
|
||||
[id]="idName"
|
||||
[name]="idName"
|
||||
@ -252,7 +253,7 @@
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'MapLayers'">
|
||||
<ng-container *ngSwitchCase="'MapLayers-Array'">
|
||||
<div class="container">
|
||||
<table class="table">
|
||||
<thead>
|
||||
@ -295,7 +296,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'MapPathGroupThemeConfig'">
|
||||
<ng-container *ngSwitchCase="'MapPathGroupThemeConfig-Array'">
|
||||
<div class="container">
|
||||
<div class="row mt-1 mb-1 bg-body-tertiary" *ngFor="let val of state.value; index as i; last as isLast">
|
||||
<div class="row mt-1 mb-1 bg-body-tertiary">
|
||||
@ -357,7 +358,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'MapPathGroupConfig'">
|
||||
<ng-container *ngSwitchCase="'MapPathGroupConfig-Array'">
|
||||
<div class="container">
|
||||
<div class="bg-body-tertiary row mt-1 mb-1" *ngFor="let arr of state.value; let i = index">
|
||||
<div class="row mt-1 mb-1 me-0 ms-0 pe-0 ps-0">
|
||||
@ -403,7 +404,7 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'NavigationLinkConfig'">
|
||||
<ng-container *ngSwitchCase="'NavigationLinkConfig-Array'">
|
||||
<div class="container">
|
||||
<div class="row mt-1 mb-1 bg-body-tertiary" *ngFor="let link of state.value; let i = index">
|
||||
<div class="col ps-0">
|
||||
@ -468,7 +469,8 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'UserConfig'">
|
||||
|
||||
<ng-container *ngSwitchCase="'UserConfig-Array'">
|
||||
<div class="container ps-0 pe-0">
|
||||
<div class="row ms-0 me-0 mt-1 mb-1 bg-body-tertiary" *ngFor="let item of state.value; let i = index">
|
||||
|
||||
|
@ -258,7 +258,7 @@ export class SettingsEntryComponent
|
||||
this.arrayType !== 'MapPathGroupConfig' &&
|
||||
this.arrayType !== 'ServerExtensionsEntryConfig' &&
|
||||
this.arrayType !== 'MapPathGroupThemeConfig' &&
|
||||
this.arrayType !== 'JobScheduleConfig' &&
|
||||
this.arrayType !== 'JobScheduleConfig-Array' &&
|
||||
this.arrayType !== 'UserConfig') {
|
||||
this.uiType = 'StringInput';
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="card-header">
|
||||
<h5 class="d-inline-block mb-0">
|
||||
<ng-icon [name]="icon"></ng-icon>
|
||||
{{Name}}
|
||||
{{ Name }}
|
||||
</h5>
|
||||
<div *ngIf="states.value.enabled !== undefined" class="float-end p-0">
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<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
|
||||
*ngTemplateOutlet="Recursion; context:{ rStates: states,topLevel:true,confPath:ConfigPath,skipJobs:true }"
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<div class="panel-info"
|
||||
*ngIf="states.value.enabled === false">
|
||||
{{Name}} <span i18n>config is not supported with these settings.</span>
|
||||
{{ Name }} <span i18n>config is not supported with these settings.</span>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-auto" *ngIf="states.tags?.uiJob && !states.tags?.uiJob[0].description">
|
||||
@ -72,46 +72,71 @@
|
||||
let-confPath="confPath">
|
||||
<div class="alert alert-secondary" role="alert"
|
||||
*ngIf="rStates.description && settingsService.configStyle == ConfigStyle.full">
|
||||
<ng-icon size="1.3em" name="ionInformationCircleOutline"></ng-icon> {{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>
|
||||
#{{rStates.tags?.githubIssue}}.</a>
|
||||
#{{ rStates.tags?.githubIssue }}.</a>
|
||||
</div>
|
||||
<ng-container *ngFor="let ck of getKeys(rStates)">
|
||||
<ng-container *ngIf="!(rStates.value.__state[ck].shouldHide && rStates.value.__state[ck].shouldHide())">
|
||||
<app-settings-entry
|
||||
*ngIf="(ck!=='enabled' || !topLevel) && !isExpandableConfig(rStates.value.__state[ck])"
|
||||
[name]="confPath+'_'+ck"
|
||||
[ngModel]="rStates?.value.__state[ck]">
|
||||
</app-settings-entry>
|
||||
<ng-container *ngIf="isExpandableConfig(rStates.value.__state[ck])">
|
||||
<div class="card mt-2 mb-2" *ngIf="topLevel && rStates?.value.__state[ck].tags?.uiIcon"
|
||||
[id]="ConfigPath+'.'+ck">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<ng-icon [name]="rStates?.value.__state[ck].tags?.uiIcon"></ng-icon>
|
||||
{{rStates?.value.__state[ck].tags?.name || ck}}
|
||||
</h5>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
||||
></ng-container>
|
||||
<!-- is array -->
|
||||
<ng-container *ngIf="rStates.value.__state[ck].isConfigArrayType && isExpandableArrayConfig(rStates.value.__state[ck])">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<h5>{{ rStates?.value.__state[ck].tags?.name || ck }}</h5>
|
||||
</div>
|
||||
<div class="col mt-2">
|
||||
<div class="row mt-2" *ngFor="let entry of rStates.value.__state[ck].value; let i = index">
|
||||
<hr/>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="Recursion; context:{ rStates: {value: rStates.value.__state[ck].value[i]}, confPath:confPath+'.'+ck+'.'+i }"
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="!topLevel || !rStates?.value.__state[ck].tags?.uiIcon">
|
||||
<div class="row mt-2">
|
||||
<div class="col-auto">
|
||||
<h5>{{rStates?.value.__state[ck].tags?.name || ck}}</h5>
|
||||
</div>
|
||||
<div class="col">
|
||||
<hr/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!rStates.value.__state[ck].isConfigArrayType || !isExpandableArrayConfig(rStates.value.__state[ck])">
|
||||
|
||||
<!-- simple entries or complex once's but with custom UI--->
|
||||
<app-settings-entry
|
||||
*ngIf="(ck!=='enabled' || !topLevel) && !isExpandableConfig(rStates.value.__state[ck])"
|
||||
[name]="confPath+'_'+ck"
|
||||
[ngModel]="rStates?.value.__state[ck]">
|
||||
</app-settings-entry>
|
||||
<!-- Config entries --->
|
||||
<ng-container *ngIf="isExpandableConfig(rStates.value.__state[ck])">
|
||||
<!-- Sub category with header and menu item -->
|
||||
<div class="card mt-2 mb-2" *ngIf="topLevel && rStates?.value.__state[ck].tags?.uiIcon"
|
||||
[id]="ConfigPath+'.'+ck">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<ng-icon [name]="rStates?.value.__state[ck].tags?.uiIcon"></ng-icon>
|
||||
{{ rStates?.value.__state[ck].tags?.name || ck }}
|
||||
</h5>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
||||
></ng-container>
|
||||
</div>
|
||||
<!-- Sub category without header and menu item -->
|
||||
<ng-container *ngIf="!topLevel || !rStates?.value.__state[ck].tags?.uiIcon">
|
||||
<div class="row mt-2">
|
||||
<div class="col-auto">
|
||||
<h5>{{ rStates?.value.__state[ck].tags?.name || ck }}</h5>
|
||||
</div>
|
||||
<div class="col">
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
||||
></ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@ -125,12 +150,14 @@
|
||||
></ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #JobTemplate let-uiJob="uiJob">
|
||||
<div class="mb-2">
|
||||
<ng-container *ngFor="let job of uiJob; let i = index">
|
||||
<div class="alert alert-secondary" role="alert"
|
||||
*ngIf="job.description && settingsService.configStyle == ConfigStyle.full">
|
||||
<ng-icon size="1.3em" name="ionInformationCircleOutline"></ng-icon> {{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)"
|
||||
@ -144,6 +171,7 @@
|
||||
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #JobProcessTemplate let-uiJob="uiJob">
|
||||
<div>
|
||||
<ng-container *ngFor="let job of uiJob">
|
||||
|
@ -79,11 +79,11 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
public readonly ConfigStyle = ConfigStyle;
|
||||
|
||||
constructor(
|
||||
protected authService: AuthenticationService,
|
||||
private navigation: NavigationService,
|
||||
protected notification: NotificationService,
|
||||
public settingsService: SettingsService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
protected authService: AuthenticationService,
|
||||
private navigation: NavigationService,
|
||||
protected notification: NotificationService,
|
||||
public settingsService: SettingsService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
this.nestedConfigs = [];
|
||||
for (const key of this.getKeys(this.states)) {
|
||||
if (this.states.value.__state[key].isConfigType &&
|
||||
this.states?.value.__state[key].tags?.uiIcon) {
|
||||
this.states?.value.__state[key].tags?.uiIcon) {
|
||||
this.nestedConfigs.push({
|
||||
id: this.ConfigPath + '.' + key,
|
||||
name: this.states?.value.__state[key].tags?.name,
|
||||
@ -112,8 +112,8 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
ngOnInit(): void {
|
||||
|
||||
if (
|
||||
!this.authService.isAuthenticated() ||
|
||||
this.authService.user.value.role < UserRoles.Admin
|
||||
!this.authService.isAuthenticated() ||
|
||||
this.authService.user.value.role < UserRoles.Admin
|
||||
) {
|
||||
this.navigation.toLogin();
|
||||
return;
|
||||
@ -143,7 +143,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
if (sliceFN) {
|
||||
this.sliceFN = sliceFN;
|
||||
this.settingsSubscription = this.settingsService.settings.subscribe(
|
||||
this.onNewSettings
|
||||
this.onNewSettings
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -171,31 +171,31 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
}
|
||||
|
||||
if (state.tags &&
|
||||
((state.tags.relevant && !state.tags.relevant(parent.value))
|
||||
|| state.tags.secret)) {
|
||||
((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.value.__state &&
|
||||
Object.keys(state.value.__state).findIndex(k => !st.value.__state[k].shouldHide()) === -1) {
|
||||
Object.keys(state.value.__state).findIndex(k => !st.value.__state[k].shouldHide()) === -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const forcedVisibility = !(state.tags?.priority > this.settingsService.configPriority ||
|
||||
//if this value should not change in Docker, lets hide it
|
||||
(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
|
||||
(this.settingsService.configPriority === ConfigPriority.basic &&
|
||||
state.tags?.dockerSensitive && this.settingsService.settings.value.Environment.isDocker));
|
||||
|
||||
if (state.isConfigArrayType) {
|
||||
for (let i = 0; i < state.value?.length; ++i) {
|
||||
for (const k of Object.keys(state.value[i].__state)) {
|
||||
if (!Utils.equalsFilter(
|
||||
state.value[i]?.__state[k]?.value,
|
||||
state.default[i] ? state.default[i][k] : undefined,
|
||||
['default', '__propPath', '__created', '__prototype', '__rootConfig'])) {
|
||||
state.value[i]?.__state[k]?.value,
|
||||
state.default[i] ? state.default[i][k] : undefined,
|
||||
['default', '__propPath', '__created', '__prototype', '__rootConfig'])) {
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -206,10 +206,10 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
|
||||
|
||||
return (!forcedVisibility &&
|
||||
Utils.equalsFilter(state.value, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']) &&
|
||||
Utils.equalsFilter(state.original, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']));
|
||||
Utils.equalsFilter(state.value, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']) &&
|
||||
Utils.equalsFilter(state.original, state.default,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig']));
|
||||
};
|
||||
};
|
||||
|
||||
@ -246,7 +246,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
}
|
||||
if (typeof state.original === 'object') {
|
||||
return Utils.equalsFilter(state.value, state.original,
|
||||
['__propPath', '__created', '__prototype', '__rootConfig', '__state']);
|
||||
['__propPath', '__created', '__prototype', '__rootConfig', '__state']);
|
||||
}
|
||||
if (typeof state.original !== 'undefined') {
|
||||
return state.value === state.original;
|
||||
@ -271,10 +271,18 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* main template should list it
|
||||
* @param c
|
||||
*/
|
||||
isExpandableConfig(c: ConfigState) {
|
||||
return c.isConfigType && !CustomSettingsEntries.iS(c);
|
||||
}
|
||||
|
||||
isExpandableArrayConfig(c: ConfigState) {
|
||||
return c.isConfigArrayType && !CustomSettingsEntries.iS(c);
|
||||
}
|
||||
|
||||
|
||||
public async save(): Promise<boolean> {
|
||||
this.inProgress = true;
|
||||
@ -284,8 +292,8 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
await this.settingsService.updateSettings(state, this.ConfigPath);
|
||||
await this.getSettings();
|
||||
this.notification.success(
|
||||
this.Name + ' ' + $localize`settings saved`,
|
||||
$localize`Success`
|
||||
this.Name + ' ' + $localize`settings saved`,
|
||||
$localize`Success`
|
||||
);
|
||||
this.inProgress = false;
|
||||
return true;
|
||||
@ -328,7 +336,6 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
||||
return 1;
|
||||
}
|
||||
return (s[a].tags?.name as string || a).localeCompare(s[b].tags?.name || b);
|
||||
|
||||
});
|
||||
states.keys = keys;
|
||||
return states.keys;
|
||||
|
Loading…
Reference in New Issue
Block a user