diff --git a/frontend/src/pages/Onboarding.tsx b/frontend/src/pages/Onboarding.tsx index dbd5f27..1994e0e 100644 --- a/frontend/src/pages/Onboarding.tsx +++ b/frontend/src/pages/Onboarding.tsx @@ -22,6 +22,7 @@ import { Database, Plus, Puzzle, + KeyRound, } from 'lucide-react' import { api } from '@/lib/api' import { useCapabilities, usePreferences, useSettings } from '@/lib/useSharedQueries' @@ -298,6 +299,10 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () => const [picked, setPicked] = useState(null) // 是否展开「添加自有数据源」编辑器 const [adding, setAdding] = useState(false) + // 正在内联配置 Key 的插件名 (仅 api_key_env 声明型, 如 fuyao) + const [keyFor, setKeyFor] = useState(null) + const [keyInput, setKeyInput] = useState('') + const [keyError, setKeyError] = useState(null) const builtin = sources.data?.builtin ?? [] const plugins = sources.data?.plugins ?? [] @@ -345,6 +350,28 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () => switchProvider.mutate(name) } + // 内联 Key 配置 (先探后存): 验证通过才落盘 secrets.json, 成功即自动选用该源 + const keyPlugin = keyFor ? plugins.find(p => p.name === keyFor) : undefined + const saveKey = useMutation({ + mutationFn: (name: string) => api.savePluginKey(name, keyInput.trim()), + onSuccess: (data, name) => { + qc.invalidateQueries({ queryKey: QK.dataSources }) + qc.invalidateQueries({ queryKey: QK.capabilities }) + if (data.ok) { + setKeyFor(null) + setKeyInput('') + setKeyError(null) + if (data.plugin_available) { + setPicked(name) + switchProvider.mutate(name) + } + } else { + setKeyError(data.error || (data.reason === 'invalid' ? 'Key 验证失败,请检查后重试' : '保存失败,请重试')) + } + }, + onError: (e: Error) => setKeyError(`保存失败: ${e.message}`), + }) + return (
@@ -369,23 +396,35 @@ function DataSourceStep({ onNext, onBack }: { onNext: () => void; onBack: () =>
{items.map(item => { const isSelected = selected === item.name - const unavailable = item.kind === 'plugin' && !item.available const plugin = item.kind === 'plugin' ? plugins.find(p => p.name === item.name) : undefined + // 缺 Key 型 (声明了 api_key_env) 不算不可用: 引导页内联填写验证即可启用 + const needsKey = item.kind === 'plugin' && !item.available && !!plugin?.api_key_env + const unavailable = item.kind === 'plugin' && !item.available && !needsKey // 切换中的目标卡片: 圆点位置显示转圈, 其余卡片压暗 const switchingToThis = switchProvider.isPending && switchProvider.variables === item.name return ( + + + {keyError && ( +

+ + {keyError} +

+ )} +
+ )} + {/* 添加自有数据源: 复用设置页编辑器 (命名/鉴权/数据集字段映射/测试/启用) */} {adding && (