Skip to content

Commit a09e10c

Browse files
committed
fix: preserve custom config fields when saving through UI
- Add CUSTOM_ROUTER_PATH and NON_INTERACTIVE_MODE to Config interface - Add index signature to Config interface to allow custom fields - Modify ConfigProvider to preserve all original config fields - Only validate and set defaults for known fields - Fix type casting issues in App.tsx This ensures that custom fields like CUSTOM_ROUTER_PATH won't be lost when the config is saved through the UI interface.
1 parent 9a5ea19 commit a09e10c

File tree

8 files changed

+66
-54
lines changed

8 files changed

+66
-54
lines changed

ui/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function App() {
5757

5858
// 根据响应信息进行提示
5959
if (response && typeof response === 'object' && 'success' in response) {
60-
const apiResponse = response as { success: boolean; message?: string };
60+
const apiResponse = response as unknown as { success: boolean; message?: string };
6161
if (apiResponse.success) {
6262
setToast({ message: apiResponse.message || t('app.config_saved_success'), type: 'success' });
6363
} else {
@@ -88,7 +88,7 @@ function App() {
8888
// Check if save was successful before restarting
8989
let saveSuccessful = true;
9090
if (response && typeof response === 'object' && 'success' in response) {
91-
const apiResponse = response as { success: boolean; message?: string };
91+
const apiResponse = response as unknown as { success: boolean; message?: string };
9292
if (!apiResponse.success) {
9393
saveSuccessful = false;
9494
setToast({ message: apiResponse.message || t('app.config_saved_failed'), type: 'error' });

ui/src/components/ConfigProvider.tsx

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createContext, useContext, useState, useEffect } from 'react';
22
import type { ReactNode, Dispatch, SetStateAction } from 'react';
33
import { api } from '@/lib/api';
4-
import type { Config, StatusLineConfig } from '@/types';
4+
import type { Config } from '@/types';
55

66
interface ConfigContextType {
77
config: Config | null;
@@ -66,44 +66,52 @@ export function ConfigProvider({ children }: ConfigProviderProps) {
6666
// Try to fetch config regardless of API key presence
6767
const data = await api.getConfig();
6868

69-
// Validate the received data to ensure it has the expected structure
70-
const validConfig = {
71-
LOG: typeof data.LOG === 'boolean' ? data.LOG : false,
72-
LOG_LEVEL: typeof data.LOG_LEVEL === 'string' ? data.LOG_LEVEL : 'debug',
73-
CLAUDE_PATH: typeof data.CLAUDE_PATH === 'string' ? data.CLAUDE_PATH : '',
74-
HOST: typeof data.HOST === 'string' ? data.HOST : '127.0.0.1',
75-
PORT: typeof data.PORT === 'number' ? data.PORT : 3456,
76-
APIKEY: typeof data.APIKEY === 'string' ? data.APIKEY : '',
77-
API_TIMEOUT_MS: typeof data.API_TIMEOUT_MS === 'string' ? data.API_TIMEOUT_MS : '600000',
78-
PROXY_URL: typeof data.PROXY_URL === 'string' ? data.PROXY_URL : '',
79-
transformers: Array.isArray(data.transformers) ? data.transformers : [],
80-
Providers: Array.isArray(data.Providers) ? data.Providers : [],
81-
StatusLine: data.StatusLine && typeof data.StatusLine === 'object' ? {
82-
enabled: typeof data.StatusLine.enabled === 'boolean' ? data.StatusLine.enabled : false,
83-
currentStyle: typeof data.StatusLine.currentStyle === 'string' ? data.StatusLine.currentStyle : 'default',
84-
default: data.StatusLine.default && typeof data.StatusLine.default === 'object' && Array.isArray(data.StatusLine.default.modules) ? data.StatusLine.default : { modules: [] },
85-
powerline: data.StatusLine.powerline && typeof data.StatusLine.powerline === 'object' && Array.isArray(data.StatusLine.powerline.modules) ? data.StatusLine.powerline : { modules: [] }
86-
} : {
87-
enabled: false,
88-
currentStyle: 'default',
89-
default: { modules: [] },
90-
powerline: { modules: [] }
91-
},
92-
Router: data.Router && typeof data.Router === 'object' ? {
93-
default: typeof data.Router.default === 'string' ? data.Router.default : '',
94-
background: typeof data.Router.background === 'string' ? data.Router.background : '',
95-
think: typeof data.Router.think === 'string' ? data.Router.think : '',
96-
longContext: typeof data.Router.longContext === 'string' ? data.Router.longContext : '',
97-
longContextThreshold: typeof data.Router.longContextThreshold === 'number' ? data.Router.longContextThreshold : 60000,
98-
webSearch: typeof data.Router.webSearch === 'string' ? data.Router.webSearch : ''
99-
} : {
100-
default: '',
101-
background: '',
102-
think: '',
103-
longContext: '',
104-
longContextThreshold: 60000,
105-
webSearch: ''
106-
}
69+
// Start with the original data to preserve all fields
70+
const validConfig = { ...data };
71+
72+
// Validate and set defaults for known fields
73+
validConfig.LOG = typeof data.LOG === 'boolean' ? data.LOG : false;
74+
validConfig.LOG_LEVEL = typeof data.LOG_LEVEL === 'string' ? data.LOG_LEVEL : 'debug';
75+
validConfig.CLAUDE_PATH = typeof data.CLAUDE_PATH === 'string' ? data.CLAUDE_PATH : '';
76+
validConfig.HOST = typeof data.HOST === 'string' ? data.HOST : '127.0.0.1';
77+
validConfig.PORT = typeof data.PORT === 'number' ? data.PORT : 3456;
78+
validConfig.APIKEY = typeof data.APIKEY === 'string' ? data.APIKEY : '';
79+
validConfig.API_TIMEOUT_MS = typeof data.API_TIMEOUT_MS === 'string' ? data.API_TIMEOUT_MS : '600000';
80+
validConfig.PROXY_URL = typeof data.PROXY_URL === 'string' ? data.PROXY_URL : '';
81+
validConfig.transformers = Array.isArray(data.transformers) ? data.transformers : [];
82+
validConfig.Providers = Array.isArray(data.Providers) ? data.Providers : [];
83+
84+
// Preserve CUSTOM_ROUTER_PATH if it exists
85+
if (typeof data.CUSTOM_ROUTER_PATH === 'string') {
86+
validConfig.CUSTOM_ROUTER_PATH = data.CUSTOM_ROUTER_PATH;
87+
}
88+
89+
// Preserve NON_INTERACTIVE_MODE if it exists
90+
if (typeof data.NON_INTERACTIVE_MODE === 'boolean') {
91+
validConfig.NON_INTERACTIVE_MODE = data.NON_INTERACTIVE_MODE;
92+
}
93+
94+
validConfig.StatusLine = data.StatusLine && typeof data.StatusLine === 'object' ? {
95+
enabled: typeof data.StatusLine.enabled === 'boolean' ? data.StatusLine.enabled : false,
96+
currentStyle: typeof data.StatusLine.currentStyle === 'string' ? data.StatusLine.currentStyle : 'default',
97+
default: data.StatusLine.default && typeof data.StatusLine.default === 'object' && Array.isArray(data.StatusLine.default.modules) ? data.StatusLine.default : { modules: [] },
98+
powerline: data.StatusLine.powerline && typeof data.StatusLine.powerline === 'object' && Array.isArray(data.StatusLine.powerline.modules) ? data.StatusLine.powerline : { modules: [] }
99+
} : undefined;
100+
101+
validConfig.Router = data.Router && typeof data.Router === 'object' ? {
102+
default: typeof data.Router.default === 'string' ? data.Router.default : '',
103+
background: typeof data.Router.background === 'string' ? data.Router.background : '',
104+
think: typeof data.Router.think === 'string' ? data.Router.think : '',
105+
longContext: typeof data.Router.longContext === 'string' ? data.Router.longContext : '',
106+
longContextThreshold: typeof data.Router.longContextThreshold === 'number' ? data.Router.longContextThreshold : 60000,
107+
webSearch: typeof data.Router.webSearch === 'string' ? data.Router.webSearch : ''
108+
} : {
109+
default: '',
110+
background: '',
111+
think: '',
112+
longContext: '',
113+
longContextThreshold: 60000,
114+
webSearch: ''
107115
};
108116

109117
setConfig(validConfig);

ui/src/components/Login.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,13 @@ export function Login() {
6767
// Navigate to dashboard
6868
// The ConfigProvider will handle fetching the config
6969
navigate('/dashboard');
70-
} catch (error: any) {
70+
} catch (error: unknown) {
7171
// Clear the API key on failure
7272
api.setApiKey('');
7373

7474
// Check if it's an unauthorized error
75-
if (error.message && error.message.includes('401')) {
75+
const errorMessage = error instanceof Error ? error.message : String(error);
76+
if (errorMessage.includes('401')) {
7677
setError(t('login.invalidApiKey'));
7778
} else {
7879
// For other errors, still allow access (restricted mode)

ui/src/components/Providers.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { ComboInput } from "@/components/ui/combo-input";
2121
import { api } from "@/lib/api";
2222
import type { Provider } from "@/types";
2323

24-
interface ProviderType extends Provider {}
24+
type ProviderType = Provider;
2525

2626
export function Providers() {
2727
const { t } = useTranslation();

ui/src/components/StatusLineConfigDialog.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useTranslation } from "react-i18next";
2-
import React, { useState, useEffect, useMemo, useCallback, useRef } from "react";
3-
import { createPortal } from "react-dom";
2+
import React, { useState, useEffect, useCallback } from "react";
43
import {
54
Dialog,
65
DialogContent,
@@ -429,7 +428,7 @@ export function StatusLineConfigDialog({
429428
const [selectedModuleIndex, setSelectedModuleIndex] = useState<number | null>(
430429
null
431430
);
432-
const [hexBackgroundColors, setHexBackgroundColors] = useState<Set<string>>(
431+
const [, setHexBackgroundColors] = useState<Set<string>>(
433432
new Set()
434433
);
435434

ui/src/components/StatusLineImportExport.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ export function StatusLineImportExport({ config, onImport, onShowToast }: Status
252252
const restoreInput = document.createElement('input');
253253
restoreInput.type = 'file';
254254
restoreInput.accept = '.json';
255-
restoreInput.onchange = (e) => handleRestore(e as any);
255+
restoreInput.onchange = (e) => handleRestore(e as Event);
256256
restoreInput.click();
257257
}}
258258
variant="outline"

ui/src/types.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface ProviderTransformer {
22
use: (string | (string | Record<string, unknown> | { max_tokens: number })[])[];
3-
[key: string]: any; // Allow for model-specific transformers
3+
[key: string]: unknown; // Allow for model-specific transformers
44
}
55

66
export interface Provider {
@@ -18,13 +18,13 @@ export interface RouterConfig {
1818
longContext: string;
1919
longContextThreshold: number;
2020
webSearch: string;
21-
custom?: any;
21+
custom?: unknown;
2222
}
2323

2424
export interface Transformer {
2525
name?: string;
2626
path: string;
27-
options?: Record<string, any>;
27+
options?: Record<string, unknown>;
2828
}
2929

3030
export interface StatusLineModuleConfig {
@@ -62,6 +62,10 @@ export interface Config {
6262
APIKEY: string;
6363
API_TIMEOUT_MS: string;
6464
PROXY_URL: string;
65+
CUSTOM_ROUTER_PATH?: string;
66+
NON_INTERACTIVE_MODE?: boolean;
67+
// Allow additional custom fields
68+
[key: string]: unknown;
6569
}
6670

6771
export type AccessLevel = 'restricted' | 'full';

ui/src/utils/statusline.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import type { StatusLineConfig, StatusLineModuleConfig } from "@/types";
1+
import type { StatusLineConfig } from "@/types";
22

33
// 验证结果(保留接口但不使用)
44
export interface ValidationResult {
55
isValid: boolean;
6-
errors: any[];
6+
errors: unknown[];
77
}
88

99
/**
1010
* 验证StatusLine配置 - 已移除所有验证
1111
* @param config 要验证的配置对象
1212
* @returns 始终返回验证通过
1313
*/
14-
export function validateStatusLineConfig(config: unknown): ValidationResult {
14+
export function validateStatusLineConfig(): ValidationResult {
1515
// 不再执行任何验证
1616
return { isValid: true, errors: [] };
1717
}

0 commit comments

Comments
 (0)