Skip to content

功能优化 - #28

Merged
CSCITech merged 5 commits into
mainfrom
cscitech
Aug 6, 2026
Merged

CSCITech merged 5 commits into
mainfrom
cscitech

Conversation

@CSCITech

@CSCITech CSCITech commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a0a8ec54-157e-4c2b-88c2-4c3a3f0832d3

📥 Commits

Reviewing files that changed from the base of the PR and between f1f31b2 and d3abca4.

📒 Files selected for processing (1)
  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (2)
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
🔇 Additional comments (1)
web/default/src/features/keys/components/api-key-routing-editor.test.tsx (1)

41-41: LGTM!

Also applies to: 60-60


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added structured API key routing with smart or manual ordered-group modes and cross-group retry.
    • API key lists now display routing mode, effective route or group chain, and retry status.
    • Token endpoints support routing policies with legacy compatibility.
    • Playground requests can explicitly select a group, overriding saved routing.
    • User group responses include available automatic routes.
  • Bug Fixes

    • Improved model aggregation and routing/channel selection reliability.
  • Localization

    • Added routing-related translations across supported languages.

Walkthrough

Changes

Token routing policy

Layer / File(s) Summary
Routing policy model and execution
model/*, service/token_routing.go, service/channel_select.go
Adds smart and manual routing policies, ordered route plans, retry handling, persistence, normalization, and channel selection.
Request and controller integration
middleware/*, controller/*, constant/context_key.go
Propagates routing through authentication, Playground overrides, token APIs, group responses, and model ownership resolution.
API key routing UI
web/default/src/features/keys/*
Adds routing schemas, form conversion, validation, manual group ordering, retry controls, routing previews, and compatibility handling.
Localization and support
web/default/src/i18n/*, .gitignore
Adds routing translations and ignores .tools.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Poem

A rabbit arranged the groups in a row,
Smart routes guide where the requests should go.
Manual hops follow an ordered track,
Retry flags help the route step back.
Badges and translations now shine bright,
Token paths follow the selected route right.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title “功能优化” is related to a functional change but is too generic to identify the primary change. Replace the title with a specific summary of the token routing or API key routing change.
Description check ❓ Inconclusive The description contains only the PR template and does not explain the changes, rationale, scope, or verification. Add a concise description of the routing changes, their purpose, affected areas, and test results.
✅ Passed checks (2 passed)
Check name Status Explanation
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cscitech

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/default/src/features/keys/lib/api-key-form.ts (1)

62-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the empty if branch.

The if (data.unlimited_quota) branch contains only a comment. Invert the condition so the quota check reads directly.

♻️ Proposed refactor
-      if (data.unlimited_quota) {
-        // Routing validation still applies to unlimited keys.
-      } else if (
-        data.remain_quota_dollars === undefined ||
-        data.remain_quota_dollars < 0
+      // Routing validation below still applies to unlimited keys.
+      if (
+        !data.unlimited_quota &&
+        (data.remain_quota_dollars === undefined ||
+          data.remain_quota_dollars < 0)
       ) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/features/keys/lib/api-key-form.ts` around lines 62 - 73, In
the quota validation logic of the API key form, remove the empty unlimited_quota
branch and invert the condition so the existing remain_quota_dollars validation
runs directly when data.unlimited_quota is false. Preserve the current
validation checks and issue details unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/model.go`:
- Around line 243-253: Update getEnabledModelsForGroups to track seen model
names with a map[string]struct{} instead of repeatedly calling
common.StringsContains, while preserving the returned slice of unique models.
Also refactor the model lookup toward a single query that accepts all
ownerGroups through an IN condition, if the model package supports it, rather
than querying once per group.

In `@controller/token.go`:
- Around line 124-126: Update tokenMutationUpdatesRouting and the UpdateToken
routing branch to treat request.CrossGroupRetry as a routing-policy change,
including when it is explicitly false; preserve the existing Routing and Group
checks and ensure standalone cross_group_retry updates apply.

In `@middleware/auth.go`:
- Around line 468-476: Before calling service.ResolveTokenRoutingPolicy in the
token-routing flow, replace an empty userGroup with
setting.GetDefaultAutoRouteKey() so legacy tokens with missing cached groups
route successfully. Also update the routingErr response to pass the error
through common.TranslateMessage(c, ...) instead of exposing routingErr.Error()
directly, while preserving the existing forbidden response and early return.

In `@middleware/distributor.go`:
- Around line 116-139: Update the preferred-channel handling around
GetPreferredChannelByAffinity to iterate routePlan.OrderedGroups in order,
selecting the first group where preferred.Id supports modelRequest.Model. Set
selectGroup and affinity context to that matched group, preserve retry-index
initialization relative to its position, and when no group matches, pass the
unused preference through CacheGetRandomSatisfiedChannel so ordered-group
fallback and cross-group retry state follow the plan ordering.

In `@service/token_routing.go`:
- Around line 209-233: In the policy parsing block around BuildTokenRoutePlan,
perform the ContextKeyTokenRoutingPolicy lookup once and track whether it
produced a valid non-nil model.TokenRoutingPolicy value. Use that parsed-policy
status for plan.Legacy instead of hasStoredPolicy, so unexpected types and nil
pointers that trigger LegacyTokenRoutingPolicy remain marked legacy.

In `@web/default/src/features/keys/components/api-key-routing-editor.tsx`:
- Around line 411-426: Replace the nested ternary in the routes-loading and
empty-options rendering within the API key routing editor with a small component
or helper using if statements and early returns, preserving the existing loading
skeleton, no-options alert, and normal content states.
- Around line 179-189: Update ManualGroupEditor to accept a single props object
typed with its existing fields, then replace every bare value, options,
disabled, and onChange reference in the component body with the corresponding
props.xxx access, matching ManualGroupRow and ApiKeyRoutingEditor.
- Around line 239-276: Update the PopoverTrigger markup so the element carrying
role='combobox' contains only the combobox trigger content, with aria-expanded
reflecting !disabled && open. Move the selected group badges and their remove
buttons, placeholder, and chevron outside that role='combobox' element while
preserving the existing toggleGroup behavior and disabled styling.

In `@web/default/src/features/keys/components/api-keys-columns.tsx`:
- Around line 235-237: Update the TooltipTrigger render element in the manual
routing label branch to use an inline-flex or equivalent non-inline display,
matching the smart branch, so max-w-60 and truncate apply and long labels render
with an ellipsis.

In `@web/default/src/features/keys/components/api-keys-mutate-drawer.tsx`:
- Around line 171-172: Update the routeGroups calculation to use the imported
MAX_MANUAL_ROUTING_GROUPS constant instead of the hardcoded 8 when limiting
option groups, keeping the existing fallback to an empty array.
- Around line 206-259: Update the load effect around getApiKey to read
autoRouteOptions, realGroups, defaultManualGroups, and effectiveAutoRoute from a
ref, and only initialize after the groups query is settled rather than on
loading or refetch identity changes. Track the current request/drawer context so
stale getApiKey responses cannot reset the form or preserved routing state, and
add rejection handling that routes server failures through handleServerError and
displays the standard toast.error feedback.

In `@web/default/src/features/keys/lib/api-key-form.test.ts`:
- Around line 50-72: Extend the api-key form tests around
transformApiKeyToFormDefaults and getApiKeyFormSchema: add coverage for a legacy
key with group '' using supplied defaults, asserting the default group is used,
and add a schema test asserting more than MAX_MANUAL_ROUTING_GROUPS manual
groups is rejected. Import MAX_MANUAL_ROUTING_GROUPS from api-key-form and
preserve the existing legacy real-group test.

In `@web/default/src/features/keys/lib/api-key-form.ts`:
- Around line 237-247: The manualGroups fallback in the routing setup must not
preserve an empty legacy apiKey.group. Update the relevant branch around
routing, legacySmart, and manualGroups so an empty group is excluded and the
supplied availability/manual-group defaults are used instead, while preserving
valid non-empty legacy groups and existing routed behavior.

In `@web/default/src/i18n/locales/ru.json`:
- Line 4369: Update the Russian translation for “Automatic routing is
enabled...” to describe using the ordered list of groups in the selected
automatic route, rather than the order within a selected group; preserve the
existing meaning that automatic routing follows the selected route’s group
order.

---

Outside diff comments:
In `@web/default/src/features/keys/lib/api-key-form.ts`:
- Around line 62-73: In the quota validation logic of the API key form, remove
the empty unlimited_quota branch and invert the condition so the existing
remain_quota_dollars validation runs directly when data.unlimited_quota is
false. Preserve the current validation checks and issue details unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 02cee46b-2c44-4048-824e-66ee49c319e8

📥 Commits

Reviewing files that changed from the base of the PR and between 4c62e58 and d710003.

📒 Files selected for processing (35)
  • .gitignore
  • constant/context_key.go
  • controller/group.go
  • controller/model.go
  • controller/model_list_test.go
  • controller/model_owned_by_test.go
  • controller/token.go
  • controller/token_test.go
  • middleware/auth.go
  • middleware/distributor.go
  • middleware/distributor_routing_test.go
  • model/ability.go
  • model/token.go
  • model/token_routing.go
  • model/token_routing_test.go
  • service/channel_select.go
  • service/channel_select_routing_test.go
  • service/token_routing.go
  • service/token_routing_test.go
  • web/default/src/features/keys/components/api-key-group-combobox.tsx
  • web/default/src/features/keys/components/api-key-routing-editor.tsx
  • web/default/src/features/keys/components/api-keys-columns.tsx
  • web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
  • web/default/src/features/keys/lib/api-key-form.test.ts
  • web/default/src/features/keys/lib/api-key-form.ts
  • web/default/src/features/keys/lib/index.ts
  • web/default/src/features/keys/types.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh.json
  • web/default/src/i18n/static-keys.ts
  • web/default/src/lib/api.ts
💤 Files with no reviewable changes (1)
  • web/default/src/i18n/static-keys.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/ability.go
  • constant/context_key.go
  • model/token.go
  • controller/group.go
  • service/channel_select_routing_test.go
  • controller/model.go
  • controller/model_list_test.go
  • controller/model_owned_by_test.go
  • service/channel_select.go
  • middleware/auth.go
  • model/token_routing.go
  • service/token_routing.go
  • service/token_routing_test.go
  • middleware/distributor_routing_test.go
  • controller/token.go
  • middleware/distributor.go
  • model/token_routing_test.go
  • controller/token_test.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/lib/api.ts
  • web/default/src/features/keys/lib/index.ts
  • web/default/src/features/keys/components/api-keys-columns.tsx
  • web/default/src/features/keys/components/api-key-routing-editor.tsx
  • web/default/src/features/keys/lib/api-key-form.test.ts
  • web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
  • web/default/src/features/keys/components/api-key-group-combobox.tsx
  • web/default/src/features/keys/lib/api-key-form.ts
  • web/default/src/features/keys/types.ts
web/default/src/features/**/lib/**/*.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

表单应使用 React Hook Form + Zod:在功能模块的 lib/ 下定义 schema,并用 z.infer 导出表单类型;useForm 应配合 @hookform/resolvers/zod 进行校验。

Files:

  • web/default/src/features/keys/lib/index.ts
  • web/default/src/features/keys/lib/api-key-form.test.ts
  • web/default/src/features/keys/lib/api-key-form.ts
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/keys/lib/index.ts
  • web/default/src/features/keys/components/api-keys-columns.tsx
  • web/default/src/features/keys/components/api-key-routing-editor.tsx
  • web/default/src/features/keys/lib/api-key-form.test.ts
  • web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
  • web/default/src/features/keys/components/api-key-group-combobox.tsx
  • web/default/src/features/keys/lib/api-key-form.ts
  • web/default/src/features/keys/types.ts
web/default/src/**/*.test.ts

📄 CodeRabbit inference engine (web/default/AGENTS.md)

工具函数与纯逻辑应优先编写单元测试;测试文件应命名为 *.test.ts

Files:

  • web/default/src/features/keys/lib/api-key-form.test.ts
🔇 Additional comments (36)
.gitignore (1)

43-44: LGTM!

web/default/src/i18n/locales/en.json (1)

27-27: LGTM!

Also applies to: 591-875, 1451-1664, 2339-2340, 2648-2651, 2860-2861, 2963-3085, 3830-3849, 3903-4034, 4140-4210, 4368-4369, 4548-4650, 4919-4919, 5147-5147

web/default/src/i18n/locales/fr.json (1)

27-27: LGTM!

Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4167, 4190-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147

web/default/src/i18n/locales/ja.json (1)

27-27: LGTM!

Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4190-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147

web/default/src/i18n/locales/ru.json (1)

27-27: LGTM!

Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4167, 4190-4194, 4210-4210, 4368-4368, 4548-4548, 4649-4650, 4919-4919, 5147-5147

web/default/src/i18n/locales/vi.json (1)

27-27: LGTM!

Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4168, 4190-4190, 4194-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147

web/default/src/i18n/locales/zh.json (1)

27-27: LGTM!

Also applies to: 591-591, 875-875, 1451-1451, 1520-1520, 1664-1664, 2339-2340, 2648-2651, 2860-2861, 2963-2963, 3005-3005, 3084-3085, 3830-3830, 3849-3849, 3903-3903, 4034-4034, 4140-4140, 4167-4168, 4190-4194, 4210-4210, 4368-4369, 4548-4548, 4649-4650, 4919-4919, 5147-5147

web/default/src/features/keys/components/api-key-group-combobox.tsx (1)

79-83: LGTM!

web/default/src/features/keys/types.ts (1)

21-33: LGTM!

Also applies to: 58-59, 108-110

web/default/src/features/keys/lib/api-key-form.ts (1)

75-125: LGTM!

Also applies to: 163-190, 199-228

web/default/src/features/keys/lib/index.ts (1)

24-28: LGTM!

web/default/src/features/keys/components/api-keys-mutate-drawer.tsx (2)

105-109: LGTM!

Also applies to: 261-279, 356-361, 417-479, 725-725


148-167: 🎯 Functional Correctness

Keep the user_selectable filter on automatic routes. controller/group.go sends only user-selectable routes in auto_routes, so the drawer should not expose disabled route options, but the current backend normalization only checks user_selectable.

			> Likely an incorrect or invalid review comment.
web/default/src/features/keys/components/api-keys-columns.tsx (2)

203-229: LGTM!


238-242: 🎯 Functional Correctness

No i18next pluralization issue here.

All supported locales define the base Manual {{count}} groups: {{groups}} key, and the config does not enable missing-key handling behavior that would override fallback to this defined key.

			> Likely an incorrect or invalid review comment.
web/default/src/features/keys/lib/api-key-form.test.ts (1)

74-131: LGTM!

Also applies to: 163-211

web/default/src/lib/api.ts (1)

23-23: LGTM!

Also applies to: 203-203

constant/context_key.go (1)

22-23: LGTM!

service/token_routing.go (1)

33-52: LGTM!

Also applies to: 96-163, 269-291

middleware/auth.go (1)

483-487: LGTM!

middleware/distributor.go (1)

86-113: LGTM!

controller/model.go (1)

189-215: LGTM!

Also applies to: 302-302

controller/token.go (2)

20-50: LGTM!

Also applies to: 67-122, 245-271, 298-313, 343-405, 432-432


52-65: 🗄️ Data Integrity & Integration

No change needed. tokenMutationRequest covers the writable token fields persisted by AddToken and UpdateToken; used_quota, created_time, accessed_time, and key are excluded from token mutation on purpose.

controller/model_owned_by_test.go (1)

9-9: LGTM!

Also applies to: 88-103

controller/token_test.go (1)

19-19: LGTM!

Also applies to: 38-45, 133-151, 537-589, 628-663, 665-741, 743-762, 764-799, 801-832

middleware/distributor_routing_test.go (1)

22-44: LGTM!

Also applies to: 46-114

model/token_routing.go (1)

26-59: LGTM!

model/token.go (1)

31-31: LGTM!

Also applies to: 315-315

model/ability.go (1)

189-191: LGTM!

service/channel_select.go (1)

102-104: LGTM!

Also applies to: 184-244

model/token_routing_test.go (1)

9-49: LGTM!

service/token_routing_test.go (1)

13-124: LGTM!

service/channel_select_routing_test.go (1)

17-145: LGTM!

controller/group.go (1)

41-49: LGTM!

controller/model_list_test.go (1)

216-229: LGTM!

Comment thread controller/model.go
Comment on lines +243 to +253
func getEnabledModelsForGroups(ownerGroups []string) []string {
models := make([]string, 0)
for _, ownerGroup := range ownerGroups {
for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) {
if !common.StringsContains(models, groupModel) {
models = append(models, groupModel)
}
}
}
return models
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Deduplicate with a set and consider one query for all groups.

common.StringsContains scans the accumulated slice for every candidate model. With up to MaxTokenManualGroups groups and large model catalogs, the cost is quadratic on a request path. model.GetGroupEnabledModels also runs one query per group. Use a map[string]struct{} for deduplication, and consider a single IN query over all owner groups.

♻️ Proposed refactor
 func getEnabledModelsForGroups(ownerGroups []string) []string {
 	models := make([]string, 0)
+	seen := make(map[string]struct{})
 	for _, ownerGroup := range ownerGroups {
 		for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) {
-			if !common.StringsContains(models, groupModel) {
-				models = append(models, groupModel)
-			}
+			if _, exists := seen[groupModel]; exists {
+				continue
+			}
+			seen[groupModel] = struct{}{}
+			models = append(models, groupModel)
 		}
 	}
 	return models
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func getEnabledModelsForGroups(ownerGroups []string) []string {
models := make([]string, 0)
for _, ownerGroup := range ownerGroups {
for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) {
if !common.StringsContains(models, groupModel) {
models = append(models, groupModel)
}
}
}
return models
}
func getEnabledModelsForGroups(ownerGroups []string) []string {
models := make([]string, 0)
seen := make(map[string]struct{})
for _, ownerGroup := range ownerGroups {
for _, groupModel := range model.GetGroupEnabledModels(ownerGroup) {
if _, exists := seen[groupModel]; exists {
continue
}
seen[groupModel] = struct{}{}
models = append(models, groupModel)
}
}
return models
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/model.go` around lines 243 - 253, Update getEnabledModelsForGroups
to track seen model names with a map[string]struct{} instead of repeatedly
calling common.StringsContains, while preserving the returned slice of unique
models. Also refactor the model lookup toward a single query that accepts all
ownerGroups through an IN condition, if the model package supports it, rather
than querying once per group.

Comment thread controller/token.go
Comment thread middleware/auth.go
Comment on lines +468 to 476
routingPolicy, legacyRouting, routingErr := service.ResolveTokenRoutingPolicy(token, userGroup)
if routingErr != nil {
abortWithOpenAiMessage(c, http.StatusForbidden, routingErr.Error())
return
}
tokenGroup, crossGroupRetry := service.ProjectTokenRoutingPolicy(routingPolicy)
if tokenGroup != "" {
// check common.UserUsableGroups[userGroup]
if !service.CanUseTokenGroupRuntime(userGroup, tokenGroup) {
abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("无权访问 %s 分组", tokenGroup))
return
}
// check group in common.GroupRatio
if !service.IsAutoRouteKey(tokenGroup) && !ratio_setting.ContainsGroupRatio(tokenGroup) {
abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("分组 %s 已被弃用", tokenGroup))
return
}
userGroup = tokenGroup
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check whether a user group can be empty and how it reaches the token auth path.
set -euo pipefail

# Find the user cache group assignment and any defaulting logic.
rg -nP -C4 '\bGroup\s*(string|=)' --type=go -g '**/user_cache*.go' -g '**/user.go'
rg -nP -C3 'func .*WriteContext' --type=go
rg -nP -C3 'ContextKeyUserGroup' --type=go

Repository: MAX-API-Next/MAX-API

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate middleware/auth.go and service definitions"
fd -a 'auth\.go$|.*service.*\.(go)$' . | sed 's#^\./##' | head -80

echo
echo "Search for ResolveTokenRoutingPolicy and ProjectTokenRoutingPolicy"
rg -n -C 5 'ResolveTokenRoutingPolicy|ProjectTokenRoutingPolicy|LegacyTokenRoutingPolicy|normalizeTokenRoutingPolicy|userCache|UserCache|ContextKeyUserGroup|WriteContext' --type=go .

Repository: MAX-API-Next/MAX-API

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Read auth.go token path around lines 320-490"
sed -n '320,490p' middleware/auth.go | cat -n

echo
echo "Read model/user_cache.go"
sed -n '1,220p' model/user_cache.go | cat -n

echo
echo "Read service functions definitions"
rg -n -C 2 'func .*ResolveTokenRoutingPolicy|func .*LegacyTokenRoutingPolicy|func .*NormalizeLegacyTokenRoutingPolicy|func .*NormalizeTokenRoutingPolicy|func .*ProjectTokenRoutingPolicy|func .*IsAutoRouteKey' --type=go .

Repository: MAX-API-Next/MAX-API

Length of output: 17308


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Read auth.go token path around lines 320-490"
sed -n '320,490p' middleware/auth.go | cat -n

echo
echo "Read model/user_cache.go"
sed -n '1,220p' model/user_cache.go | cat -n

echo
echo "Read service functions definitions"
rg -n -C 4 'func .*ResolveTokenRoutingPolicy|func .*LegacyTokenRoutingPolicy|func .*NormalizeLegacyTokenRoutingPolicy|func .*NormalizeTokenRoutingPolicy|func .*ProjectTokenRoutingPolicy|func .*IsAutoRouteKey' --type=go .

Repository: MAX-API-Next/MAX-API

Length of output: 19700


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Read service/token_routing.go"
sed -n '1,190p' service/token_routing.go | cat -n

echo
echo "Read model token Group defaulting/validation"
rg -n -C 4 'type Token|func .*CreateUserToken|func .*Update.*Token|func .*Ensure.*Token|func .*Validate.*Token|Group.*string|Create.*Group|DefaultGroup|GetDefault' --type=go model service controller | head -240

echo
echo "Read GetUserCache and cache population/update"
sed -n '1500,1840p' model/user.go | cat -n
rg -n -C 3 'func cacheUser|func UpdateUserCache|func Build.*Cache|UserBase|RedisInvalidateVersionedHash|RedisSet' --type=go model/user.go model/user_cache.go model/cache_invalidation_task.go | head -260

Repository: MAX-API-Next/MAX-API

Length of output: 37922


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Read service/token_routing.go"
sed -n '1,190p' service/token_routing.go | cat -n

echo
echo "Read model token Group defaulting/validation"
rg -n -C 4 'type Token|func .*CreateUserToken|func .*Update.*Token|func .*Ensure.*Token|func .*Validate.*Token|Group.*string|Create.*Group|DefaultGroup|GetDefault' --type=go model service controller | head -240

echo
echo "Read GetUserCache and cache population/update"
sed -n '1500,1840p' model/user.go | cat -n
rg -n -C 3 'func cacheUser|func UpdateUserCache|func .*(Build|Ensure).*Cache|UserBase|RedisInvalidateVersionedHash|RedisSet' --type=go model/user.go model/user_cache.go model/cache_invalidation_task.go | head -260

Repository: MAX-API-Next/MAX-API

Length of output: 40094


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Search token migrations/schema and Group field"
rg -n -C 4 'type Token|Table Name|TableName|Group\s+string|gorm:",|DEFAULT|default'| --type=go model | head -260
fd -i 'migration|mysql|postgres|sqlite|schema|sql' model data config | head -200

echo
echo "Search where User.Group is assigned or trimmed"
rg -n -C 3 'Group\s*[:=]|Update.*Group|Trim\([^)]*Group|strings\.Trim\([^)]*Group|TrimString|SetUserGroup|UpdateUserGroup|groupMap|GroupRatio' --type=go model service controller | head -320

echo
echo "Search where User.Group is changed after create/insert"
rg -n -C 4 'DB.*Model\(&User\)|First\(&[^=]*=.*Group|Update\(&|UpdateAll|AutoMigrate.*User|migration.*Group|schema.*Group|Change.*Group|Modify.*Group|DefaultGroup' --type=go model controller service | head -360

Repository: MAX-API-Next/MAX-API

Length of output: 252


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Search token migrations/schema and Group field"
rg -n -C 4 'type Token|Table Name|TableName|Group\s+string|gorm:",|DEFAULT|default' --type=go model | head -260
fd -i 'migration|mysql|postgres|sqlite|schema|sql' model data config | head -200

echo
echo "Search where User.Group is assigned or trimmed"
rg -n -C 3 'Group\s*[:=]|Update.*Group|Trim\([^)]*Group|strings\.Trim\([^)]*Group|SetUserGroup|UpdateUserGroup|groupMap|GroupRatio' --type=go model service controller | head -320

echo
echo "Search where User.Group is changed after create/insert"
rg -n -C 4 'DB.*Model\(&User\)|First\(&[^=]*=.*Group|Update\(&|UpdateAll|AutoMigrate.*User|migration.*Group|schema.*Group|Change.*Group|Modify.*Group|DefaultGroup' --type=go model controller service | head -360

Repository: MAX-API-Next/MAX-API

Length of output: 42386


Handle corrupted empty user groups before legacy token routing.

LegacyTokenRoutingPolicy falls back to userGroup, and a legacy token with token.Group and an empty userCache.Group routes through NormalizeLegacyTokenRoutingPolicy as a manual routing policy with Groups: [""], which emits manual routing groups must not be empty. Use userGroup = setting.GetDefaultAutoRouteKey() in middleware/auth.go before calling ResolveTokenRoutingPolicy, so missing user groups do not block legacy tokens. Also replace routingErr.Error() in middleware/auth.go:470 with common.TranslateMessage(c, ...) for consistent client-facing routing errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@middleware/auth.go` around lines 468 - 476, Before calling
service.ResolveTokenRoutingPolicy in the token-routing flow, replace an empty
userGroup with setting.GetDefaultAutoRouteKey() so legacy tokens with missing
cached groups route successfully. Also update the routingErr response to pass
the error through common.TranslateMessage(c, ...) instead of exposing
routingErr.Error() directly, while preserving the existing forbidden response
and early return.

Comment thread middleware/distributor.go
Comment thread service/token_routing.go
Comment thread web/default/src/features/keys/components/api-keys-mutate-drawer.tsx Outdated
Comment thread web/default/src/features/keys/components/api-keys-mutate-drawer.tsx Outdated
Comment thread web/default/src/features/keys/lib/api-key-form.test.ts
Comment thread web/default/src/features/keys/lib/api-key-form.ts Outdated
Comment thread web/default/src/i18n/locales/ru.json Outdated
@CSCITech

CSCITech commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/default/src/features/keys/components/api-key-routing-editor.test.tsx`:
- Around line 19-23: Update the ApiKeyRoutingEditor tests to use React Testing
Library and accessible user flows instead of className or Lucide icon selectors.
Query the routing selector by combobox role and accessible name, verify it
opens, and assert that remove buttons are accessible and located outside the
trigger.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 61f07a20-5980-41ca-a78d-2d4dc04b6d67

📥 Commits

Reviewing files that changed from the base of the PR and between d571825 and 65ce777.

📒 Files selected for processing (2)
  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
  • web/default/src/features/keys/components/api-key-routing-editor.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
  • web/default/src/features/keys/components/api-key-routing-editor.tsx
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
  • web/default/src/features/keys/components/api-key-routing-editor.tsx
🔇 Additional comments (1)
web/default/src/features/keys/components/api-key-routing-editor.tsx (1)

235-264: LGTM!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/default/src/features/keys/components/api-key-routing-editor.test.tsx`:
- Line 41: Add explicit TypeScript annotations for the test callback and the
helper logic in api-key-routing-editor.test.tsx: update the test named keep(s)
the maximum manual selection in one accessible selector so its callback has an
explicit return type, and type the nextGroups parameter/value used around the
onManualGroupsChange assertions to match that callback contract. Keep the
existing test behavior unchanged while making the parameter and return types
explicit in the affected test and helper expressions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f78abf40-4f29-4979-87af-dcc7ac08e5dc

📥 Commits

Reviewing files that changed from the base of the PR and between 65ce777 and f1f31b2.

⛔ Files ignored due to path filters (1)
  • web/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • web/default/package.json
  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (3)
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/keys/components/api-key-routing-editor.test.tsx
web/default/**/package.json

📄 CodeRabbit inference engine (web/default/AGENTS.md)

脚本与包管理以 package.json 为准;发布前应执行 typecheck、lint、format、生产构建,并检查产物体积与环境变量配置。

Files:

  • web/default/package.json
🔇 Additional comments (2)
web/default/package.json (1)

85-85: 📐 Maintainability & Code Quality

Verify release validation.

Before release, run typecheck, lint, format, and the production build. Check artifact size and environment variable configuration. The PR does not provide validation results.

Source: Coding guidelines

web/default/src/features/keys/components/api-key-routing-editor.test.tsx (1)

20-32: LGTM!

Comment thread web/default/src/features/keys/components/api-key-routing-editor.test.tsx Outdated
@CSCITech

CSCITech commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech
CSCITech merged commit 923aaad into main Aug 6, 2026
3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 9, 2026
11 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Aug 19, 2026
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant