mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-08 04:03:48 +02:00
Merge branch 'bpatrik:master' into feature/timestamp_rework_test_fix
This commit is contained in:
commit
d528760b26
11
package-lock.json
generated
11
package-lock.json
generated
@ -27,7 +27,7 @@
|
|||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
"sharp": "0.31.3",
|
"sharp": "0.31.3",
|
||||||
"ts-node-iptc": "1.0.11",
|
"ts-node-iptc": "1.0.11",
|
||||||
"typeconfig": "2.1.2",
|
"typeconfig": "2.2.11",
|
||||||
"typeorm": "0.3.12",
|
"typeorm": "0.3.12",
|
||||||
"xml2js": "0.6.2"
|
"xml2js": "0.6.2"
|
||||||
},
|
},
|
||||||
@ -20361,8 +20361,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typeconfig": {
|
"node_modules/typeconfig": {
|
||||||
"version": "2.1.2",
|
"version": "2.2.11",
|
||||||
"license": "MIT",
|
"resolved": "https://registry.npmjs.org/typeconfig/-/typeconfig-2.2.11.tgz",
|
||||||
|
"integrity": "sha512-Knj+1kbIJ4zOZlUm2TPSWZUoiOW4txrmPyf6oyuBhaDQDlGxpSL5jobF3vVV9mZElK1V3ZQVeTgvGaiDyeT8mQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "1.2.8"
|
"minimist": "1.2.8"
|
||||||
}
|
}
|
||||||
@ -35279,7 +35280,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typeconfig": {
|
"typeconfig": {
|
||||||
"version": "2.1.2",
|
"version": "2.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/typeconfig/-/typeconfig-2.2.11.tgz",
|
||||||
|
"integrity": "sha512-Knj+1kbIJ4zOZlUm2TPSWZUoiOW4txrmPyf6oyuBhaDQDlGxpSL5jobF3vVV9mZElK1V3ZQVeTgvGaiDyeT8mQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "1.2.8"
|
"minimist": "1.2.8"
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
"sharp": "0.31.3",
|
"sharp": "0.31.3",
|
||||||
"ts-node-iptc": "1.0.11",
|
"ts-node-iptc": "1.0.11",
|
||||||
"typeconfig": "2.1.2",
|
"typeconfig": "2.2.11",
|
||||||
"typeorm": "0.3.12",
|
"typeorm": "0.3.12",
|
||||||
"xml2js": "0.6.2"
|
"xml2js": "0.6.2"
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {Config} from '../common/config/private/Config';
|
import {Config} from '../common/config/private/Config';
|
||||||
import {LogLevel} from '../common/config/private/PrivateConfig';
|
import {LogLevel} from '../common/config/private/PrivateConfig';
|
||||||
|
|
||||||
export type logFN = (...args: (string | number)[]) => void;
|
export type logFN = (...args: (string | number | (() => string))[]) => void;
|
||||||
|
|
||||||
const forcedDebug = process.env['NODE_ENV'] === 'debug';
|
const forcedDebug = process.env['NODE_ENV'] === 'debug';
|
||||||
|
|
||||||
@ -11,7 +11,8 @@ if (forcedDebug === true) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoggerFunction = (...args: (string | number)[]) => void;
|
export type LoggerArgs = (string | number | (() => string))
|
||||||
|
export type LoggerFunction = (...args: LoggerArgs[]) => void;
|
||||||
|
|
||||||
export interface ILogger {
|
export interface ILogger {
|
||||||
silly: LoggerFunction;
|
silly: LoggerFunction;
|
||||||
@ -23,67 +24,67 @@ export interface ILogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const createLoggerWrapper = (TAG: string): ILogger => ({
|
export const createLoggerWrapper = (TAG: string): ILogger => ({
|
||||||
silly: (...args: (string | number)[]) => {
|
silly: (...args: LoggerArgs[]) => {
|
||||||
Logger.silly(TAG, ...args);
|
Logger.silly(TAG, ...args);
|
||||||
},
|
},
|
||||||
debug: (...args: (string | number)[]) => {
|
debug: (...args: LoggerArgs[]) => {
|
||||||
Logger.debug(TAG, ...args);
|
Logger.debug(TAG, ...args);
|
||||||
},
|
},
|
||||||
verbose: (...args: (string | number)[]) => {
|
verbose: (...args: LoggerArgs[]) => {
|
||||||
Logger.verbose(TAG, ...args);
|
Logger.verbose(TAG, ...args);
|
||||||
},
|
},
|
||||||
info: (...args: (string | number)[]) => {
|
info: (...args: LoggerArgs[]) => {
|
||||||
Logger.info(TAG, ...args);
|
Logger.info(TAG, ...args);
|
||||||
},
|
},
|
||||||
warn: (...args: (string | number)[]) => {
|
warn: (...args: LoggerArgs[]) => {
|
||||||
Logger.warn(TAG, ...args);
|
Logger.warn(TAG, ...args);
|
||||||
},
|
},
|
||||||
error: (...args: (string | number)[]) => {
|
error: (...args: LoggerArgs[]) => {
|
||||||
Logger.error(TAG, ...args);
|
Logger.error(TAG, ...args);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export class Logger {
|
export class Logger {
|
||||||
public static silly(...args: (string | number)[]): void {
|
public static silly(...args: LoggerArgs[]): void {
|
||||||
if (!forcedDebug && Config.Server.Log.level < LogLevel.silly) {
|
if (!forcedDebug && Config.Server.Log.level < LogLevel.silly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.log(`[\x1b[35mSILLY\x1b[0m]`, ...args);
|
Logger.log(`[\x1b[35mSILLY\x1b[0m]`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static debug(...args: (string | number)[]): void {
|
public static debug(...args: LoggerArgs[]): void {
|
||||||
if (!forcedDebug && Config.Server.Log.level < LogLevel.debug) {
|
if (!forcedDebug && Config.Server.Log.level < LogLevel.debug) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.log(`[\x1b[34mDEBUG\x1b[0m]`, ...args);
|
Logger.log(`[\x1b[34mDEBUG\x1b[0m]`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static verbose(...args: (string | number)[]): void {
|
public static verbose(...args: LoggerArgs[]): void {
|
||||||
if (!forcedDebug && Config.Server.Log.level < LogLevel.verbose) {
|
if (!forcedDebug && Config.Server.Log.level < LogLevel.verbose) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.log(`[\x1b[36mVERBS\x1b[0m]`, ...args);
|
Logger.log(`[\x1b[36mVERBS\x1b[0m]`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static info(...args: (string | number)[]): void {
|
public static info(...args: LoggerArgs[]): void {
|
||||||
if (!forcedDebug && Config.Server.Log.level < LogLevel.info) {
|
if (!forcedDebug && Config.Server.Log.level < LogLevel.info) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.log(`[\x1b[32mINFO_\x1b[0m]`, ...args);
|
Logger.log(`[\x1b[32mINFO_\x1b[0m]`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static warn(...args: (string | number)[]): void {
|
public static warn(...args: LoggerArgs[]): void {
|
||||||
if (!forcedDebug && Config.Server.Log.level < LogLevel.warn) {
|
if (!forcedDebug && Config.Server.Log.level < LogLevel.warn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.log(`[\x1b[33mWARN_\x1b[0m]`, ...args);
|
Logger.log(`[\x1b[33mWARN_\x1b[0m]`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static error(...args: (string | number)[]): void {
|
public static error(...args: LoggerArgs[]): void {
|
||||||
Logger.log(`[\x1b[31mERROR\x1b[0m]`, ...args);
|
Logger.log(`[\x1b[31mERROR\x1b[0m]`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static log(tag: string, ...args: (string | number)[]): void {
|
private static log(tag: string, ...args: LoggerArgs[]): void {
|
||||||
const date = new Date().toLocaleString();
|
const date = new Date().toLocaleString();
|
||||||
let LOG_TAG = '';
|
let LOG_TAG = '';
|
||||||
if (
|
if (
|
||||||
@ -95,6 +96,11 @@ export class Logger {
|
|||||||
LOG_TAG = args[0];
|
LOG_TAG = args[0];
|
||||||
args.shift();
|
args.shift();
|
||||||
}
|
}
|
||||||
|
args.forEach((element:LoggerArgs, index:number) => {
|
||||||
|
if(typeof element === "function"){
|
||||||
|
args[index] = element(); //execute function, put resulting string in the array
|
||||||
|
}
|
||||||
|
});
|
||||||
console.log(date + tag + LOG_TAG, ...args);
|
console.log(date + tag + LOG_TAG, ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,6 @@ export class SharingMWs {
|
|||||||
sharing,
|
sharing,
|
||||||
forceUpdate
|
forceUpdate
|
||||||
);
|
);
|
||||||
console.log(req.resultPipe);
|
|
||||||
return next();
|
return next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return next(
|
return next(
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import {NextFunction, Request, Response} from 'express';
|
import {NextFunction, Request, Response} from 'express';
|
||||||
import {ErrorCodes, ErrorDTO} from '../../../common/entities/Error';
|
import {ErrorCodes, ErrorDTO} from '../../../common/entities/Error';
|
||||||
import {Logger} from '../../Logger';
|
|
||||||
import {Config} from '../../../common/config/private/Config';
|
import {Config} from '../../../common/config/private/Config';
|
||||||
import {ConfigDiagnostics} from '../../model/diagnostics/ConfigDiagnostics';
|
import {ConfigDiagnostics} from '../../model/diagnostics/ConfigDiagnostics';
|
||||||
import {ConfigClassBuilder} from 'typeconfig/node';
|
import {ConfigClassBuilder} from 'typeconfig/node';
|
||||||
import {TAGS} from '../../../common/config/public/ClientConfig';
|
import {TAGS} from '../../../common/config/public/ClientConfig';
|
||||||
import {ObjectManagers} from '../../model/ObjectManagers';
|
import {ObjectManagers} from '../../model/ObjectManagers';
|
||||||
import {ExtensionConfigWrapper} from '../../model/extension/ExtensionConfigWrapper';
|
import {ExtensionConfigWrapper} from '../../model/extension/ExtensionConfigWrapper';
|
||||||
|
import {Logger} from '../../Logger';
|
||||||
|
|
||||||
const LOG_TAG = '[SettingsMWs]';
|
const LOG_TAG = '[SettingsMWs]';
|
||||||
|
|
||||||
@ -21,8 +21,8 @@ export class SettingsMWs {
|
|||||||
*/
|
*/
|
||||||
public static async updateSettings(req: Request, res: Response, next: NextFunction): Promise<void> {
|
public static async updateSettings(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||||
if ((typeof req.body === 'undefined')
|
if ((typeof req.body === 'undefined')
|
||||||
|| (typeof req.body.settings === 'undefined')
|
|| (typeof req.body.settings === 'undefined')
|
||||||
|| (typeof req.body.settingsPath !== 'string')) {
|
|| (typeof req.body.settingsPath !== 'string')) {
|
||||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'settings is needed'));
|
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'settings is needed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ import {IConfigClass} from 'typeconfig/common';
|
|||||||
import {Config, PrivateConfigClass} from '../../../common/config/private/Config';
|
import {Config, PrivateConfigClass} from '../../../common/config/private/Config';
|
||||||
import {ConfigClassBuilder} from 'typeconfig/node';
|
import {ConfigClassBuilder} from 'typeconfig/node';
|
||||||
import {IExtensionConfig} from './IExtension';
|
import {IExtensionConfig} from './IExtension';
|
||||||
import {Utils} from '../../../common/Utils';
|
|
||||||
import {ObjectManagers} from '../ObjectManagers';
|
import {ObjectManagers} from '../ObjectManagers';
|
||||||
|
import {ServerExtensionsEntryConfig} from '../../../common/config/private/subconfigs/ServerExtensionsConfig';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps to original config and makes sure all extension related config is loaded
|
* Wraps to original config and makes sure all extension related config is loaded
|
||||||
@ -12,12 +12,13 @@ export class ExtensionConfigWrapper {
|
|||||||
static async original(): Promise<PrivateConfigClass & IConfigClass> {
|
static async original(): Promise<PrivateConfigClass & IConfigClass> {
|
||||||
const pc = ConfigClassBuilder.attachPrivateInterface(new PrivateConfigClass());
|
const pc = ConfigClassBuilder.attachPrivateInterface(new PrivateConfigClass());
|
||||||
try {
|
try {
|
||||||
await pc.load();
|
await pc.load(); // loading the basic configs but we do not know the extension config hierarchy yet
|
||||||
if (ObjectManagers.isReady()) {
|
if (ObjectManagers.isReady()) {
|
||||||
for (const ext of Object.values(ObjectManagers.getInstance().ExtensionManager.extObjects)) {
|
for (const ext of Object.values(ObjectManagers.getInstance().ExtensionManager.extObjects)) {
|
||||||
ext.config.loadToConfig(ConfigClassBuilder.attachPrivateInterface(pc));
|
ext.config.loadToConfig(ConfigClassBuilder.attachPrivateInterface(pc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await pc.load(); // loading the extension related configs
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error during loading original config. Reverting to defaults.');
|
console.error('Error during loading original config. Reverting to defaults.');
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -29,11 +30,21 @@ export class ExtensionConfigWrapper {
|
|||||||
export class ExtensionConfig<C> implements IExtensionConfig<C> {
|
export class ExtensionConfig<C> implements IExtensionConfig<C> {
|
||||||
public template: new() => C;
|
public template: new() => C;
|
||||||
|
|
||||||
constructor(private readonly extensionId: string) {
|
constructor(private readonly extensionFolder: string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConfig(): C {
|
public getConfig(): C {
|
||||||
return Config.Extensions.configs[this.extensionId] as C;
|
return this.findConfig(Config).configs as C;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setTemplate(template: new() => C): void {
|
public setTemplate(template: new() => C): void {
|
||||||
@ -45,8 +56,9 @@ export class ExtensionConfig<C> implements IExtensionConfig<C> {
|
|||||||
if (!this.template) {
|
if (!this.template) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const conf = ConfigClassBuilder.attachPrivateInterface(new this.template());
|
|
||||||
conf.__loadJSONObject(Utils.clone(config.Extensions.configs[this.extensionId] || {}));
|
const confTemplate = ConfigClassBuilder.attachPrivateInterface(new this.template());
|
||||||
config.Extensions.configs[this.extensionId] = conf;
|
const extConf = this.findConfig(config);
|
||||||
|
extConf.configs = confTemplate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import {SQLConnection} from '../database/SQLConnection';
|
|||||||
import {ExtensionObject} from './ExtensionObject';
|
import {ExtensionObject} from './ExtensionObject';
|
||||||
import {ExtensionDecoratorObject} from './ExtensionDecorator';
|
import {ExtensionDecoratorObject} from './ExtensionDecorator';
|
||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
|
import {ServerExtensionsEntryConfig} from '../../../common/config/private/subconfigs/ServerExtensionsConfig';
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const exec = util.promisify(require('child_process').exec);
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
|
||||||
@ -70,13 +71,23 @@ export class ExtensionManager implements IObjectManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config.Extensions.list = fs
|
|
||||||
|
const extList = fs
|
||||||
.readdirSync(ProjectPath.ExtensionFolder)
|
.readdirSync(ProjectPath.ExtensionFolder)
|
||||||
.filter((f): boolean =>
|
.filter((f): boolean =>
|
||||||
fs.statSync(path.join(ProjectPath.ExtensionFolder, f)).isDirectory()
|
fs.statSync(path.join(ProjectPath.ExtensionFolder, f)).isDirectory()
|
||||||
);
|
);
|
||||||
Config.Extensions.list.sort();
|
extList.sort();
|
||||||
Logger.debug(LOG_TAG, 'Extensions found ', JSON.stringify(Config.Extensions.list));
|
|
||||||
|
// delete not existing extensions
|
||||||
|
Config.Extensions.extensions = Config.Extensions.extensions.filter(ec => extList.indexOf(ec.path) !== -1);
|
||||||
|
|
||||||
|
// 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)));
|
||||||
|
|
||||||
|
Logger.debug(LOG_TAG, 'Extensions found ', JSON.stringify(Config.Extensions.extensions.map(ec => ec.path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private createUniqueExtensionObject(name: string, folder: string): IExtensionObject<unknown> {
|
private createUniqueExtensionObject(name: string, folder: string): IExtensionObject<unknown> {
|
||||||
@ -95,9 +106,13 @@ export class ExtensionManager implements IObjectManager {
|
|||||||
|
|
||||||
private async initExtensions() {
|
private async initExtensions() {
|
||||||
|
|
||||||
for (let i = 0; i < Config.Extensions.list.length; ++i) {
|
for (let i = 0; i < Config.Extensions.extensions.length; ++i) {
|
||||||
const extFolder = Config.Extensions.list[i];
|
const extFolder = Config.Extensions.extensions[i].path;
|
||||||
let extName = extFolder;
|
let extName = extFolder;
|
||||||
|
|
||||||
|
if(Config.Extensions.extensions[i].enabled === false){
|
||||||
|
Logger.silly(LOG_TAG, `Skipping ${extFolder} initiation. Extension is disabled.`);
|
||||||
|
}
|
||||||
const extPath = path.join(ProjectPath.ExtensionFolder, extFolder);
|
const extPath = path.join(ProjectPath.ExtensionFolder, extFolder);
|
||||||
const serverExtPath = path.join(extPath, 'server.js');
|
const serverExtPath = path.join(extPath, 'server.js');
|
||||||
const packageJsonPath = path.join(extPath, 'package.json');
|
const packageJsonPath = path.join(extPath, 'package.json');
|
||||||
@ -107,10 +122,14 @@ export class ExtensionManager implements IObjectManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fs.existsSync(packageJsonPath)) {
|
if (fs.existsSync(packageJsonPath)) {
|
||||||
Logger.silly(LOG_TAG, `Running: "npm install --prefer-offline --no-audit --progress=false --omit=dev" in ${extPath}`);
|
if (fs.existsSync(path.join(extPath, 'node_modules'))) {
|
||||||
await exec('npm install --no-audit --progress=false --omit=dev', {
|
Logger.debug(LOG_TAG, `node_modules folder exists. Skipping "npm install".`);
|
||||||
cwd: extPath
|
} 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
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const pkg = require(packageJsonPath);
|
const pkg = require(packageJsonPath);
|
||||||
if (pkg.name) {
|
if (pkg.name) {
|
||||||
@ -122,7 +141,7 @@ export class ExtensionManager implements IObjectManager {
|
|||||||
const ext = require(serverExtPath);
|
const ext = require(serverExtPath);
|
||||||
if (typeof ext?.init === 'function') {
|
if (typeof ext?.init === 'function') {
|
||||||
Logger.debug(LOG_TAG, 'Running init on extension: ' + extFolder);
|
Logger.debug(LOG_TAG, 'Running init on extension: ' + extFolder);
|
||||||
await ext?.init(this.createUniqueExtensionObject(extName, extPath));
|
await ext?.init(this.createUniqueExtensionObject(extName, extFolder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Config.Extensions.cleanUpUnusedTables) {
|
if (Config.Extensions.cleanUpUnusedTables) {
|
||||||
|
@ -26,7 +26,7 @@ export class ExtensionObject<C> implements IExtensionObject<C> {
|
|||||||
events: IExtensionEvents) {
|
events: IExtensionEvents) {
|
||||||
const logger = createLoggerWrapper(`[Extension][${extensionId}]`);
|
const logger = createLoggerWrapper(`[Extension][${extensionId}]`);
|
||||||
this._app = new ExtensionApp();
|
this._app = new ExtensionApp();
|
||||||
this.config = new ExtensionConfig<C>(extensionId);
|
this.config = new ExtensionConfig<C>(folder);
|
||||||
this.db = new ExtensionDB(logger);
|
this.db = new ExtensionDB(logger);
|
||||||
this.paths = ProjectPath;
|
this.paths = ProjectPath;
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
|
@ -100,7 +100,6 @@ export class TopPickSendJob extends Job<{
|
|||||||
arr.findIndex(m => MediaDTOUtils.equals(m, value)) === index);
|
arr.findIndex(m => MediaDTOUtils.equals(m, value)) === index);
|
||||||
|
|
||||||
this.Progress.Processed++;
|
this.Progress.Processed++;
|
||||||
// console.log(this.mediaList);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,14 +67,14 @@ export class Server {
|
|||||||
await ConfigDiagnostics.runDiagnostics();
|
await ConfigDiagnostics.runDiagnostics();
|
||||||
Logger.verbose(
|
Logger.verbose(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
'using config from ' +
|
() => 'using config from ' +
|
||||||
(
|
(
|
||||||
ConfigClassBuilder.attachPrivateInterface(Config)
|
ConfigClassBuilder.attachPrivateInterface(Config)
|
||||||
.__options as ConfigClassOptions<ServerConfig>
|
.__options as ConfigClassOptions<ServerConfig>
|
||||||
).configPath +
|
).configPath +
|
||||||
':'
|
':'
|
||||||
);
|
);
|
||||||
Logger.verbose(LOG_TAG, JSON.stringify(Config.toJSON({attachDescription: false}), (k, v) => {
|
Logger.verbose(LOG_TAG, () => JSON.stringify(Config.toJSON({attachDescription: false}), (k, v) => {
|
||||||
const MAX_LENGTH = 80;
|
const MAX_LENGTH = 80;
|
||||||
if (typeof v === 'string' && v.length > MAX_LENGTH) {
|
if (typeof v === 'string' && v.length > MAX_LENGTH) {
|
||||||
v = v.slice(0, MAX_LENGTH - 3) + '...';
|
v = v.slice(0, MAX_LENGTH - 3) + '...';
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
} from '../../entities/job/JobScheduleDTO';
|
} from '../../entities/job/JobScheduleDTO';
|
||||||
import {
|
import {
|
||||||
ClientConfig,
|
ClientConfig,
|
||||||
ClientExtensionsConfig,
|
|
||||||
ClientGPXCompressingConfig,
|
ClientGPXCompressingConfig,
|
||||||
ClientMediaConfig,
|
ClientMediaConfig,
|
||||||
ClientMetaFileConfig,
|
ClientMetaFileConfig,
|
||||||
@ -30,7 +29,8 @@ import {SearchQueryDTO, SearchQueryTypes, TextSearch,} from '../../entities/Sear
|
|||||||
import {SortByTypes} from '../../entities/SortingMethods';
|
import {SortByTypes} from '../../entities/SortingMethods';
|
||||||
import {UserRoles} from '../../entities/UserDTO';
|
import {UserRoles} from '../../entities/UserDTO';
|
||||||
import {MediaPickDTO} from '../../entities/MediaPickDTO';
|
import {MediaPickDTO} from '../../entities/MediaPickDTO';
|
||||||
import {MessagingConfig} from './MessagingConfig';
|
import {ServerExtensionsConfig} from './subconfigs/ServerExtensionsConfig';
|
||||||
|
import {MessagingConfig} from './subconfigs/MessagingConfig';
|
||||||
|
|
||||||
declare let $localize: (s: TemplateStringsArray) => string;
|
declare let $localize: (s: TemplateStringsArray) => string;
|
||||||
|
|
||||||
@ -966,35 +966,6 @@ export class ServerServiceConfig extends ClientServiceConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SubConfigClass<TAGS>({softReadonly: true})
|
|
||||||
export class ServerExtensionsConfig extends ClientExtensionsConfig {
|
|
||||||
|
|
||||||
@ConfigProperty({
|
|
||||||
tags: {
|
|
||||||
name: $localize`Extension folder`,
|
|
||||||
priority: ConfigPriority.underTheHood,
|
|
||||||
dockerSensitive: true
|
|
||||||
},
|
|
||||||
description: $localize`Folder where the app stores the extensions. Extensions live in their sub-folders.`,
|
|
||||||
})
|
|
||||||
folder: string = 'extensions';
|
|
||||||
|
|
||||||
@ConfigProperty({volatile: true})
|
|
||||||
list: string[] = [];
|
|
||||||
|
|
||||||
@ConfigProperty({type: 'object'})
|
|
||||||
configs: Record<string, unknown> = {};
|
|
||||||
|
|
||||||
@ConfigProperty({
|
|
||||||
tags: {
|
|
||||||
name: $localize`Clean up unused tables`,
|
|
||||||
priority: ConfigPriority.underTheHood,
|
|
||||||
},
|
|
||||||
description: $localize`Automatically removes all tables from the DB that are not used anymore.`,
|
|
||||||
})
|
|
||||||
cleanUpUnusedTables: boolean = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubConfigClass({softReadonly: true})
|
@SubConfigClass({softReadonly: true})
|
||||||
export class ServerEnvironmentConfig {
|
export class ServerEnvironmentConfig {
|
||||||
@ConfigProperty({volatile: true})
|
@ConfigProperty({volatile: true})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
||||||
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
|
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
|
||||||
import {ConfigPriority, TAGS} from '../public/ClientConfig';
|
import {ConfigPriority, TAGS} from '../../public/ClientConfig';
|
||||||
|
|
||||||
declare let $localize: (s: TemplateStringsArray) => string;
|
declare let $localize: (s: TemplateStringsArray) => string;
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
||||||
|
import {ConfigProperty, SubConfigClass} from 'typeconfig/common';
|
||||||
|
import {ClientExtensionsConfig, ConfigPriority, TAGS} from '../../public/ClientConfig';
|
||||||
|
import {GenericConfigType} from 'typeconfig/src/GenericConfigType';
|
||||||
|
|
||||||
|
@SubConfigClass<TAGS>({softReadonly: true})
|
||||||
|
export class ServerExtensionsEntryConfig {
|
||||||
|
|
||||||
|
constructor(path: string = '') {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Enabled`,
|
||||||
|
priority: ConfigPriority.advanced,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
enabled: boolean = true;
|
||||||
|
|
||||||
|
@ConfigProperty({
|
||||||
|
readonly: true,
|
||||||
|
tags: {
|
||||||
|
name: $localize`Extension folder`,
|
||||||
|
priority: ConfigPriority.underTheHood,
|
||||||
|
},
|
||||||
|
description: $localize`Folder where the app stores all extensions. Individual extensions live in their own sub-folders.`,
|
||||||
|
})
|
||||||
|
path: string = '';
|
||||||
|
|
||||||
|
@ConfigProperty({
|
||||||
|
type: GenericConfigType,
|
||||||
|
tags: {
|
||||||
|
name: $localize`Config`,
|
||||||
|
priority: ConfigPriority.advanced
|
||||||
|
}
|
||||||
|
})
|
||||||
|
configs: GenericConfigType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubConfigClass<TAGS>({softReadonly: true})
|
||||||
|
export class ServerExtensionsConfig extends ClientExtensionsConfig {
|
||||||
|
|
||||||
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Extension folder`,
|
||||||
|
priority: ConfigPriority.underTheHood,
|
||||||
|
dockerSensitive: true
|
||||||
|
},
|
||||||
|
description: $localize`Folder where the app stores all extensions. Individual extensions live in their own sub-folders.`,
|
||||||
|
})
|
||||||
|
folder: string = 'extensions';
|
||||||
|
|
||||||
|
|
||||||
|
@ConfigProperty({
|
||||||
|
arrayType: ServerExtensionsEntryConfig,
|
||||||
|
tags: {
|
||||||
|
name: $localize`Installed extensions`,
|
||||||
|
priority: ConfigPriority.advanced
|
||||||
|
}
|
||||||
|
})
|
||||||
|
extensions: ServerExtensionsEntryConfig[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
@ConfigProperty({
|
||||||
|
tags: {
|
||||||
|
name: $localize`Clean up unused tables`,
|
||||||
|
priority: ConfigPriority.underTheHood,
|
||||||
|
},
|
||||||
|
description: $localize`Automatically removes all tables from the DB that are not used anymore.`,
|
||||||
|
})
|
||||||
|
cleanUpUnusedTables: boolean = true;
|
||||||
|
}
|
@ -11,7 +11,7 @@ declare let $localize: (s: TemplateStringsArray) => string;
|
|||||||
if (typeof $localize === 'undefined') {
|
if (typeof $localize === 'undefined') {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @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
|
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,
|
uiDisabled: (sb: ThemesConfig) => !sb.enabled,
|
||||||
relevant: (c: ThemesConfig) => c.selectedTheme !== 'default',
|
relevant: (c: ThemesConfig) => c.selectedTheme !== 'default',
|
||||||
uiType: 'SelectedThemeSettings'
|
|
||||||
} as TAGS,
|
} as TAGS,
|
||||||
description: $localize`Adds these css settings as it is to the end of the body tag of the page.`
|
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[] = [];
|
public readonly configPaths: string[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthenticationService,
|
private authService: AuthenticationService,
|
||||||
private navigation: NavigationService,
|
private navigation: NavigationService,
|
||||||
public viewportScroller: ViewportScroller,
|
public viewportScroller: ViewportScroller,
|
||||||
public notificationService: NotificationService,
|
public notificationService: NotificationService,
|
||||||
public settingsService: SettingsService,
|
public settingsService: SettingsService,
|
||||||
private piTitleService: PiTitleService
|
private piTitleService: PiTitleService
|
||||||
) {
|
) {
|
||||||
this.configPriorities = enumToTranslatedArray(ConfigPriority);
|
this.configPriorities = enumToTranslatedArray(ConfigPriority);
|
||||||
this.configStyles = enumToTranslatedArray(ConfigStyle);
|
this.configStyles = enumToTranslatedArray(ConfigStyle);
|
||||||
@ -50,8 +50,8 @@ export class AdminComponent implements OnInit, AfterViewInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (
|
if (
|
||||||
!this.authService.isAuthenticated() ||
|
!this.authService.isAuthenticated() ||
|
||||||
this.authService.user.value.role < UserRoles.Admin
|
this.authService.user.value.role < UserRoles.Admin
|
||||||
) {
|
) {
|
||||||
this.navigation.toLogin();
|
this.navigation.toLogin();
|
||||||
return;
|
return;
|
||||||
|
@ -167,7 +167,6 @@ export class GallerySearchFieldBaseComponent
|
|||||||
0,
|
0,
|
||||||
this.rawSearchText.length - token.current.length
|
this.rawSearchText.length - token.current.length
|
||||||
) + item.queryHint;
|
) + item.queryHint;
|
||||||
console.log('aa');
|
|
||||||
this.onChange();
|
this.onChange();
|
||||||
this.emptyAutoComplete();
|
this.emptyAutoComplete();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
import {propertyTypes} from 'typeconfig/common';
|
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
|
* Configuration in these class have a custom UI
|
||||||
@ -8,6 +18,13 @@ export class CustomSettingsEntries {
|
|||||||
public static readonly entries = [
|
public static readonly entries = [
|
||||||
{c: ClientSortingConfig, name: 'ClientSortingConfig'},
|
{c: ClientSortingConfig, name: 'ClientSortingConfig'},
|
||||||
{c: ClientGroupingConfig, name: 'ClientGroupingConfig'},
|
{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'},
|
{c: SVGIconConfig, name: 'SVGIconConfig'},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -46,7 +63,7 @@ export class CustomSettingsEntries {
|
|||||||
return cN;
|
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);
|
const c = this.getConfigName(s);
|
||||||
return this.entries.findIndex(e => e.name == c) !== -1;
|
return this.entries.findIndex(e => e.name == c) !== -1;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
[hidden]="shouldHide">
|
[hidden]="shouldHide">
|
||||||
<label class="col-sm-3 col-md-2 control-label" [for]="idName">{{name}}</label>
|
<label class="col-sm-3 col-md-2 control-label" [for]="idName">{{name}}</label>
|
||||||
<div class="col-12 col-sm">
|
<div class="col-12 col-sm">
|
||||||
|
|
||||||
<div class="input-group" [ngSwitch]="uiType">
|
<div class="input-group" [ngSwitch]="uiType">
|
||||||
<app-gallery-search-field
|
<app-gallery-search-field
|
||||||
*ngSwitchCase="'SearchQuery'"
|
*ngSwitchCase="'SearchQuery'"
|
||||||
@ -29,7 +28,9 @@
|
|||||||
style="flex: 1"
|
style="flex: 1"
|
||||||
*ngSwitchCase="'StringInput'">
|
*ngSwitchCase="'StringInput'">
|
||||||
<input
|
<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"
|
[placeholder]="placeholder"
|
||||||
[title]="title"
|
[title]="title"
|
||||||
[(ngModel)]="StringValue"
|
[(ngModel)]="StringValue"
|
||||||
@ -131,7 +132,7 @@
|
|||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
rows="5"
|
rows="5"
|
||||||
*ngSwitchCase="'SelectedThemeSettings'"
|
*ngSwitchCase="'ThemeConfig-Array'"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
[title]="title"
|
[title]="title"
|
||||||
@ -168,7 +169,7 @@
|
|||||||
|
|
||||||
<app-settings-workflow
|
<app-settings-workflow
|
||||||
class="w-100"
|
class="w-100"
|
||||||
*ngSwitchCase="'JobScheduleConfig'"
|
*ngSwitchCase="'JobScheduleConfig-Array'"
|
||||||
[(ngModel)]="state.value"
|
[(ngModel)]="state.value"
|
||||||
[id]="idName"
|
[id]="idName"
|
||||||
[name]="idName"
|
[name]="idName"
|
||||||
@ -252,7 +253,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngSwitchCase="'MapLayers'">
|
<ng-container *ngSwitchCase="'MapLayers-Array'">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -295,7 +296,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngSwitchCase="'MapPathGroupThemeConfig'">
|
<ng-container *ngSwitchCase="'MapPathGroupThemeConfig-Array'">
|
||||||
<div class="container">
|
<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" *ngFor="let val of state.value; index as i; last as isLast">
|
||||||
<div class="row mt-1 mb-1 bg-body-tertiary">
|
<div class="row mt-1 mb-1 bg-body-tertiary">
|
||||||
@ -357,7 +358,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngSwitchCase="'MapPathGroupConfig'">
|
<ng-container *ngSwitchCase="'MapPathGroupConfig-Array'">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="bg-body-tertiary row mt-1 mb-1" *ngFor="let arr of state.value; let i = index">
|
<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">
|
<div class="row mt-1 mb-1 me-0 ms-0 pe-0 ps-0">
|
||||||
@ -403,7 +404,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngSwitchCase="'NavigationLinkConfig'">
|
<ng-container *ngSwitchCase="'NavigationLinkConfig-Array'">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mt-1 mb-1 bg-body-tertiary" *ngFor="let link of state.value; let i = index">
|
<div class="row mt-1 mb-1 bg-body-tertiary" *ngFor="let link of state.value; let i = index">
|
||||||
<div class="col ps-0">
|
<div class="col ps-0">
|
||||||
@ -468,7 +469,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngSwitchCase="'UserConfig'">
|
|
||||||
|
<ng-container *ngSwitchCase="'UserConfig-Array'">
|
||||||
<div class="container ps-0 pe-0">
|
<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">
|
<div class="row ms-0 me-0 mt-1 mb-1 bg-body-tertiary" *ngFor="let item of state.value; let i = index">
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import {enumToTranslatedArray} from '../../../EnumTranslations';
|
|||||||
import {BsModalService} from 'ngx-bootstrap/modal';
|
import {BsModalService} from 'ngx-bootstrap/modal';
|
||||||
import {CustomSettingsEntries} from '../CustomSettingsEntries';
|
import {CustomSettingsEntries} from '../CustomSettingsEntries';
|
||||||
import {GroupByTypes, SortByTypes} from '../../../../../../common/entities/SortingMethods';
|
import {GroupByTypes, SortByTypes} from '../../../../../../common/entities/SortingMethods';
|
||||||
|
import { ServerExtensionsEntryConfig } from '../../../../../../common/config/private/subconfigs/ServerExtensionsConfig';
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
shouldHide(): boolean;
|
shouldHide(): boolean;
|
||||||
@ -232,6 +233,8 @@ export class SettingsEntryComponent
|
|||||||
this.arrayType = 'MapPathGroupThemeConfig';
|
this.arrayType = 'MapPathGroupThemeConfig';
|
||||||
} else if (this.state.arrayType === UserConfig) {
|
} else if (this.state.arrayType === UserConfig) {
|
||||||
this.arrayType = 'UserConfig';
|
this.arrayType = 'UserConfig';
|
||||||
|
} else if (this.state.arrayType === ServerExtensionsEntryConfig) {
|
||||||
|
this.arrayType = 'ServerExtensionsEntryConfig';
|
||||||
} else if (this.state.arrayType === JobScheduleConfig) {
|
} else if (this.state.arrayType === JobScheduleConfig) {
|
||||||
this.arrayType = 'JobScheduleConfig';
|
this.arrayType = 'JobScheduleConfig';
|
||||||
} else {
|
} else {
|
||||||
@ -253,8 +256,9 @@ export class SettingsEntryComponent
|
|||||||
this.arrayType !== 'MapLayers' &&
|
this.arrayType !== 'MapLayers' &&
|
||||||
this.arrayType !== 'NavigationLinkConfig' &&
|
this.arrayType !== 'NavigationLinkConfig' &&
|
||||||
this.arrayType !== 'MapPathGroupConfig' &&
|
this.arrayType !== 'MapPathGroupConfig' &&
|
||||||
|
this.arrayType !== 'ServerExtensionsEntryConfig' &&
|
||||||
this.arrayType !== 'MapPathGroupThemeConfig' &&
|
this.arrayType !== 'MapPathGroupThemeConfig' &&
|
||||||
this.arrayType !== 'JobScheduleConfig' &&
|
this.arrayType !== 'JobScheduleConfig-Array' &&
|
||||||
this.arrayType !== 'UserConfig') {
|
this.arrayType !== 'UserConfig') {
|
||||||
this.uiType = 'StringInput';
|
this.uiType = 'StringInput';
|
||||||
}
|
}
|
||||||
@ -463,7 +467,6 @@ export class SettingsEntryComponent
|
|||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
console.log(reader.result);
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const doc = parser.parseFromString(reader.result as string, 'image/svg+xml');
|
const doc = parser.parseFromString(reader.result as string, 'image/svg+xml');
|
||||||
try {
|
try {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="d-inline-block mb-0">
|
<h5 class="d-inline-block mb-0">
|
||||||
<ng-icon [name]="icon"></ng-icon>
|
<ng-icon [name]="icon"></ng-icon>
|
||||||
{{Name}}
|
{{ Name }}
|
||||||
</h5>
|
</h5>
|
||||||
<div *ngIf="states.value.enabled !== undefined" class="float-end p-0">
|
<div *ngIf="states.value.enabled !== undefined" class="float-end p-0">
|
||||||
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<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 *ngIf="states.value.enabled !== false">
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngTemplateOutlet="Recursion; context:{ rStates: states,topLevel:true,confPath:ConfigPath,skipJobs:true }"
|
*ngTemplateOutlet="Recursion; context:{ rStates: states,topLevel:true,confPath:ConfigPath,skipJobs:true }"
|
||||||
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<div class="panel-info"
|
<div class="panel-info"
|
||||||
*ngIf="states.value.enabled === false">
|
*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>
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col-auto" *ngIf="states.tags?.uiJob && !states.tags?.uiJob[0].description">
|
<div class="col-auto" *ngIf="states.tags?.uiJob && !states.tags?.uiJob[0].description">
|
||||||
@ -72,46 +72,71 @@
|
|||||||
let-confPath="confPath">
|
let-confPath="confPath">
|
||||||
<div class="alert alert-secondary" role="alert"
|
<div class="alert alert-secondary" role="alert"
|
||||||
*ngIf="rStates.description && settingsService.configStyle == ConfigStyle.full">
|
*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"
|
<a *ngIf="rStates.tags?.githubIssue"
|
||||||
[href]="'https://github.com/bpatrik/pigallery2/issues/'+rStates.tags?.githubIssue">
|
[href]="'https://github.com/bpatrik/pigallery2/issues/'+rStates.tags?.githubIssue">
|
||||||
<ng-container i18n>See</ng-container>
|
<ng-container i18n>See</ng-container>
|
||||||
#{{rStates.tags?.githubIssue}}.</a>
|
#{{ rStates.tags?.githubIssue }}.</a>
|
||||||
</div>
|
</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
|
<!-- is array -->
|
||||||
*ngIf="(ck!=='enabled' || !topLevel) && !isExpandableConfig(rStates.value.__state[ck])"
|
<ng-container *ngIf="rStates.value.__state[ck].isConfigArrayType && isExpandableArrayConfig(rStates.value.__state[ck])">
|
||||||
[name]="confPath+'_'+ck"
|
<div class="row">
|
||||||
[ngModel]="rStates?.value.__state[ck]">
|
<div class="col-auto">
|
||||||
</app-settings-entry>
|
<h5>{{ rStates?.value.__state[ck].tags?.name || ck }}</h5>
|
||||||
<ng-container *ngIf="isExpandableConfig(rStates.value.__state[ck])">
|
</div>
|
||||||
<div class="card mt-2 mb-2" *ngIf="topLevel && rStates?.value.__state[ck].tags?.uiIcon"
|
<div class="col mt-2">
|
||||||
[id]="ConfigPath+'.'+ck">
|
<div class="row mt-2" *ngFor="let entry of rStates.value.__state[ck].value; let i = index">
|
||||||
<div class="card-body">
|
<hr/>
|
||||||
<h5 class="card-title">
|
<ng-container
|
||||||
<ng-icon [name]="rStates?.value.__state[ck].tags?.uiIcon"></ng-icon>
|
*ngTemplateOutlet="Recursion; context:{ rStates: {value: rStates.value.__state[ck].value[i]}, confPath:confPath+'.'+ck+'.'+i }"
|
||||||
{{rStates?.value.__state[ck].tags?.name || ck}}
|
></ng-container>
|
||||||
</h5>
|
</div>
|
||||||
<ng-container
|
|
||||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
|
||||||
></ng-container>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="!topLevel || !rStates?.value.__state[ck].tags?.uiIcon">
|
</ng-container>
|
||||||
<div class="row mt-2">
|
|
||||||
<div class="col-auto">
|
<ng-container *ngIf="!rStates.value.__state[ck].isConfigArrayType || !isExpandableArrayConfig(rStates.value.__state[ck])">
|
||||||
<h5>{{rStates?.value.__state[ck].tags?.name || ck}}</h5>
|
|
||||||
</div>
|
<!-- simple entries or complex once's but with custom UI--->
|
||||||
<div class="col">
|
<app-settings-entry
|
||||||
<hr/>
|
*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>
|
</div>
|
||||||
<div class="mt-2">
|
<!-- Sub category without header and menu item -->
|
||||||
<ng-container
|
<ng-container *ngIf="!topLevel || !rStates?.value.__state[ck].tags?.uiIcon">
|
||||||
*ngTemplateOutlet="Recursion; context:{ rStates: rStates.value.__state[ck], confPath:confPath+'.'+ck }"
|
<div class="row mt-2">
|
||||||
></ng-container>
|
<div class="col-auto">
|
||||||
</div>
|
<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>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@ -125,12 +150,14 @@
|
|||||||
></ng-container>
|
></ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #JobTemplate let-uiJob="uiJob">
|
<ng-template #JobTemplate let-uiJob="uiJob">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<ng-container *ngFor="let job of uiJob; let i = index">
|
<ng-container *ngFor="let job of uiJob; let i = index">
|
||||||
<div class="alert alert-secondary" role="alert"
|
<div class="alert alert-secondary" role="alert"
|
||||||
*ngIf="job.description && settingsService.configStyle == ConfigStyle.full">
|
*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>
|
</div>
|
||||||
<app-settings-job-button
|
<app-settings-job-button
|
||||||
*ngIf="!job.relevant || job.relevant(settingsService.settings | async)"
|
*ngIf="!job.relevant || job.relevant(settingsService.settings | async)"
|
||||||
@ -144,6 +171,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #JobProcessTemplate let-uiJob="uiJob">
|
<ng-template #JobProcessTemplate let-uiJob="uiJob">
|
||||||
<div>
|
<div>
|
||||||
<ng-container *ngFor="let job of uiJob">
|
<ng-container *ngFor="let job of uiJob">
|
||||||
|
@ -79,11 +79,11 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
public readonly ConfigStyle = ConfigStyle;
|
public readonly ConfigStyle = ConfigStyle;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected authService: AuthenticationService,
|
protected authService: AuthenticationService,
|
||||||
private navigation: NavigationService,
|
private navigation: NavigationService,
|
||||||
protected notification: NotificationService,
|
protected notification: NotificationService,
|
||||||
public settingsService: SettingsService,
|
public settingsService: SettingsService,
|
||||||
public jobsService: ScheduledJobsService,
|
public jobsService: ScheduledJobsService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
this.nestedConfigs = [];
|
this.nestedConfigs = [];
|
||||||
for (const key of this.getKeys(this.states)) {
|
for (const key of this.getKeys(this.states)) {
|
||||||
if (this.states.value.__state[key].isConfigType &&
|
if (this.states.value.__state[key].isConfigType &&
|
||||||
this.states?.value.__state[key].tags?.uiIcon) {
|
this.states?.value.__state[key].tags?.uiIcon) {
|
||||||
this.nestedConfigs.push({
|
this.nestedConfigs.push({
|
||||||
id: this.ConfigPath + '.' + key,
|
id: this.ConfigPath + '.' + key,
|
||||||
name: this.states?.value.__state[key].tags?.name,
|
name: this.states?.value.__state[key].tags?.name,
|
||||||
@ -112,8 +112,8 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this.authService.isAuthenticated() ||
|
!this.authService.isAuthenticated() ||
|
||||||
this.authService.user.value.role < UserRoles.Admin
|
this.authService.user.value.role < UserRoles.Admin
|
||||||
) {
|
) {
|
||||||
this.navigation.toLogin();
|
this.navigation.toLogin();
|
||||||
return;
|
return;
|
||||||
@ -143,7 +143,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
if (sliceFN) {
|
if (sliceFN) {
|
||||||
this.sliceFN = sliceFN;
|
this.sliceFN = sliceFN;
|
||||||
this.settingsSubscription = this.settingsService.settings.subscribe(
|
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 &&
|
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)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if all sub elements are hidden, hide the parent too.
|
// if all sub elements are hidden, hide the parent too.
|
||||||
if (state.isConfigType) {
|
if (state.isConfigType) {
|
||||||
if (state.value && state.value.__state &&
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const forcedVisibility = !(state.tags?.priority > this.settingsService.configPriority ||
|
const forcedVisibility = !(state.tags?.priority > this.settingsService.configPriority ||
|
||||||
//if this value should not change in Docker, lets hide it
|
//if this value should not change in Docker, lets hide it
|
||||||
(this.settingsService.configPriority === ConfigPriority.basic &&
|
(this.settingsService.configPriority === ConfigPriority.basic &&
|
||||||
state.tags?.dockerSensitive && this.settingsService.settings.value.Environment.isDocker));
|
state.tags?.dockerSensitive && this.settingsService.settings.value.Environment.isDocker));
|
||||||
|
|
||||||
if (state.isConfigArrayType) {
|
if (state.isConfigArrayType) {
|
||||||
for (let i = 0; i < state.value?.length; ++i) {
|
for (let i = 0; i < state.value?.length; ++i) {
|
||||||
for (const k of Object.keys(state.value[i].__state)) {
|
for (const k of Object.keys(state.value[i].__state)) {
|
||||||
if (!Utils.equalsFilter(
|
if (!Utils.equalsFilter(
|
||||||
state.value[i]?.__state[k]?.value,
|
state.value[i]?.__state[k]?.value,
|
||||||
state.default[i] ? state.default[i][k] : undefined,
|
state.default[i] ? state.default[i][k] : undefined,
|
||||||
['default', '__propPath', '__created', '__prototype', '__rootConfig'])) {
|
['default', '__propPath', '__created', '__prototype', '__rootConfig'])) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -206,10 +206,10 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
|
|
||||||
|
|
||||||
return (!forcedVisibility &&
|
return (!forcedVisibility &&
|
||||||
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']));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
}
|
}
|
||||||
if (typeof state.original === 'object') {
|
if (typeof state.original === 'object') {
|
||||||
return Utils.equalsFilter(state.value, state.original,
|
return Utils.equalsFilter(state.value, state.original,
|
||||||
['__propPath', '__created', '__prototype', '__rootConfig', '__state']);
|
['__propPath', '__created', '__prototype', '__rootConfig', '__state']);
|
||||||
}
|
}
|
||||||
if (typeof state.original !== 'undefined') {
|
if (typeof state.original !== 'undefined') {
|
||||||
return state.value === state.original;
|
return state.value === state.original;
|
||||||
@ -271,10 +271,18 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
this.getSettings();
|
this.getSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main template should list it
|
||||||
|
* @param c
|
||||||
|
*/
|
||||||
isExpandableConfig(c: ConfigState) {
|
isExpandableConfig(c: ConfigState) {
|
||||||
return c.isConfigType && !CustomSettingsEntries.iS(c);
|
return c.isConfigType && !CustomSettingsEntries.iS(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isExpandableArrayConfig(c: ConfigState) {
|
||||||
|
return c.isConfigArrayType && !CustomSettingsEntries.iS(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async save(): Promise<boolean> {
|
public async save(): Promise<boolean> {
|
||||||
this.inProgress = true;
|
this.inProgress = true;
|
||||||
@ -284,8 +292,8 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
await this.settingsService.updateSettings(state, this.ConfigPath);
|
await this.settingsService.updateSettings(state, this.ConfigPath);
|
||||||
await this.getSettings();
|
await this.getSettings();
|
||||||
this.notification.success(
|
this.notification.success(
|
||||||
this.Name + ' ' + $localize`settings saved`,
|
this.Name + ' ' + $localize`settings saved`,
|
||||||
$localize`Success`
|
$localize`Success`
|
||||||
);
|
);
|
||||||
this.inProgress = false;
|
this.inProgress = false;
|
||||||
return true;
|
return true;
|
||||||
@ -328,7 +336,6 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return (s[a].tags?.name as string || a).localeCompare(s[b].tags?.name || b);
|
return (s[a].tags?.name as string || a).localeCompare(s[b].tags?.name || b);
|
||||||
|
|
||||||
});
|
});
|
||||||
states.keys = keys;
|
states.keys = keys;
|
||||||
return states.keys;
|
return states.keys;
|
||||||
|
Loading…
Reference in New Issue
Block a user