diff --git a/ui/src/App.tsx b/ui/src/App.tsx index bce45f89..856f6b2b 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -57,7 +57,7 @@ function App() { // 根据响应信息进行提示 if (response && typeof response === 'object' && 'success' in response) { - const apiResponse = response as { success: boolean; message?: string }; + const apiResponse = response as unknown as { success: boolean; message?: string }; if (apiResponse.success) { setToast({ message: apiResponse.message || t('app.config_saved_success'), type: 'success' }); } else { @@ -88,7 +88,7 @@ function App() { // Check if save was successful before restarting let saveSuccessful = true; if (response && typeof response === 'object' && 'success' in response) { - const apiResponse = response as { success: boolean; message?: string }; + const apiResponse = response as unknown as { success: boolean; message?: string }; if (!apiResponse.success) { saveSuccessful = false; setToast({ message: apiResponse.message || t('app.config_saved_failed'), type: 'error' }); diff --git a/ui/src/components/ConfigProvider.tsx b/ui/src/components/ConfigProvider.tsx index d6c01df2..8181f71c 100644 --- a/ui/src/components/ConfigProvider.tsx +++ b/ui/src/components/ConfigProvider.tsx @@ -1,7 +1,7 @@ import { createContext, useContext, useState, useEffect } from 'react'; import type { ReactNode, Dispatch, SetStateAction } from 'react'; import { api } from '@/lib/api'; -import type { Config, StatusLineConfig } from '@/types'; +import type { Config } from '@/types'; interface ConfigContextType { config: Config | null; @@ -66,44 +66,52 @@ export function ConfigProvider({ children }: ConfigProviderProps) { // Try to fetch config regardless of API key presence const data = await api.getConfig(); - // Validate the received data to ensure it has the expected structure - const validConfig = { - LOG: typeof data.LOG === 'boolean' ? data.LOG : false, - LOG_LEVEL: typeof data.LOG_LEVEL === 'string' ? data.LOG_LEVEL : 'debug', - CLAUDE_PATH: typeof data.CLAUDE_PATH === 'string' ? data.CLAUDE_PATH : '', - HOST: typeof data.HOST === 'string' ? data.HOST : '127.0.0.1', - PORT: typeof data.PORT === 'number' ? data.PORT : 3456, - APIKEY: typeof data.APIKEY === 'string' ? data.APIKEY : '', - API_TIMEOUT_MS: typeof data.API_TIMEOUT_MS === 'string' ? data.API_TIMEOUT_MS : '600000', - PROXY_URL: typeof data.PROXY_URL === 'string' ? data.PROXY_URL : '', - transformers: Array.isArray(data.transformers) ? data.transformers : [], - Providers: Array.isArray(data.Providers) ? data.Providers : [], - StatusLine: data.StatusLine && typeof data.StatusLine === 'object' ? { - enabled: typeof data.StatusLine.enabled === 'boolean' ? data.StatusLine.enabled : false, - currentStyle: typeof data.StatusLine.currentStyle === 'string' ? data.StatusLine.currentStyle : 'default', - default: data.StatusLine.default && typeof data.StatusLine.default === 'object' && Array.isArray(data.StatusLine.default.modules) ? data.StatusLine.default : { modules: [] }, - powerline: data.StatusLine.powerline && typeof data.StatusLine.powerline === 'object' && Array.isArray(data.StatusLine.powerline.modules) ? data.StatusLine.powerline : { modules: [] } - } : { - enabled: false, - currentStyle: 'default', - default: { modules: [] }, - powerline: { modules: [] } - }, - Router: data.Router && typeof data.Router === 'object' ? { - default: typeof data.Router.default === 'string' ? data.Router.default : '', - background: typeof data.Router.background === 'string' ? data.Router.background : '', - think: typeof data.Router.think === 'string' ? data.Router.think : '', - longContext: typeof data.Router.longContext === 'string' ? data.Router.longContext : '', - longContextThreshold: typeof data.Router.longContextThreshold === 'number' ? data.Router.longContextThreshold : 60000, - webSearch: typeof data.Router.webSearch === 'string' ? data.Router.webSearch : '' - } : { - default: '', - background: '', - think: '', - longContext: '', - longContextThreshold: 60000, - webSearch: '' - } + // Start with the original data to preserve all fields + const validConfig = { ...data }; + + // Validate and set defaults for known fields + validConfig.LOG = typeof data.LOG === 'boolean' ? data.LOG : false; + validConfig.LOG_LEVEL = typeof data.LOG_LEVEL === 'string' ? data.LOG_LEVEL : 'debug'; + validConfig.CLAUDE_PATH = typeof data.CLAUDE_PATH === 'string' ? data.CLAUDE_PATH : ''; + validConfig.HOST = typeof data.HOST === 'string' ? data.HOST : '127.0.0.1'; + validConfig.PORT = typeof data.PORT === 'number' ? data.PORT : 3456; + validConfig.APIKEY = typeof data.APIKEY === 'string' ? data.APIKEY : ''; + validConfig.API_TIMEOUT_MS = typeof data.API_TIMEOUT_MS === 'string' ? data.API_TIMEOUT_MS : '600000'; + validConfig.PROXY_URL = typeof data.PROXY_URL === 'string' ? data.PROXY_URL : ''; + validConfig.transformers = Array.isArray(data.transformers) ? data.transformers : []; + validConfig.Providers = Array.isArray(data.Providers) ? data.Providers : []; + + // Preserve CUSTOM_ROUTER_PATH if it exists + if (typeof data.CUSTOM_ROUTER_PATH === 'string') { + validConfig.CUSTOM_ROUTER_PATH = data.CUSTOM_ROUTER_PATH; + } + + // Preserve NON_INTERACTIVE_MODE if it exists + if (typeof data.NON_INTERACTIVE_MODE === 'boolean') { + validConfig.NON_INTERACTIVE_MODE = data.NON_INTERACTIVE_MODE; + } + + validConfig.StatusLine = data.StatusLine && typeof data.StatusLine === 'object' ? { + enabled: typeof data.StatusLine.enabled === 'boolean' ? data.StatusLine.enabled : false, + currentStyle: typeof data.StatusLine.currentStyle === 'string' ? data.StatusLine.currentStyle : 'default', + default: data.StatusLine.default && typeof data.StatusLine.default === 'object' && Array.isArray(data.StatusLine.default.modules) ? data.StatusLine.default : { modules: [] }, + powerline: data.StatusLine.powerline && typeof data.StatusLine.powerline === 'object' && Array.isArray(data.StatusLine.powerline.modules) ? data.StatusLine.powerline : { modules: [] } + } : undefined; + + validConfig.Router = data.Router && typeof data.Router === 'object' ? { + default: typeof data.Router.default === 'string' ? data.Router.default : '', + background: typeof data.Router.background === 'string' ? data.Router.background : '', + think: typeof data.Router.think === 'string' ? data.Router.think : '', + longContext: typeof data.Router.longContext === 'string' ? data.Router.longContext : '', + longContextThreshold: typeof data.Router.longContextThreshold === 'number' ? data.Router.longContextThreshold : 60000, + webSearch: typeof data.Router.webSearch === 'string' ? data.Router.webSearch : '' + } : { + default: '', + background: '', + think: '', + longContext: '', + longContextThreshold: 60000, + webSearch: '' }; setConfig(validConfig); diff --git a/ui/src/components/Login.tsx b/ui/src/components/Login.tsx index bbfe08f4..1798933d 100644 --- a/ui/src/components/Login.tsx +++ b/ui/src/components/Login.tsx @@ -67,12 +67,13 @@ export function Login() { // Navigate to dashboard // The ConfigProvider will handle fetching the config navigate('/dashboard'); - } catch (error: any) { + } catch (error: unknown) { // Clear the API key on failure api.setApiKey(''); // Check if it's an unauthorized error - if (error.message && error.message.includes('401')) { + const errorMessage = error instanceof Error ? error.message : String(error); + if (errorMessage.includes('401')) { setError(t('login.invalidApiKey')); } else { // For other errors, still allow access (restricted mode) diff --git a/ui/src/components/Providers.tsx b/ui/src/components/Providers.tsx index fadf0a20..eed93566 100644 --- a/ui/src/components/Providers.tsx +++ b/ui/src/components/Providers.tsx @@ -21,7 +21,7 @@ import { ComboInput } from "@/components/ui/combo-input"; import { api } from "@/lib/api"; import type { Provider } from "@/types"; -interface ProviderType extends Provider {} +type ProviderType = Provider; export function Providers() { const { t } = useTranslation(); diff --git a/ui/src/components/StatusLineConfigDialog.tsx b/ui/src/components/StatusLineConfigDialog.tsx index 12cc1f98..4aedb9bb 100644 --- a/ui/src/components/StatusLineConfigDialog.tsx +++ b/ui/src/components/StatusLineConfigDialog.tsx @@ -1,6 +1,5 @@ import { useTranslation } from "react-i18next"; -import React, { useState, useEffect, useMemo, useCallback, useRef } from "react"; -import { createPortal } from "react-dom"; +import React, { useState, useEffect, useCallback } from "react"; import { Dialog, DialogContent, @@ -429,7 +428,7 @@ export function StatusLineConfigDialog({ const [selectedModuleIndex, setSelectedModuleIndex] = useState( null ); - const [hexBackgroundColors, setHexBackgroundColors] = useState>( + const [, setHexBackgroundColors] = useState>( new Set() ); diff --git a/ui/src/components/StatusLineImportExport.tsx b/ui/src/components/StatusLineImportExport.tsx index 5ab875dd..d56c396c 100644 --- a/ui/src/components/StatusLineImportExport.tsx +++ b/ui/src/components/StatusLineImportExport.tsx @@ -252,7 +252,7 @@ export function StatusLineImportExport({ config, onImport, onShowToast }: Status const restoreInput = document.createElement('input'); restoreInput.type = 'file'; restoreInput.accept = '.json'; - restoreInput.onchange = (e) => handleRestore(e as any); + restoreInput.onchange = (e) => handleRestore(e as Event); restoreInput.click(); }} variant="outline" diff --git a/ui/src/types.ts b/ui/src/types.ts index 198a663f..d262e74c 100644 --- a/ui/src/types.ts +++ b/ui/src/types.ts @@ -1,6 +1,6 @@ export interface ProviderTransformer { use: (string | (string | Record | { max_tokens: number })[])[]; - [key: string]: any; // Allow for model-specific transformers + [key: string]: unknown; // Allow for model-specific transformers } export interface Provider { @@ -18,13 +18,13 @@ export interface RouterConfig { longContext: string; longContextThreshold: number; webSearch: string; - custom?: any; + custom?: unknown; } export interface Transformer { name?: string; path: string; - options?: Record; + options?: Record; } export interface StatusLineModuleConfig { @@ -62,6 +62,10 @@ export interface Config { APIKEY: string; API_TIMEOUT_MS: string; PROXY_URL: string; + CUSTOM_ROUTER_PATH?: string; + NON_INTERACTIVE_MODE?: boolean; + // Allow additional custom fields + [key: string]: unknown; } export type AccessLevel = 'restricted' | 'full'; diff --git a/ui/src/utils/statusline.ts b/ui/src/utils/statusline.ts index 976e42c5..503e35d8 100644 --- a/ui/src/utils/statusline.ts +++ b/ui/src/utils/statusline.ts @@ -1,9 +1,9 @@ -import type { StatusLineConfig, StatusLineModuleConfig } from "@/types"; +import type { StatusLineConfig } from "@/types"; // 验证结果(保留接口但不使用) export interface ValidationResult { isValid: boolean; - errors: any[]; + errors: unknown[]; } /** @@ -11,7 +11,7 @@ export interface ValidationResult { * @param config 要验证的配置对象 * @returns 始终返回验证通过 */ -export function validateStatusLineConfig(config: unknown): ValidationResult { +export function validateStatusLineConfig(): ValidationResult { // 不再执行任何验证 return { isValid: true, errors: [] }; }