Files
KimiCodeSwitch/docs/PROPOSAL-settings-global-page.md
T
KimiSwitch Dev 38dbb5527a
Release / Version consistency (push) Canceled after 0s
Release / Build (macos-latest) (push) Canceled after 0s
Release / Build (ubuntu-latest) (push) Canceled after 0s
Release / Build (windows-latest) (push) Canceled after 0s
Release / Attach macOS install script (push) Canceled after 0s
feat(settings): 设置弹窗改为全局设置页面(全局/高级/关于三 Tab)+ 体检账单缺口与更新下载修复 — bump to v0.8.5
2026-10-16 08:50:45 +08:00

187 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 提案:设置改为全局页面(设置 + 高级功能 合一)
状态:**待评审**(本文档为主代理自查 + 交叉审核用,未开始实现)
日期:2026-10-15
---
## 1. 目标
取消「设置」弹窗,改为带返回按钮的全局页面;三个 Tab 从同一入口打开同一页面(顺序 **全局设置 | 高级设置 | 关于**):
- **全局设置 Tab**:全局默认模型 / 供应商级别的默认项
- **高级设置 Tab**(原「高级设置」页内容 + 代理设置):代理设置(thinking/循环控制/权限规则/hooks 等)、Kimi Code WebUI 快速打开、models.dev 模型数据、子代理副模型/模型池、实验开关
- **关于 Tab**(id 仍为 `general`,原 `SettingsModal` 内容):外观(主题/语言)、更新(版本/检查/下载/安装)、Kimi Code CLI 版本与兼容性、关于
已确认的三个决策点:
| 决策 | 选择 | 含义 |
| --- | --- | --- |
| A | 1 | `AgentSettingsPanel` 从供应商编辑页(`ProviderEdit.tsx`)**移除**,只保留在设置页高级 Tab —— 单一入口 |
| B | 2 | **保留**旧 `view === "subagent"` 渲染分支作为兼容外壳,不删除 |
| C | 1 | 所有 section **抽成独立可复用组件**,不复制内容,避免两处分叉 |
## 2. 现状核实(已完成调研,行号为当前 main 上的位置)
| 文件 | 关键事实 |
| --- | --- |
| `src/App.tsx:83-85` | `view` 类型:`"list" \| "edit" \| "subagent" \| "dashboard" \| "sessions" \| "plugins"`,需新增 `"settings"` |
| `src/App.tsx:89` | `showSettings` state(改造后删除) |
| `src/App.tsx:600-638` | 顶部导航(供应商/数据看板/会话),**无 dirty 拦截**,直接 `setView` |
| `src/App.tsx:652-665` | 齿轮按钮 → `setShowSettings(true)`;含「有更新」绿点徽标(保留) |
| `src/App.tsx:682-696` | 渲染分支:`subagent` → `<SubagentSettingsPage>`(保留,即决策 B) |
| `src/App.tsx:697-724` | `ProviderEdit` 入参含 `rawOther` / `onRawOtherChange` / `defaultModel` |
| `src/App.tsx:906-914` | footer「高级设置」按钮(仅 `view === "list"` 显示)→ `setView("subagent")`,改为打开设置页高级 Tab |
| `src/App.tsx:919-926` | `<SettingsModal>` 挂载(改造后删除) |
| `src/components/SettingsModal.tsx`(589 行) | 4 个 section:外观 `:257`、更新 `:302`、Kimi Code `:434`、关于 `:500`;弹窗专属:`createPortal`、`fixed inset-0` 蒙层、Esc 关闭、`body.overflow` 锁定;`handleDownload`(`:103-130`)含「无安装包 → 打开 release 页」回退(**近期 bug 修复,必须逐字保留**);全仓库仅 `App.tsx` 引用 |
| `src/components/SubagentSettingsPage.tsx`(710 行) | props `{ rawOther, models, onChange, onBack }`;返回头 `:402-414`,内容区 `:416-707`(masterOn 提示条 + WebUI Card + models.dev Card + 副模型/模型池 Card + 实验开关 Card);仅 `App.tsx` 引用 |
| `src/components/AgentSettingsPanel.tsx`(451 行) | props `{ rawOther, onChange, models?, defaultModel? }`;读写全局 `config.raw_other`;自带 `mt-6` 外壳和 `agentSettings` 小标题,页面内可直接复用,**该文件本身不改**;目前唯一挂载点 `ProviderEdit.tsx:478-484`(`agent === "kimi_code"` 时) |
| `src/i18n/zh.ts` / `en.ts` | 已有:`settings`、`settingsTitle`、`settingsAppearance`、`settingsUpdates`、`settingsAbout`、`subagentSettings`、`back`;三个 Tab 直接复用 `settingsTabGlobal` / `subagentSettings` / `settingsAbout` |
数据流结论(合并无数据层改动):`AgentSettingsPanel`、`SubagentSettingsPage` 都只读写全局 `config.raw_other`,`App.tsx` 已有现成回调 `onRawOtherChange={(next) => updateConfig((cfg) => ({ ...cfg, raw_other: next }))}`(`App.tsx:722-724`)。
## 3. 目标结构
```
src/components/settings/
├── SettingsPage.tsx 新增:返回头 + Tab 切换 + 内容容器(本次唯一的"页面")
├── SettingsGeneralTab.tsx 新增:SettingsModal 的 4 个 section,去掉弹窗外壳
└── SettingsAdvancedTab.tsx 新增:AgentSettingsPanel + SubagentSettingsPage 内容区,去掉返回头
src/components/
├── SettingsModal.tsx 删除(仅 App.tsx 引用,一并摘除)
└── SubagentSettingsPage.tsx 改为薄壳:返回头 + <SettingsAdvancedTab>(决策 B 的兼容入口)
```
### 3.1 组件接口契约
```tsx
// SettingsGeneralTab.tsx —— 自包含(主题/语言/版本/下载状态都内置)
interface SettingsGeneralTabProps {
updateInfo: UpdateInfo | null;
checking: boolean;
onCheckUpdate: () => void;
lastChecked: number | null;
}
// SettingsAdvancedTab.tsx —— 纯内容,无返回头
interface SettingsAdvancedTabProps {
rawOther: unknown;
models: Record<string, Model>;
defaultModel: string | null; // 供 AgentSettingsPanel 判断 effort 支持
onChange: (nextRawOther: unknown) => void;
}
// SettingsPage.tsx
// 返回头与 SubagentSettingsPage 同款:`← {t("back")}` + 标题 `t("settingsTitle")`("设置")
interface SettingsPageProps {
// Tab 受控(不用 initialTab + 内部 state)——齿轮按钮在 header 常驻,
// 停留在设置页时再点齿轮,必须能切回第一个 Tab(全局设置);非受控则 prop 变化不生效。
activeTab: "global" | "advanced" | "general";
onTabChange: (tab: "global" | "advanced" | "general") => void;
onBack: () => void;
// 透传给三个 Tab:
updateInfo / checking / onCheckUpdate / lastChecked
rawOther / models / defaultModel / onRawOtherChange
}
```
### 3.2 Tab 挂载策略(审核补充的关键点)
原 `SettingsModal` **常驻挂载**(`open=false` 时返回 null 但 hooks 仍在跑),下载进度监听、`downloadedPath` 状态在弹窗开关间不丢失。改造后若用条件渲染 `{tab === "general" && ...}`,下载进行中切到高级 Tab(或按返回离开页面)会丢失 `downloadedPath`,「安装」按钮消失——这是行为回归。
**方案:三个 Tab 面板都常驻挂载,非激活 Tab 用 `className="hidden"` 隐藏。** 代价仅是高级 Tab 提前挂载(一次 `getAgentSettings` IPC 读,无副作用),换来下载状态与滚动位置不丢。
## 4. App.tsx 接线
1. `view` 类型加 `"settings"`;删除 `showSettings` state 与 `<SettingsModal>` 挂载、import;删除 `SettingsModal.tsx`。
2. 新增 `settingsTab` state(`"global" | "advanced" | "general"`)。
3. 齿轮按钮(`App.tsx:670`)→ `setSettingsTab("global"); setView("settings")`(第一个 Tab 即全局设置);绿点徽标保留。
4. header「高级设置」按钮 → `setSettingsTab("advanced"); setView("settings")`,文案键不变。
5. 渲染分支加(Tab 受控,state 放 App):
```tsx
) : view === "settings" ? (
<SettingsPage
activeTab={settingsTab}
onTabChange={setSettingsTab}
onBack={() => setView("list")}
updateInfo={updateInfo} checking={checking} onCheckUpdate={checkNow} lastChecked={lastChecked}
rawOther={config.raw_other} models={config.models} defaultModel={config.default_model}
onRawOtherChange={(next) => updateConfig((cfg) => ({ ...cfg, raw_other: next }))}
/>
```
6. 兼容分支(决策 B):`view === "subagent"` 保留,仅多传 `defaultModel={config.default_model}`(`SubagentSettingsPage` 新增可选 prop)。此后 UI 上无入口指向它,代码保留。
## 5. ProviderEdit.tsx 摘除(决策 A)
- 删除 `AgentSettingsPanel` 挂载块(`:477-484`)与 import(`:16`)。
- 连锁清理(`noUnusedLocals` / `noUnusedParameters` 开启,tsc 会逼出来):`rawOther` / `onRawOtherChange` 两个 props 若无其他使用则从 `ProviderEditProps`(`:93` 附近)和 `App.tsx:721-724` 调用处一并删除;`modelsByAlias` 等仅为其存在的中间变量同步清理。以 `npx tsc --noEmit` 零错误为准。
## 6. i18n
三个 Tab 文案键(zh / en):
| key | zh | en |
| --- | --- | --- |
| `settingsTabGlobal` | 全局设置 | Global Settings |
| `subagentSettings` | 高级设置 | Advanced Settings |
| `settingsAbout` | 关于 | About |
不新增其他 key;`SubagentSettingsPage` 薄壳继续复用 `subagentSettings` / `back`。
## 7. 行为差异清单(有意为之,评审确认)
| # | 差异 | 说明 |
| --- | --- | --- |
| 1 | Esc 不再关闭设置 | 弹窗行为;页面用「← 返回」。如需保留可加,默认不加 |
| 2 | 设置不再遮挡底层界面 | 弹窗 → 页面,符合本次需求本意 |
| 3 | footer 出现在设置页 | footer 显示条件不含 `settings`,保存/重载按钮仍可用(高级 Tab 改 `raw_other` 会标 dirty,**能在页内直接保存**,是改善而非回归) |
| 4 | 顶部导航「供应商」高亮条件 | `list/edit/subagent` 高亮(`App.tsx:604`),`settings` 不加入高亮,返回后仍正确 |
| 5 | 齿轮/高级按钮进入设置页**不做 dirty 拦截** | 与现有 header 导航(数据看板/会话)一致;配置在内存中不丢失 |
| 6 | 停留在设置页时再点齿轮 | 切回第一个 Tab(全局设置),受控 Tab 保证 prop 变化生效,见 3.1 |
| 7 | footer 按钮文案 | 与高级设置 Tab 共用 `subagentSettings`(高级设置),文案一致 |
## 8. 不做的事(边界)
- 不动 dashboard / sessions / plugins 页面,不动 Rust 侧任何代码。
- 不改 `AgentSettingsPanel.tsx` 内部(含 `mt-6` 外壳与「代理设置」小标题,在高级 Tab 中观感正常);高级 Tab 不再按 `agent === "kimi_code"` 判断——当前仅支持 kimi_code(`getInitialAgent` 恒返回 `"kimi_code"`),判断无意义。
- Tab 选择不持久化到 localStorage:每次进入按入口决定初始 Tab(齿轮 → 全局设置,header「高级设置」→ 高级设置)。
- 不新增组件测试:项目测试先例仅覆盖 `src/lib` / `src/hooks`,无组件测试;本次跟随先例。
- `SettingsGeneralTab` 只在设置页打开时挂载(原弹窗常驻挂载)——下载监听只能由设置页内的按钮发起,无实际影响。
- 工作区里已有的未提交改动(更新下载修复、OpenTerminal 链接、models-dev 数据)与本提案无关,实现时**不混入**,分开提交。
## 9. 实施步骤(依赖顺序)
1. **并行抽取**(两个子代理,文件不相交):
a. `SettingsGeneralTab.tsx`(含下载回退修复逐字保留)
b. `SettingsAdvancedTab.tsx` + `SubagentSettingsPage.tsx` 改薄壳
2. **接线**(主代理):`SettingsPage.tsx` + `App.tsx` + `ProviderEdit.tsx` + i18n 两键 + 删除 `SettingsModal.tsx`。
3. **验证**:`npx tsc --noEmit` 零错误 → `npm test`(150 例基线)→ `cargo test`(应无影响,跑一遍确认 208 例基线)。
4. **dev 实测**(注意先 `taskkill` 关正式版,单实例锁冲突):见 10。
## 10. 验收标准
**自动化**:`npx tsc --noEmit` 零错误;`npm test` 全绿;`cargo test` 全绿。
**手动清单**(`npm run tauri-dev`):
- [ ] 齿轮 → 打开设置页,初始停在「全局设置」Tab,四个 section(外观/更新/KimiCode/关于)在「关于」Tab 中原弹窗内容一致(含 OpenTerminal 链接)
- [ ] header「高级设置」→ 同一页面,初始停在「高级设置」Tab,含代理设置 + 原 4 个 Card
- [ ] 「← 返回」回到供应商列表
- [ ] 供应商编辑页模型 Tab **不再出现**代理设置区块
- [ ] 高级 Tab 改动(如实验开关)→ footer 出现未保存标记 → 可在页内保存 → 配置文件落盘正确
- [ ] 检查更新 / 下载 / 安装流程可用;下载中切到高级 Tab 再切回,进度与「安装」按钮不丢
- [ ] 主题、语言切换即时生效
- [ ] 有新版本时齿轮绿点徽标仍显示
- [ ] 停留在设置页时再点齿轮 → 切回第一个 Tab(全局设置)
- [ ] header「高级设置」按钮文案与高级设置 Tab 名一致
## 11. 风险与回退
| 风险 | 缓解 |
| --- | --- |
| 抽取时漏搬/改错下载回退逻辑 | 验收清单专项覆盖;diff 逐行 review |
| 高级 Tab 提前挂载引发意外 IPC | 仅一次只读 `getAgentSettings`,无写操作 |
| `ProviderEdit` props 清理波及其他用法 | 已核实 `rawOther` 仅 `AgentSettingsPanel` 消费,tsc 兜底 |
| 回退 | 单独 commit,`git revert` 即可整体回退,不碰数据格式 |