// ======================================== // Settings Page // ======================================== // Application settings and configuration with CLI tools management import { useState } from 'react'; import { useIntl } from 'react-intl'; import { Settings, Moon, Bell, Cpu, RefreshCw, RotateCcw, Check, X, ChevronDown, ChevronUp, Languages, Plus, } from 'lucide-react'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { Badge } from '@/components/ui/Badge'; import { ThemeSelector } from '@/components/shared/ThemeSelector'; import { useTheme } from '@/hooks'; import { useConfigStore, selectCliTools, selectDefaultCliTool, selectUserPreferences } from '@/stores/configStore'; import type { CliToolConfig, UserPreferences } from '@/types/store'; import { cn } from '@/lib/utils'; import { LanguageSwitcher } from '@/components/layout/LanguageSwitcher'; // ========== CLI Tool Card Component ========== interface CliToolCardProps { toolId: string; config: CliToolConfig; isDefault: boolean; isExpanded: boolean; onToggleExpand: () => void; onToggleEnabled: () => void; onSetDefault: () => void; onUpdateModel: (field: 'primaryModel' | 'secondaryModel', value: string) => void; onUpdateTags: (tags: string[]) => void; onUpdateAvailableModels: (models: string[]) => void; onUpdateSettingsFile: (settingsFile: string | undefined) => void; } function CliToolCard({ toolId, config, isDefault, isExpanded, onToggleExpand, onToggleEnabled, onSetDefault, onUpdateModel, onUpdateTags, onUpdateAvailableModels, onUpdateSettingsFile, }: CliToolCardProps) { const { formatMessage } = useIntl(); // Local state for tag and model input const [tagInput, setTagInput] = useState(''); const [modelInput, setModelInput] = useState(''); // Handler for adding tags const handleAddTag = () => { const newTag = tagInput.trim(); if (newTag && !config.tags.includes(newTag)) { onUpdateTags([...config.tags, newTag]); setTagInput(''); } }; // Handler for removing tags const handleRemoveTag = (tagToRemove: string) => { onUpdateTags(config.tags.filter((t) => t !== tagToRemove)); }; // Handler for adding available models const handleAddModel = () => { const newModel = modelInput.trim(); const currentModels = config.availableModels || []; if (newModel && !currentModels.includes(newModel)) { onUpdateAvailableModels([...currentModels, newModel]); setModelInput(''); } }; // Handler for removing available models const handleRemoveModel = (modelToRemove: string) => { const currentModels = config.availableModels || []; onUpdateAvailableModels(currentModels.filter((m) => m !== modelToRemove)); }; // Predefined tags const predefinedTags = ['分析', 'Debug', 'implementation', 'refactoring', 'testing']; return ( {/* Header */}
{toolId} {isDefault && ( {formatMessage({ id: 'settings.cliTools.default' })} )} {config.type}

{config.primaryModel}

{isExpanded ? ( ) : ( )}
{/* Tags */} {config.tags && config.tags.length > 0 && (
{config.tags.map((tag) => ( {tag} ))}
)}
{/* Expanded Content */} {isExpanded && (
onUpdateModel('primaryModel', e.target.value)} className="mt-1" />
onUpdateModel('secondaryModel', e.target.value)} className="mt-1" />
{/* Tags Section */}

{formatMessage({ id: 'apiSettings.cliSettings.tagsDescription' })}

{config.tags.map((tag) => ( {tag} ))} setTagInput(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleAddTag(); } }} placeholder={config.tags.length === 0 ? formatMessage({ id: 'apiSettings.cliSettings.tagInputPlaceholder' }) : ''} className="flex-1 min-w-[120px] bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground" />
{/* Predefined Tags */}
{formatMessage({ id: 'apiSettings.cliSettings.predefinedTags' })}: {predefinedTags.map((predefinedTag) => ( ))}
{/* Available Models Section */}
{(config.availableModels || []).map((model) => ( {model} ))} setModelInput(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleAddModel(); } }} placeholder={(config.availableModels || []).length === 0 ? formatMessage({ id: 'apiSettings.cliSettings.availableModelsPlaceholder' }) : ''} className="flex-1 min-w-[120px] bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground" />

{formatMessage({ id: 'apiSettings.cliSettings.availableModelsHint' })}

{/* Settings File */}
onUpdateSettingsFile(e.target.value || undefined)} placeholder={formatMessage({ id: 'apiSettings.cliSettings.settingsFilePlaceholder' })} />

{formatMessage({ id: 'apiSettings.cliSettings.settingsFileHint' })}

{!isDefault && config.enabled && ( )}
)}
); } // ========== Main Page Component ========== export function SettingsPage() { const { formatMessage } = useIntl(); const { theme, setTheme } = useTheme(); const cliTools = useConfigStore(selectCliTools); const defaultCliTool = useConfigStore(selectDefaultCliTool); const userPreferences = useConfigStore(selectUserPreferences); const { updateCliTool, setDefaultCliTool, setUserPreferences, resetUserPreferences } = useConfigStore(); const [expandedTools, setExpandedTools] = useState>(new Set()); const toggleToolExpand = (toolId: string) => { setExpandedTools((prev) => { const next = new Set(prev); if (next.has(toolId)) { next.delete(toolId); } else { next.add(toolId); } return next; }); }; const handleToggleToolEnabled = (toolId: string) => { updateCliTool(toolId, { enabled: !cliTools[toolId].enabled }); }; const handleSetDefaultTool = (toolId: string) => { setDefaultCliTool(toolId); }; const handleUpdateModel = (toolId: string, field: 'primaryModel' | 'secondaryModel', value: string) => { updateCliTool(toolId, { [field]: value }); }; const handleUpdateTags = (toolId: string, tags: string[]) => { updateCliTool(toolId, { tags }); }; const handleUpdateAvailableModels = (toolId: string, availableModels: string[]) => { updateCliTool(toolId, { availableModels }); }; const handleUpdateSettingsFile = (toolId: string, settingsFile: string | undefined) => { updateCliTool(toolId, { settingsFile }); }; const handlePreferenceChange = (key: keyof UserPreferences, value: unknown) => { setUserPreferences({ [key]: value }); }; return (
{/* Page Header */}

{formatMessage({ id: 'settings.title' })}

{formatMessage({ id: 'settings.description' })}

{/* Appearance Settings */}

{formatMessage({ id: 'settings.sections.appearance' })}

{/* Multi-Theme Selector */}

{formatMessage({ id: 'settings.appearance.theme' })}

{formatMessage({ id: 'settings.appearance.description' })}

{/* System Theme Toggle (Backward Compatibility) */}

{formatMessage({ id: 'settings.appearance.systemFollow' })}

{formatMessage({ id: 'settings.appearance.systemFollowDesc' })}

{/* Language Settings */}

{formatMessage({ id: 'settings.sections.language' })}

{formatMessage({ id: 'settings.language.displayLanguage' })}

{formatMessage({ id: 'settings.language.chooseLanguage' })}

{/* CLI Tools Configuration */}

{formatMessage({ id: 'settings.sections.cliTools' })}

{formatMessage({ id: 'settings.cliTools.description' })} {defaultCliTool}

{Object.entries(cliTools).map(([toolId, config]) => ( toggleToolExpand(toolId)} onToggleEnabled={() => handleToggleToolEnabled(toolId)} onSetDefault={() => handleSetDefaultTool(toolId)} onUpdateModel={(field, value) => handleUpdateModel(toolId, field, value)} onUpdateTags={(tags) => handleUpdateTags(toolId, tags)} onUpdateAvailableModels={(models) => handleUpdateAvailableModels(toolId, models)} onUpdateSettingsFile={(settingsFile) => handleUpdateSettingsFile(toolId, settingsFile)} /> ))}
{/* Data Refresh Settings */}

{formatMessage({ id: 'settings.dataRefresh.title' })}

{formatMessage({ id: 'settings.dataRefresh.autoRefresh' })}

{formatMessage({ id: 'settings.dataRefresh.autoRefreshDesc' })}

{userPreferences.autoRefresh && (

{formatMessage({ id: 'settings.dataRefresh.refreshInterval' })}

{formatMessage({ id: 'settings.dataRefresh.refreshIntervalDesc' })}

{[15000, 30000, 60000, 120000].map((interval) => ( ))}
)}
{/* Notifications */}

{formatMessage({ id: 'settings.notifications.title' })}

{formatMessage({ id: 'settings.notifications.enableNotifications' })}

{formatMessage({ id: 'settings.notifications.enableNotificationsDesc' })}

{formatMessage({ id: 'settings.notifications.soundEffects' })}

{formatMessage({ id: 'settings.notifications.soundEffectsDesc' })}

{/* Display Settings */}

{formatMessage({ id: 'settings.sections.display' })}

{formatMessage({ id: 'settings.display.showCompletedTasks' })}

{formatMessage({ id: 'settings.display.showCompletedTasksDesc' })}

{/* Reset Settings */}

{formatMessage({ id: 'common.actions.reset' })}

{formatMessage({ id: 'settings.reset.description' })}

); } export default SettingsPage;