Skip to content

fix(api-client): wrap provider group-count and model-suggestion wrappers in toActionResult#1235

Merged
ding113 merged 3 commits into
devfrom
fix/provider-group-stats-actionresult
Jun 2, 2026
Merged

fix(api-client): wrap provider group-count and model-suggestion wrappers in toActionResult#1235
ding113 merged 3 commits into
devfrom
fix/provider-group-stats-actionresult

Conversation

@ding113

@ding113 ding113 commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Related Issues/PRs:

问题

在用户管理页面展开「用户编辑面板」(创建/编辑用户对话框) 时,100% 必现前端报错 获取供应商分组统计失败: undefined,但所有后端接口均返回 200,无任何接口错误。

复现

实测确认 (本地登录后端 dev server 浏览器复现):

  • GET /api/v1/providers/groups?include=countHTTP 200,响应体为裸数组 [](不含 ok 字段)。
  • 控制台报错 获取供应商分组统计失败: (第二个参数为 undefined)。

根因

src/lib/api-client/v1/actions/providers.ts 中的 api-client 包装器 getProviderGroupsWithCount 与同类的 getModelSuggestionsByProviderGroup 直接返回了原始 HTTP body,未包裹 toActionResult

而后端 handler 经 actionJson() 解包后返回的是裸数据(数组/对象,没有 ok)。但 UI 消费方仍按旧的 ActionResult { ok, data, error } 形态消费:

// provider-group-select.tsx
getProviderGroupsWithCount().then((res) => {
  if (res.ok) { ... }                       // res 是数组 → res.ok === undefined → 走错误分支
  console.error("获取供应商分组统计失败:", res.error);  // res.error === undefined
  toast.error(res.error || loadFailedText);
});

res.ok 永远是 undefined,即使 HTTP 200 也会进入错误分支,故每次面板挂载必现该 toast。getModelSuggestionsByProviderGroup 是同类问题(use-model-suggestions.ts 检查 res.ok && res.data),只是表现为模型自动补全静默失效、不弹 toast。属于与 #1158 (testProviderUnified) 完全相同的契约错配类别。

该 bug 类对测试套件不可见:tests/setup.ts 全局把所有 @/lib/api-client/v1/actions/* 包装器 vi.doMock 替换为 server-action 实现(本身就返回 ActionResult),所以包装器的"重新封装"契约从未被默认套件覆盖。

修复

将两个包装器用 toActionResult 封装,与本文件其余函数及 #1158 的约定一致。React Query 直接消费的 getProvidersHealthStatus 仍保持裸返回不变。

测试 (TDD)

tests/unit/api/v1/api-client-actions.test.ts(该文件用 vi.importActual 加载真实包装器并 mock @/lib/api-client/v1/client,绕过全局替换)新增 3 个契约测试:成功封装、失败映射 (ApiError{ ok:false })、model-suggestions 封装。修复前 red,修复后 green。

浏览器实测:修复后展开对话框无任何控制台报错,分组字段正常挂载。

本地验证 (全绿)

  • bun run build
  • bun run typecheck
  • bun run lint
  • bun run test ✅ 688 文件 / 6181 用例通过,0 失败

🤖 Generated with Claude Code

Greptile Summary

This PR fixes a contract mismatch in the v1 API client: getProviderGroupsWithCount and getModelSuggestionsByProviderGroup were returning raw HTTP response bodies instead of the ActionResult<T> shape expected by their UI consumers, causing guaranteed false-error toasts whenever the provider-group edit panel was opened.

  • providers.ts: Both affected wrappers are now wrapped with toActionResult, matching every other mutating/querying function in the file (except getProvidersHealthStatus, which is intentionally bare for React Query direct consumption).
  • api-client-actions.test.ts: Three contract tests are added using vi.importActual to exercise the real wrappers against a mocked HTTP client — covering success and failure paths for getProviderGroupsWithCount, and the success path for getModelSuggestionsByProviderGroup.
  • provider-form-*.test.tsx: Test mocks for getModelSuggestionsByProviderGroup are updated from the old bare-array shape to the correct { ok: true, data: [] } shape, keeping existing tests consistent with the new contract.

Confidence Score: 5/5

Safe to merge — the fix is a minimal, targeted wrapping of two functions to match the contract already enforced everywhere else in the same file.

The change touches only two wrapper functions, adds three regression tests that were red before and green after, and updates two test mocks to stay in sync. The intentional exception (getProvidersHealthStatus kept bare for React Query) is preserved and explicitly documented in both the source and test comments. No new logic paths, no schema changes, no side effects introduced.

No files require special attention.

Important Files Changed

Filename Overview
src/lib/api-client/v1/actions/providers.ts Two functions wrapped in toActionResult to match the ActionResult contract expected by UI consumers; change is targeted and consistent with all other functions in the file.
tests/unit/api/v1/api-client-actions.test.ts Three new contract tests added covering success + failure for getProviderGroupsWithCount and success for getModelSuggestionsByProviderGroup; uses vi.importActual to exercise real wrappers.
tests/unit/settings/providers/provider-form-endpoint-pool.test.tsx Mock for getModelSuggestionsByProviderGroup updated from bare array to ActionResult shape to stay consistent with the new contract.
tests/unit/settings/providers/provider-form-total-limit-ui.test.tsx Same mock update as provider-form-endpoint-pool.test.tsx — bare array replaced with ActionResult shape.

Sequence Diagram

sequenceDiagram
    participant UI as provider-group-select.tsx
    participant AC as api-client/providers.ts
    participant BE as GET /api/v1/providers/groups?include=count

    Note over UI,BE: Before fix
    UI->>AC: getProviderGroupsWithCount()
    AC->>BE: apiGet(...)
    BE-->>AC: 200 [] (bare array)
    AC-->>UI: [] (bare array, no ok/data)
    UI->>UI: "res.ok === undefined → error branch"
    UI->>UI: toast.error(获取供应商分组统计失败: undefined)

    Note over UI,BE: After fix
    UI->>AC: getProviderGroupsWithCount()
    AC->>BE: apiGet(...)
    BE-->>AC: 200 [] (bare array)
    AC->>AC: toActionResult(promise)
    AC-->>UI: "{ ok: true, data: [] }"
    UI->>UI: "res.ok === true → success branch"
Loading

Reviews (2): Last reviewed commit: "test: align model-suggestion mocks with ..." | Re-trigger Greptile

…in toActionResult

The getProviderGroupsWithCount and getModelSuggestionsByProviderGroup
wrappers returned raw arrays, but dashboard consumers check res.ok,
causing a misleading error toast because ok was undefined.
Wrap them in toActionResult to return { ok, data } and add contract
tests for success and error paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

两个提供商 API 查询方法 (getProviderGroupsWithCountgetModelSuggestionsByProviderGroup) 的返回值从直接 apiGet 调用改为通过 toActionResult 包装,实现统一的 ActionResult 错误处理格式。新增单元测试验证成功和失败场景的包装行为。

Changes

提供商 API ActionResult 包装

Layer / File(s) Summary
API 方法返回值包装
src/lib/api-client/v1/actions/providers.ts
getProviderGroupsWithCountgetModelSuggestionsByProviderGroup 的返回值改为使用 toActionResult(...) 包装,将原始 apiGet 响应或错误统一转换为 { ok, data?, error?, errorCode? } 形式。
ActionResult 包装行为测试
tests/unit/api/v1/api-client-actions.test.ts, tests/unit/settings/providers/provider-form-endpoint-pool.test.tsx, tests/unit/settings/providers/provider-form-total-limit-ui.test.tsx
新增/更新测试:验证 getProviderGroupsWithCount() 成功/失败映射为 ActionResult、getModelSuggestionsByProviderGroup() 成功时返回 { ok: true, data },并调整相关测试 mock 返回值以匹配新的 ActionResult 结构;同时断言请求 URL 与 DASHBOARD_COMPAT_HEADER 的传递。

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • ding113/claude-code-hub#1158: 同样更新 src/lib/api-client/v1/actions/providers.ts,对提供商操作 API 调用进行 toActionResult(...) 包装,使返回的 ActionResult 形式与 UI/测试预期一致。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: wrapping two API client functions (getProviderGroupsWithCount and getModelSuggestionsByProviderGroup) with toActionResult wrapper, which is the core change across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed Pull request description is well-related to the changeset, providing clear problem statement, root cause analysis, fix approach, and test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/provider-group-stats-actionresult

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added bug Something isn't working area:core area:provider labels Jun 1, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates getProviderGroupsWithCount and getModelSuggestionsByProviderGroup in the API client to wrap their results in an ActionResult using toActionResult. This ensures compatibility with consumers expecting an { ok, data } structure rather than raw arrays. Additionally, comprehensive unit tests have been added to verify the wrapping behavior for successful and failed requests. I have no feedback to provide on these changes.

@github-actions github-actions Bot added the size/S Small PR (< 200 lines) label Jun 1, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

No significant issues identified in this PR.

PR Size: S

  • Lines changed: 67
  • Files changed: 2

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate
  • Code clarity - Good

Automated review by Codex AI

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Identified PR #1235 (fix(api-client): wrap provider group-count and model-suggestion wrappers in toActionResult) and reviewed the full diff for src/lib/api-client/v1/actions/providers.ts and tests/unit/api/v1/api-client-actions.test.ts.
  • Applied the size label: size/S (67 lines changed across 2 files).
  • Completed a diff-scoped 6-perspective review (comments, tests, error-handling, types, general correctness/security, simplification); no issues met the >=80 confidence reporting threshold, so no inline review comments were posted.
  • Posted the required PR review summary via gh pr review.
  • Note: I could not run repo quality checks here because bunx is not available in this runner (bunx: command not found).

provider-form-{total-limit-ui,endpoint-pool} mocked getModelSuggestionsByProviderGroup with a raw [] (old contract). After wrapping the real api-client fn in toActionResult, update both mocks to { ok: true, data: [] } so the test doubles match production and would catch a regression in the model-suggestion path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🧪 测试结果

测试类型 状态
代码质量
单元测试
集成测试
API 测试

总体结果: ✅ 所有测试通过

@ding113
ding113 merged commit 5bb7ad5 into dev Jun 2, 2026
10 checks passed
@ding113
ding113 deleted the fix/provider-group-stats-actionresult branch June 2, 2026 03:25
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Claude Code Hub Roadmap Jun 2, 2026
ding113 added a commit that referenced this pull request Jun 2, 2026
… focused (#1237)

Fixes the create-user dialog where the "provider group" dropdown would not open
to select existing groups. TagInput now auto-opens its suggestions the first
time they load asynchronously while the input is focused (fire-once,
disabled-guarded), so focusing the field before the data arrives no longer
leaves the dropdown stuck closed.

The data-fetch half of #1212 was fixed separately in #1235; this completes the
interaction-layer fix. Includes regression tests (incl. the dialog/portal path)
and corrects the test mock path.

Fixes #1212

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai coderabbitai Bot mentioned this pull request Jun 3, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core area:provider bug Something isn't working size/S Small PR (< 200 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant