'use client' import { useState } from 'react' import useSWR from 'swr' import { Loader2, Pencil, RotateCcw, } from 'lucide-react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Badge } from '@/components/ui/badge' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription, } from '@/components/ui/dialog' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { api } from '@/lib/api-client' import { TableSkeleton } from '@/components/ui/skeleton' import { ErrorBanner, EmptyState } from '@/components/ui/state' import { ApiRequestError } from '@/lib/api-client' import type { ConfigItem } from '@/lib/types' const sourceLabels: Record = { default: '默认值', env: '环境变量', db: '数据库', } const sourceVariants: Record = { default: 'secondary', env: 'info', db: 'default', } export default function ConfigPage() { const [error, setError] = useState('') const [activeTab, setActiveTab] = useState('all') // SWR for config list const { data: configs = [], isLoading, mutate } = useSWR( ['config', activeTab], () => { const params: Record = {} if (activeTab !== 'all') params.category = activeTab return api.config.list(params) } ) // 编辑 Dialog const [editTarget, setEditTarget] = useState(null) const [editValue, setEditValue] = useState('') const [saving, setSaving] = useState(false) function openEditDialog(config: ConfigItem) { setEditTarget(config) setEditValue(config.current_value ?? '') } async function handleSave() { if (!editTarget) return setSaving(true) try { let parsedValue: string | number | boolean = editValue if (editTarget.value_type === 'number') { parsedValue = parseFloat(editValue) || 0 } else if (editTarget.value_type === 'boolean') { parsedValue = editValue === 'true' } await api.config.update(editTarget.id, { value: parsedValue }) setEditTarget(null) mutate() } catch (err) { if (err instanceof ApiRequestError) setError(err.body.message) } finally { setSaving(false) } } function formatValue(value: unknown): string { if (value === undefined || value === null) return '-' if (typeof value === 'boolean') return value ? 'true' : 'false' return String(value) } const categoryLabels: Record = { all: '全部', server: '服务器', agent: 'Agent', memory: '记忆', llm: 'LLM', security: '安全策略', } const categories = Object.keys(categoryLabels) return (
{/* 分类 Tabs */} {categories.map((cat) => ( {categoryLabels[cat] || cat} ))} {error && setError('')} />} {isLoading ? ( ) : error ? null : configs.length === 0 ? ( ) : ( 分类 Key 当前值 默认值 来源 需重启 描述 操作 {configs.map((config) => ( {config.category} {config.key_path} {formatValue(config.current_value)} {formatValue(config.default_value)} {sourceLabels[config.source] || config.source} {config.requires_restart ? ( ) : ( )} {config.description || '-'} ))}
)} {/* 编辑 Dialog */} setEditTarget(null)}> 编辑配置 修改 {editTarget?.key_path} 的值 {editTarget?.requires_restart && ( 注意: 修改此配置需要重启服务才能生效 )}
{editTarget?.value_type === 'boolean' ? ( ) : ( setEditValue(e.target.value)} /> )}
) }