refactor: complete application rewrite with modern UI

This commit is contained in:
sokol
2026-02-19 22:55:26 +03:00
parent 271b530fa1
commit a6cc5a9827
26 changed files with 3036 additions and 794 deletions

View File

@@ -1,158 +1,174 @@
import { Env } from "./Env";
import { Env } from './Env';
/**
* Configuration template with placeholder support
*/
export class ConfigTemplate {
public static Empty: ConfigTemplate = new ConfigTemplate();
public static readonly Empty: ConfigTemplate = new ConfigTemplate();
constructor(text: string = "") {
this._contentText = text;
this.extractParams();
private _contentText: string;
private _params: string[];
constructor(contentText: string = '') {
this._contentText = contentText;
this._params = this.extractParams();
}
private _contentText: string = "";
private _params: string[] = [];
public get content(): string {
return this._contentText;
}
/**
* Backward compatibility getter
*/
public get Params(): string[] {
return this.params;
}
public get params(): string[] {
return [...this._params];
}
private extractParams() {
let regex = /@(\w+)@/g;
let matches;
let paramsSet = new Set<string>();
/**
* Extracts @placeholder@ patterns from template content
*/
private extractParams(): string[] {
const regex = /@(\w+)@/g;
const paramsSet = new Set<string>();
let match;
while ((matches = regex.exec(this._contentText)) !== null) {
if (matches.length > 1) {
paramsSet.add(matches[1]);
}
while ((match = regex.exec(this._contentText)) !== null) {
paramsSet.add(match[1]);
}
this._params = Array.from(paramsSet);
return Array.from(paramsSet);
}
}
/**
* Main configuration container
*/
export class Config {
public static get ENV_NAME_PARAM(): string { return "env_name" };
public static readonly ENV_NAME_PARAM = 'env_name';
public envs: Env[] = [];
public template: ConfigTemplate = ConfigTemplate.Empty;
addEnvs(envs: Env[]) {
/**
* Sets environments (backward compatibility)
*/
public addEnvs(envs: Env[]): void {
this.envs = envs;
}
addTemplate(text: string) {
this.template = new ConfigTemplate(text);
/**
* Sets environments
*/
public setEnvs(envs: Env[]): void {
this.envs = envs;
}
getTemplateAsJson(): string {
/**
* Sets template content (backward compatibility)
*/
public addTemplate(content: string): void {
this.setTemplate(content);
}
/**
* Sets template content
*/
public setTemplate(content: string): void {
this.template = new ConfigTemplate(content);
}
/**
* Gets template as JSON string
*/
public getTemplateAsJson(): string {
try {
return this.template.content ;
} catch (error) {
console.error("Error converting template content to JSON:", error);
return "{}";
return this.template.content;
} catch {
return '{}';
}
}
/**
* Updates the template JSON by adding/updating params from the given environment.
* Params are added as "!!! paramName": "@paramName@" placeholder pairs.
* If a param's @placeholder@ already exists in template, it won't be added.
* Existing template content is preserved.
* Updates template by adding placeholders for environment params
*/
updateTemplateFromEnv(env: Env) {
public updateTemplateFromEnv(env: Env): void {
let templateObj: Record<string, any> = {};
// Try to parse existing template as JSON
// Try to parse existing template
try {
if (this.template.content.trim()) {
templateObj = JSON.parse(this.template.content);
}
} catch (e) {
// If parsing fails, start with empty object
console.warn("Template is not valid JSON, starting fresh");
} catch {
// Start fresh if invalid JSON
}
// Add/update params from the environment as placeholders
// Add placeholders for params that don't exist yet
for (const param of env.params) {
if (param.name && param.name.trim() !== "") {
const placeholderValue = `@${param.name}@`;
// Check if this placeholder already exists anywhere in the template
const placeholderAlreadyExists = this.template.content.includes(placeholderValue);
if (!placeholderAlreadyExists) {
const placeholderKey = `!!! ${param.name}`;
templateObj[placeholderKey] = placeholderValue;
if (param.name && param.name.trim()) {
const placeholder = `@${param.name}@`;
if (!this.template.content.includes(placeholder)) {
templateObj[`!!! ${param.name}`] = placeholder;
}
}
}
// Convert back to formatted JSON string
const newTemplateContent = JSON.stringify(templateObj, null, 4);
this.template = new ConfigTemplate(newTemplateContent);
this.template = new ConfigTemplate(JSON.stringify(templateObj, null, 4));
}
validateParams(): string[] {
const envKeys = this.envs.map(env => env.params.map(param => param.name)).flat();
const missingParams = this.template.Params.filter(param => param != Config.ENV_NAME_PARAM && !envKeys.includes(param));
/**
* Validates that all template placeholders have corresponding params (backward compatibility)
*/
public validateParams(): string[] {
return this.validatePlaceholders();
}
if (missingParams.length > 0) {
console.error("Template: missing parameters in environments:", missingParams);
/**
* Validates that all template placeholders have corresponding params
*/
public validatePlaceholders(): string[] {
const defaultEnv = this.envs.find(e => e.name === 'DEFAULT');
const customEnvs = this.envs.filter(e => e.name !== 'DEFAULT');
// Collect param names from DEFAULT
const defaultParamNames = new Set(
defaultEnv?.getParamNames() || []
);
// Collect param names from all custom envs
const customParamNames = new Set(
customEnvs.flatMap(e => e.getParamNames())
);
// Find missing placeholders
const missingParams: string[] = [];
for (const placeholder of this.template.params) {
if (placeholder === Config.ENV_NAME_PARAM) continue;
const inDefault = defaultParamNames.has(placeholder);
const inCustom = customParamNames.has(placeholder);
if (!inDefault && !inCustom) {
missingParams.push(placeholder);
}
}
return missingParams;
}
/**
* Validates that all @placeholders@ in template have corresponding params.
* Checks DEFAULT env first, then all custom envs.
* Returns array of placeholder names that are not defined.
* Creates a deep copy of the config
*/
validatePlaceholders(): string[] {
const defaultEnv = this.envs.find(e => e.name === "DEFAULT");
const customEnvs = this.envs.filter(e => e.name !== "DEFAULT");
// Collect all param names from DEFAULT
const defaultParamNames = new Set(
defaultEnv?.params.map(p => p.name).filter(n => n && n.trim() !== "") || []
);
// Collect all param names from all custom envs
const customParamNames = new Set(
customEnvs.flatMap(e => e.params.map(p => p.name).filter(n => n && n.trim() !== ""))
);
// Extract all @placeholders@ from template
const placeholderRegex = /@(\w+)@/g;
const placeholdersInTemplate = new Set<string>();
let match;
while ((match = placeholderRegex.exec(this.template.content)) !== null) {
placeholdersInTemplate.add(match[1]);
}
// Find placeholders that don't have matching params
const missingParams: string[] = [];
for (const placeholder of placeholdersInTemplate) {
if (placeholder === Config.ENV_NAME_PARAM) continue; // Skip built-in
// Check if exists in DEFAULT or in ANY custom env
const inDefault = defaultParamNames.has(placeholder);
const inCustom = customParamNames.has(placeholder);
// Valid if: in DEFAULT, or in at least one custom env
if (!inDefault && !inCustom) {
missingParams.push(placeholder);
}
}
return missingParams;
public clone(): Config {
const cloned = new Config();
cloned.envs = [...this.envs];
cloned.template = this.template;
return cloned;
}
}