feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* OnboardingWizard — 首次使用引导向导
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Dialog, DialogContent, Button, TextField, Select, MenuItem, Stepper, Step, StepLabel, Box, Typography, Stack, FormControl, InputLabel, IconButton, InputAdornment } from '@mui/material';
|
||||
import { ArrowRight, ArrowLeft, FolderOpen, Play, CheckCircle, Eye, EyeOff } from 'lucide-react';
|
||||
import { useUIStore } from '@renderer/stores/ui-store';
|
||||
@@ -10,6 +10,9 @@ import { useAgentStore } from '@renderer/stores/agent-store';
|
||||
|
||||
const STEPS = ['欢迎', '配置 LLM', '自定义 Agent', '工作空间', '开始使用'];
|
||||
|
||||
// #48 修复: Onboarding 进度持久化 key
|
||||
const ONBOARDING_PROGRESS_KEY = 'onboarding_progress';
|
||||
|
||||
export function OnboardingWizard(): React.JSX.Element | null {
|
||||
const onboardingCompleted = useUIStore((s) => s.onboardingCompleted);
|
||||
const setOnboardingCompleted = useUIStore((s) => s.setOnboardingCompleted);
|
||||
@@ -23,6 +26,46 @@ export function OnboardingWizard(): React.JSX.Element | null {
|
||||
// 上下文窗口(联动 Provider:ollama 可空=由模型决定;其他 provider 默认值见 DEFAULT_CTX)
|
||||
const [contextWindow, setContextWindow] = useState<number | null>(null);
|
||||
|
||||
// #48 修复: 启动时从 localStorage 恢复未完成的引导进度,避免中途退出后需重新填写
|
||||
// 注意: apiKey 属于敏感信息,不持久化到 localStorage,恢复时需用户重新输入
|
||||
useEffect(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem(ONBOARDING_PROGRESS_KEY);
|
||||
if (!saved) return;
|
||||
const p = JSON.parse(saved) as {
|
||||
step?: number; provider?: string; baseURL?: string;
|
||||
model?: string; workspacePath?: string;
|
||||
contextWindow?: number | null;
|
||||
};
|
||||
if (typeof p.step === 'number' && p.step >= 0 && p.step < STEPS.length) setStep(p.step);
|
||||
if (typeof p.provider === 'string') setProvider(p.provider);
|
||||
if (typeof p.baseURL === 'string') setBaseURL(p.baseURL);
|
||||
if (typeof p.model === 'string') setModel(p.model);
|
||||
if (typeof p.workspacePath === 'string') setWorkspacePath(p.workspacePath);
|
||||
if (p.contextWindow !== undefined) setContextWindow(p.contextWindow);
|
||||
// 审查修复: 恢复后如果 provider 需要 apiKey 但 apiKey 为空(未持久化),
|
||||
// 回退到步骤 1(配置 LLM)让用户重新输入 apiKey,避免配置不完整
|
||||
// ollama 不需要 apiKey
|
||||
if (p.provider && p.provider !== 'ollama' && p.step && p.step >= 2) {
|
||||
setStep(1);
|
||||
}
|
||||
} catch {
|
||||
// 解析失败忽略,使用默认值
|
||||
}
|
||||
}, []);
|
||||
|
||||
// #48 修复: 每步完成后保存进度到 localStorage,中途退出(关闭窗口/刷新)可恢复
|
||||
// 注意: 不保存 apiKey(敏感信息不写入 localStorage)
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem(ONBOARDING_PROGRESS_KEY, JSON.stringify({
|
||||
step, provider, baseURL, model, workspacePath, contextWindow,
|
||||
}));
|
||||
} catch {
|
||||
// 写入失败(如隐私模式)忽略
|
||||
}
|
||||
}, [step, provider, baseURL, model, workspacePath, contextWindow]);
|
||||
|
||||
if (onboardingCompleted) return null;
|
||||
|
||||
// 各 Provider 上下文窗口默认值(与 SettingsModal 保持一致)
|
||||
@@ -79,6 +122,8 @@ export function OnboardingWizard(): React.JSX.Element | null {
|
||||
useAgentStore.getState().setConfigLoaded(true);
|
||||
}
|
||||
setOnboardingCompleted(true);
|
||||
// #48 修复: 引导完成后清理 localStorage 进度,下次启动不再恢复
|
||||
try { localStorage.removeItem(ONBOARDING_PROGRESS_KEY); } catch { /* ignore */ }
|
||||
} catch (err) {
|
||||
console.error('[OnboardingWizard]', 'Failed to save configuration:', err);
|
||||
// 用户主动操作失败必须有反馈,否则向导不关闭、用户卡死
|
||||
|
||||
Reference in New Issue
Block a user