feat: add visual configuration editor and YAML handling

- Implemented a new hook `useVisualConfig` for managing visual configuration state and YAML parsing.
- Added types for visual configuration in `visualConfig.ts`.
- Enhanced `ConfigPage` to support switching between visual and source editors.
- Introduced floating action buttons for save and reload actions.
- Updated translations for tab labels in English and Chinese.
- Styled the configuration page with new tab and floating action button styles.
This commit is contained in:
LTbinglingfeng
2026-02-06 02:15:40 +08:00
parent 7d41afb5f1
commit 11c2498be6
10 changed files with 2090 additions and 103 deletions

105
src/types/visualConfig.ts Normal file
View File

@@ -0,0 +1,105 @@
export type PayloadParamValueType = 'string' | 'number' | 'boolean' | 'json';
export type PayloadParamEntry = {
id: string;
path: string;
valueType: PayloadParamValueType;
value: string;
};
export type PayloadModelEntry = {
id: string;
name: string;
protocol?: 'openai' | 'gemini' | 'claude' | 'codex' | 'antigravity';
};
export type PayloadRule = {
id: string;
models: PayloadModelEntry[];
params: PayloadParamEntry[];
};
export type PayloadFilterRule = {
id: string;
models: PayloadModelEntry[];
params: string[];
};
export interface StreamingConfig {
keepaliveSeconds: string;
bootstrapRetries: string;
nonstreamKeepaliveInterval: string;
}
export type VisualConfigValues = {
host: string;
port: string;
tlsEnable: boolean;
tlsCert: string;
tlsKey: string;
rmAllowRemote: boolean;
rmSecretKey: string;
rmDisableControlPanel: boolean;
rmPanelRepo: string;
authDir: string;
apiKeysText: string;
debug: boolean;
commercialMode: boolean;
loggingToFile: boolean;
logsMaxTotalSizeMb: string;
usageStatisticsEnabled: boolean;
usageRecordsRetentionDays: string;
proxyUrl: string;
forceModelPrefix: boolean;
requestRetry: string;
maxRetryInterval: string;
quotaSwitchProject: boolean;
quotaSwitchPreviewModel: boolean;
routingStrategy: 'round-robin' | 'fill-first';
wsAuth: boolean;
payloadDefaultRules: PayloadRule[];
payloadOverrideRules: PayloadRule[];
payloadFilterRules: PayloadFilterRule[];
streaming: StreamingConfig;
};
export const makeClientId = () => {
if (typeof globalThis.crypto?.randomUUID === 'function') return globalThis.crypto.randomUUID();
return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
};
export const DEFAULT_VISUAL_VALUES: VisualConfigValues = {
host: '',
port: '',
tlsEnable: false,
tlsCert: '',
tlsKey: '',
rmAllowRemote: false,
rmSecretKey: '',
rmDisableControlPanel: false,
rmPanelRepo: '',
authDir: '',
apiKeysText: '',
debug: false,
commercialMode: false,
loggingToFile: false,
logsMaxTotalSizeMb: '',
usageStatisticsEnabled: false,
usageRecordsRetentionDays: '',
proxyUrl: '',
forceModelPrefix: false,
requestRetry: '',
maxRetryInterval: '',
quotaSwitchProject: true,
quotaSwitchPreviewModel: true,
routingStrategy: 'round-robin',
wsAuth: false,
payloadDefaultRules: [],
payloadOverrideRules: [],
payloadFilterRules: [],
streaming: {
keepaliveSeconds: '',
bootstrapRetries: '',
nonstreamKeepaliveInterval: '',
},
};