feat(frontend): providers 页 FineTune 卡片行 + 两诉求 — 重构 Stage 3 起步 (MOC-254)#505
feat(frontend): providers 页 FineTune 卡片行 + 两诉求 — 重构 Stage 3 起步 (MOC-254)#505Cmochance wants to merge 4 commits into
Conversation
stacked on stage2(FineTune 风)。providers 页用 FineTune 卡片范式迁移, 实现用户两诉求。 - typed API 层: http.ts(移植 api 核心 + 错误 shape) + types.ts + providers.ts (逐字移植 ICON_MAP/computeIcon/mapProvider/providerBody + 端点, 含协议 normalize 实战逻辑) - providers store(pinia): load/setDefault/remove/reorder(乐观更新 + 失败回滚) - ProviderCard【诉求1】: 右侧只保留 启用/编辑/删除 三按钮, 统一图标+文字(AppButton), 去掉测速/钱包/复制/终端; 左侧 grip 拖拽手柄 - ProvidersPage【诉求2】: HTML5 拖拽排序(复刻旧 enableProviderReorder 语义, drop 调 /api/providers/reorder 持久化) + 列表 + 空/错/载状态 - vue-tsc + vite build 通过; 真机功能验证(CRUD+拖拽, 需后端 /api/providers 数据) 待 cargo tauri dev / .app e2e Refs MOC-254
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 41136db08c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| 'GET', | ||
| '/api/providers', | ||
| ) | ||
| const activeId = data.activeProviderId ?? null |
There was a problem hiding this comment.
Read activeId from providers response
When the providers page loads, this reads activeProviderId, but the /api/providers handler returns the active provider under activeId (src-tauri/src/admin/handlers/providers/crud.rs:127-130), as the legacy API did. In any config with an active provider, activeId is therefore always treated as null, so mapProvider marks every card as inactive and the Providers page never shows the active badge/secondary state even after enabling a provider.
Useful? React with 👍 / 👎.
proxy API(start/stop/status/logs+mapLog 移植)+ store + ProxyPage(SettingsGroup 开关/端口 + 日志卡片轮询)。Refs MOC-254
ProviderFormPage(基本信息分组卡片: 名称/BaseURL/APIKey/协议分段/默认模型 + 保存, edit 取 getProviderSecret)+ AppInput 组件。Refs MOC-254
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 221a537e16
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| saving.value = true | ||
| error.value = '' | ||
| const payload: ProviderPayload = { |
There was a problem hiding this comment.
Preserve authScheme when saving providers
When this form saves, the payload never includes the provider's authScheme; providerBody then fills in bearer, and the backend persists any authScheme it receives on update. In contexts such as adding Gemini Native (needs google_api_key/x-goog-api-key) or editing Grok/OAuth providers, a harmless save rewrites the provider to Bearer auth and subsequent tests/proxy calls use the wrong credentials, breaking that provider. Carry through the existing scheme or infer the correct scheme for the selected protocol before saving.
Useful? React with 👍 / 👎.
| baseUrl: form.baseUrl, | ||
| apiKey: form.apiKey || undefined, | ||
| apiFormat: form.apiFormat, | ||
| models: form.defaultModel ? { default: form.defaultModel } : {}, |
There was a problem hiding this comment.
Send every model slot when saving edits
In edit mode this only sends models.default, but update_provider merges model keys rather than replacing the whole mapping. For any existing provider that already has gpt_5_5/gpt_5_4 slots populated, changing the default model or clearing extra models in this form leaves those stale slots on disk; the catalog/proxy still route the gpt-5.5 default slot through the old value. Send all slot keys, including empty strings for cleared slots, so saves actually reflect the form state.
Useful? React with 👍 / 👎.
逐字移植旧 app.js L3009-3306 的用量统计渲染逻辑到 Vue 3 SFC,功能等价: - KPI 卡(总输入/总输出/总 tokens/对话数) - 三视图分段(按对话/按日/按模型),model 视图跳重复模型列(Devin #280) - 数据表(命中率/input/output/reasoning/total/turns/last),conversation 视图命中率可点开缓存逐轮分布柱状图 - fetch 失败不写空 report(避免误显 0 用量),显带 retry 错误条 - 新增可复用 AppModal(teleport + ESC + 背景关闭),codex 页将复用 Refs MOC-254
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ddd819af39
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| modelCapabilities: payload.modelCapabilities || {}, | ||
| requestOptions: payload.requestOptions || {}, |
There was a problem hiding this comment.
Preserve provider metadata during edits
When an existing provider is saved from the new form, its payload does not include the provider's current modelCapabilities or requestOptions, so these defaults serialize as {}. The backend update_provider overwrites both fields whenever they are present, which means a harmless key/model edit on providers such as Gemini/Minimax clears context-window capabilities or request options from disk and changes catalog/proxy behavior. Only send these fields when the caller supplied them, or carry through the existing values in edit mode.
Useful? React with 👍 / 👎.
重构 Stage 3 起步(stacked on #504)。providers 页用 FineTune 卡片范式迁移, 实现你最初的两诉求。
改动
enableProviderReorder, drop 调/api/providers/reorder持久化)+ 列表/空/错/载状态验证
vue-tsc+vite build通过。真机功能验证(provider CRUD + 拖拽, 需后端/api/providers数据)待cargo tauri dev/.app, 纳入最终 e2e。Refs MOC-254