diff --git a/package-lock.json b/package-lock.json index e71ebb12..c4770b33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "reflect-metadata": "0.1.13", "sharp": "0.31.3", "ts-node-iptc": "1.0.11", - "typeconfig": "2.1.2", + "typeconfig": "2.2.7", "typeorm": "0.3.12", "xml2js": "0.6.2" }, @@ -20361,8 +20361,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" } @@ -35279,7 +35280,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" } diff --git a/package.json b/package.json index 7219c2c0..d5b78dfb 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "reflect-metadata": "0.1.13", "sharp": "0.31.3", "ts-node-iptc": "1.0.11", - "typeconfig": "2.1.2", + "typeconfig": "2.2.7", "typeorm": "0.3.12", "xml2js": "0.6.2" }, diff --git a/src/backend/middlewares/RenderingMWs.ts b/src/backend/middlewares/RenderingMWs.ts index 404c1814..2576db38 100644 --- a/src/backend/middlewares/RenderingMWs.ts +++ b/src/backend/middlewares/RenderingMWs.ts @@ -119,6 +119,7 @@ export class RenderingMWs { skipTags: {secret: true} as TAGS }) as PrivateConfigClass ); + console.log(message.result.Extensions.extensions); res.json(message); } diff --git a/src/backend/model/extension/ExtensionConfigWrapper.ts b/src/backend/model/extension/ExtensionConfigWrapper.ts index cad0ad24..2b61ab2c 100644 --- a/src/backend/model/extension/ExtensionConfigWrapper.ts +++ b/src/backend/model/extension/ExtensionConfigWrapper.ts @@ -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 implements IExtensionConfig { 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 implements IExtensionConfig { 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);*/ } } diff --git a/src/backend/model/extension/ExtensionManager.ts b/src/backend/model/extension/ExtensionManager.ts index 11f50aa4..795a6b09 100644 --- a/src/backend/model/extension/ExtensionManager.ts +++ b/src/backend/model/extension/ExtensionManager.ts @@ -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) { diff --git a/src/common/config/private/subconfigs/ServerExtensionsConfig.ts b/src/common/config/private/subconfigs/ServerExtensionsConfig.ts index 22f7ad66..4d62097e 100644 --- a/src/common/config/private/subconfigs/ServerExtensionsConfig.ts +++ b/src/common/config/private/subconfigs/ServerExtensionsConfig.ts @@ -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({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; + configs: GenericConfigType; } @SubConfigClass({softReadonly: true}) @@ -59,13 +60,6 @@ export class ServerExtensionsConfig extends ClientExtensionsConfig { }) extensions: ServerExtensionsEntryConfig[] = []; - @ConfigProperty({ - tags: { - name: $localize`Installed extensions2`, - priority: ConfigPriority.advanced - } - }) - extensions2: Record = {}; @ConfigProperty({ tags: { diff --git a/src/common/config/public/ClientConfig.ts b/src/common/config/public/ClientConfig.ts index 3ac5b769..5d24388d 100644 --- a/src/common/config/public/ClientConfig.ts +++ b/src/common/config/public/ClientConfig.ts @@ -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.` }) diff --git a/src/frontend/app/ui/admin/admin.component.ts b/src/frontend/app/ui/admin/admin.component.ts index 04feb789..5fb5d307 100644 --- a/src/frontend/app/ui/admin/admin.component.ts +++ b/src/frontend/app/ui/admin/admin.component.ts @@ -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; diff --git a/src/frontend/app/ui/settings/template/CustomSettingsEntries.ts b/src/frontend/app/ui/settings/template/CustomSettingsEntries.ts index b2346b6c..d7470668 100644 --- a/src/frontend/app/ui/settings/template/CustomSettingsEntries.ts +++ b/src/frontend/app/ui/settings/template/CustomSettingsEntries.ts @@ -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; } diff --git a/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.html b/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.html index f6bdbfbe..a04a9801 100644 --- a/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.html +++ b/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.html @@ -12,7 +12,6 @@ [hidden]="shouldHide">
-
- +
@@ -295,7 +296,7 @@ - +
@@ -357,7 +358,7 @@
- +
@@ -403,7 +404,7 @@
- +
@@ -468,7 +469,8 @@
- + +
diff --git a/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.ts b/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.ts index 1d235785..4857ba25 100644 --- a/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.ts +++ b/src/frontend/app/ui/settings/template/settings-entry/settings-entry.component.ts @@ -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'; } diff --git a/src/frontend/app/ui/settings/template/template.component.html b/src/frontend/app/ui/settings/template/template.component.html index 35f7fd8d..35af7b9b 100644 --- a/src/frontend/app/ui/settings/template/template.component.html +++ b/src/frontend/app/ui/settings/template/template.component.html @@ -3,7 +3,7 @@
- {{Name}} + {{ Name }}
@@ -22,7 +22,7 @@
- + - {{Name}} config is not supported with these settings. + {{ Name }} config is not supported with these settings.
@@ -72,46 +72,71 @@ let-confPath="confPath"> - - - -
-
-
- - {{rStates?.value.__state[ck].tags?.name || ck}} -
- + + +
+
+
{{ rStates?.value.__state[ck].tags?.name || ck }}
+
+
+
+
+ +
- -
-
-
{{rStates?.value.__state[ck].tags?.name || ck}}
-
-
-
+ + + + + + + + + + +
+
+
+ + {{ rStates?.value.__state[ck].tags?.name || ck }} +
+
-
- -
+ + +
+
+
{{ rStates?.value.__state[ck].tags?.name || ck }}
+
+
+
+
+
+
+ +
+
@@ -125,12 +150,14 @@ >
+
+
diff --git a/src/frontend/app/ui/settings/template/template.component.ts b/src/frontend/app/ui/settings/template/template.component.ts index 6c115e31..70aa8f9c 100644 --- a/src/frontend/app/ui/settings/template/template.component.ts +++ b/src/frontend/app/ui/settings/template/template.component.ts @@ -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 { 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;