fix(config): align visual editor with backend config semantics

This commit is contained in:
LTbinglingfeng
2026-02-06 18:14:13 +08:00
parent 26fa1ea98e
commit f833f0dfd2
8 changed files with 53 additions and 42 deletions

View File

@@ -891,15 +891,6 @@ export function VisualConfigEditor({ values, disabled = false, onChange }: Visua
onChange={(e) => onChange({ logsMaxTotalSizeMb: e.target.value })}
disabled={disabled}
/>
<Input
label={t('config_management.visual.sections.system.usage_retention_days')}
type="number"
placeholder="30"
value={values.usageRecordsRetentionDays}
onChange={(e) => onChange({ usageRecordsRetentionDays: e.target.value })}
disabled={disabled}
hint={t('config_management.visual.sections.system.usage_retention_hint')}
/>
</SectionGrid>
</div>
</ConfigSection>

View File

@@ -102,6 +102,27 @@ function deepClone<T>(value: T): T {
return JSON.parse(JSON.stringify(value)) as T;
}
function parsePayloadParamValue(raw: unknown): { valueType: PayloadParamValueType; value: string } {
if (typeof raw === 'number') {
return { valueType: 'number', value: String(raw) };
}
if (typeof raw === 'boolean') {
return { valueType: 'boolean', value: String(raw) };
}
if (raw === null || typeof raw === 'object') {
try {
const json = JSON.stringify(raw, null, 2);
return { valueType: 'json', value: json ?? 'null' };
} catch {
return { valueType: 'json', value: String(raw) };
}
}
return { valueType: 'string', value: String(raw ?? '') };
}
function parsePayloadRules(rules: unknown): PayloadRule[] {
if (!Array.isArray(rules)) return [];
@@ -115,19 +136,15 @@ function parsePayloadRules(rules: unknown): PayloadRule[] {
}))
: [],
params: (rule as any)?.params
? Object.entries((rule as any).params as Record<string, unknown>).map(([path, value], pIndex) => ({
id: `param-${index}-${pIndex}`,
path,
valueType:
typeof value === 'number'
? 'number'
: typeof value === 'boolean'
? 'boolean'
: typeof value === 'object'
? 'json'
: 'string',
value: String(value),
}))
? Object.entries((rule as any).params as Record<string, unknown>).map(([path, value], pIndex) => {
const parsedValue = parsePayloadParamValue(value);
return {
id: `param-${index}-${pIndex}`,
path,
valueType: parsedValue.valueType,
value: parsedValue.value,
};
})
: [],
}));
}
@@ -220,7 +237,7 @@ export function useVisualConfig() {
const newValues: VisualConfigValues = {
host: parsed.host || '',
port: String(parsed.port || ''),
port: String(parsed.port ?? ''),
tlsEnable: Boolean(parsed.tls?.enable),
tlsCert: parsed.tls?.cert || '',
@@ -240,14 +257,13 @@ export function useVisualConfig() {
debug: Boolean(parsed.debug),
commercialMode: Boolean(parsed['commercial-mode']),
loggingToFile: Boolean(parsed['logging-to-file']),
logsMaxTotalSizeMb: String(parsed['logs-max-total-size-mb'] || ''),
logsMaxTotalSizeMb: String(parsed['logs-max-total-size-mb'] ?? ''),
usageStatisticsEnabled: Boolean(parsed['usage-statistics-enabled']),
usageRecordsRetentionDays: String(parsed['usage-records-retention-days'] ?? ''),
proxyUrl: parsed['proxy-url'] || '',
forceModelPrefix: Boolean(parsed['force-model-prefix']),
requestRetry: String(parsed['request-retry'] || ''),
maxRetryInterval: String(parsed['max-retry-interval'] || ''),
requestRetry: String(parsed['request-retry'] ?? ''),
maxRetryInterval: String(parsed['max-retry-interval'] ?? ''),
wsAuth: Boolean(parsed['ws-auth']),
quotaSwitchProject: Boolean(parsed['quota-exceeded']?.['switch-project'] ?? true),
@@ -333,11 +349,6 @@ export function useVisualConfig() {
setBoolean(parsed, 'logging-to-file', values.loggingToFile);
setIntFromString(parsed, 'logs-max-total-size-mb', values.logsMaxTotalSizeMb);
setBoolean(parsed, 'usage-statistics-enabled', values.usageStatisticsEnabled);
setIntFromString(
parsed,
'usage-records-retention-days',
values.usageRecordsRetentionDays
);
setString(parsed, 'proxy-url', values.proxyUrl);
setBoolean(parsed, 'force-model-prefix', values.forceModelPrefix);

View File

@@ -882,9 +882,7 @@
"logging_to_file_desc": "Save logs to rotating files",
"usage_statistics": "Usage Statistics",
"usage_statistics_desc": "Collect usage statistics",
"logs_max_size": "Log File Size Limit (MB)",
"usage_retention_days": "Usage Records Retention Days",
"usage_retention_hint": "0 means no limit (no cleanup)"
"logs_max_size": "Log File Size Limit (MB)"
},
"network": {
"title": "Network Configuration",

View File

@@ -882,9 +882,7 @@
"logging_to_file_desc": "将日志保存到滚动文件",
"usage_statistics": "使用统计",
"usage_statistics_desc": "收集使用统计信息",
"logs_max_size": "日志文件大小限制 (MB)",
"usage_retention_days": "使用记录保留天数",
"usage_retention_hint": "0 为无限制(不清理)"
"logs_max_size": "日志文件大小限制 (MB)"
},
"network": {
"title": "网络配置",

View File

@@ -80,9 +80,10 @@ export function ConfigPage() {
try {
const nextContent = activeTab === 'visual' ? applyVisualChangesToYaml(content) : content;
await configFileApi.saveConfigYaml(nextContent);
const latestContent = await configFileApi.fetchConfigYaml();
setDirty(false);
setContent(nextContent);
loadVisualValuesFromYaml(nextContent);
setContent(latestContent);
loadVisualValuesFromYaml(latestContent);
showNotification(t('config_management.save_success'), 'success');
} catch (err: unknown) {
const message = err instanceof Error ? err.message : '';

View File

@@ -48,7 +48,6 @@ export type VisualConfigValues = {
loggingToFile: boolean;
logsMaxTotalSizeMb: string;
usageStatisticsEnabled: boolean;
usageRecordsRetentionDays: string;
proxyUrl: string;
forceModelPrefix: boolean;
requestRetry: string;
@@ -85,7 +84,6 @@ export const DEFAULT_VISUAL_VALUES: VisualConfigValues = {
loggingToFile: false,
logsMaxTotalSizeMb: '',
usageStatisticsEnabled: false,
usageRecordsRetentionDays: '',
proxyUrl: '',
forceModelPrefix: false,
requestRetry: '',