Skip to content

fix(web): handle unlimited API key quota validation#4881

Merged
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
yyhhyyyyyy:fix/api-key-unlimited-quota-validation
May 16, 2026
Merged

fix(web): handle unlimited API key quota validation#4881
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
yyhhyyyyyy:fix/api-key-unlimited-quota-validation

Conversation

@yyhhyyyyyy
Copy link
Copy Markdown
Contributor

@yyhhyyyyyy yyhhyyyyyy commented May 15, 2026

⚠️ 提交说明 / PR Notice

Important

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

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
修复 default 主题下 API Key 编辑表单的隐藏额度校验问题。
当 API Key 开启无限额度时,后端返回的负数剩余额度仍会被写入前端表单的隐藏额度字段,导致 zod 在提交前拦截校验,表现为点击保存无请求、无错误提示。现在在无限额度场景下会将该隐藏额度归一化为 0,并跳过额度字段校验;非无限额度仍保持非负校验。同时补充了表单校验失败提示和相关 i18n 文案,避免静默失败。

🚀 变更类型 / 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

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

Summary by CodeRabbit

  • Improvements

    • Enhanced API key form with improved validation error handling that prompts users to fix highlighted fields.
    • Refined quota validation logic for better accuracy.
  • Localization

    • Added translations for form validation messages across six languages: English, French, Japanese, Russian, Vietnamese, and Chinese.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

Walkthrough

The pull request refactors the API key form validation schema from a static constant to a localized, parameterized function. It adds conditional validation on the remaining quota field based on the unlimited quota toggle, integrates dynamic schema resolution in the form component, adds validation failure feedback via toast notification, and provides multilingual translations for two new validation messages.

Changes

API Key Form Validation Refactor

Layer / File(s) Summary
Localized schema with conditional quota validation
web/default/src/features/keys/lib/api-key-form.ts
Schema is converted to a getApiKeyFormSchema(t: TFunction) function accepting localization context. A conditional superRefine enforces remain_quota_dollars validation only when unlimited_quota is false, requiring it to be defined and zero or greater. Form default transformation sets remain_quota_dollars to 0 when unlimited quota is enabled.
Dynamic schema integration and validation feedback
web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
The drawer component builds the validation schema dynamically using getApiKeyFormSchema(t) and passes it to zodResolver. An onInvalid handler displays a toast when validation fails, instructing users to fix highlighted fields. Form submission wires both the valid and invalid submit handlers.
Public API export and multilingual translations
web/default/src/features/keys/lib/index.ts, web/default/src/i18n/locales/{en,fr,ja,ru,vi,zh}.json
The public re-export is updated from apiKeyFormSchema to getApiKeyFormSchema. Two new translation keys are added across six languages: one for the validation error message and one for the quota validation rule.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A schema now speaks in a thousand tongues,
Dynamic and wise with translations on its lungs,
Quotas gently enforced when the toggle says "no,"
Toast messages flutter when errors take flow,
Localization complete, from jest to au revoir!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main fix: handling validation for unlimited API key quota—a core bug fix reflected throughout the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
web/default/src/features/keys/components/api-keys-mutate-drawer.tsx (1)

155-158: ⚡ Quick win

Memoize the schema and resolver.

getApiKeyFormSchema(t) and zodResolver(schema) are rebuilt on every render, including every field change. Wrapping them in useMemo keeps the validation wiring stable in the form’s hot path.

♻️ Proposed refactor
-import { useEffect, useState, type ReactNode } from 'react'
+import { useEffect, useMemo, useState, type ReactNode } from 'react'
@@
-  const schema = getApiKeyFormSchema(t)
+  const schema = useMemo(() => getApiKeyFormSchema(t), [t])
+  const resolver = useMemo(() => zodResolver(schema), [schema])

   const form = useForm<ApiKeyFormValues>({
-    resolver: zodResolver(schema),
+    resolver,
     defaultValues: getApiKeyFormDefaultValues(defaultUseAutoGroup),
   })

As per coding guidelines, web/default/**/*.tsx: Use useMemo and useCallback judiciously to reduce unnecessary re-renders; avoid creating new objects/arrays in render paths; use React.memo when necessary

🤖 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/components/api-keys-mutate-drawer.tsx` around
lines 155 - 158, getApiKeyFormSchema(t) and zodResolver(schema) are recreated on
every render, causing unnecessary work in the form hot path; wrap the schema
creation and the resolver creation in useMemo so the same schema and resolver
instances are passed to useForm. Specifically memoize the result of
getApiKeyFormSchema(t) into a schema variable (used by zodResolver) and then
memoize zodResolver(schema) before passing it to useForm<ApiKeyFormValues> so
the form/resolver stays stable across field updates.
web/default/src/i18n/locales/ru.json (1)

2924-2924: ⚡ Quick win

Use hierarchical semantic i18n keys for these new messages.

These new entries use source-sentence keys, which conflicts with the i18n key naming rule and makes key stability depend on copy text edits.

♻️ Suggested key shape
-    "Please fix the highlighted fields before saving": "Исправьте выделенные поля перед сохранением",
+    "keys.validation.fixHighlightedFieldsBeforeSaving": "Исправьте выделенные поля перед сохранением",
...
-    "Quota must be zero or greater": "Квота не может быть отрицательной",
+    "keys.validation.quotaMustBeZeroOrGreater": "Квота не может быть отрицательной",

As per coding guidelines, Use hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency.

Also applies to: 3101-3101

🤖 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/i18n/locales/ru.json` at line 2924, Replace the
source-sentence JSON key "Please fix the highlighted fields before saving" with
a hierarchical, semantic key to ensure stability; e.g. change the key to
something like form.validation.highlightedFields.fixBeforeSave (or a similar
namespace that fits your app's i18n convention) and move the Russian string as
its value, updating any consumers to use the new key (search for usages of the
original sentence key and replace them with
form.validation.highlightedFields.fixBeforeSave or chosen semantic key).
web/default/src/i18n/locales/ja.json (1)

2924-2924: ⚡ Quick win

Use semantic hierarchical i18n keys for these new entries.

Both new keys are sentence literals. Please switch them to structured keys (for example, validation.fixHighlightedFieldsBeforeSaving and validation.quota.nonNegative) and wire usages to those keys for consistency and maintainability.

As per coding guidelines, web/default/src/i18n/**/*.{ts,tsx,json} should "Use hierarchical and semantically clear translation key names such as dashboard.overview.title and maintain naming consistency".

Also applies to: 3101-3101

🤖 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/i18n/locales/ja.json` at line 2924, Replace the
sentence-literal translation keys in the locale JSON with semantic hierarchical
keys (e.g., change "Please fix the highlighted fields before saving" to
validation.fixHighlightedFieldsBeforeSaving and the other literal at the
referenced location to validation.quota.nonNegative), update the ja.json entries
accordingly, and then find and update all usages in the codebase (components,
hooks, and tests) that reference the old literal keys to use the new
hierarchical keys (e.g., i18n.t('validation.fixHighlightedFieldsBeforeSaving'))
to maintain naming consistency across web/default/src/i18n/**/*.{ts,tsx,json}.
🤖 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.

Nitpick comments:
In `@web/default/src/features/keys/components/api-keys-mutate-drawer.tsx`:
- Around line 155-158: getApiKeyFormSchema(t) and zodResolver(schema) are
recreated on every render, causing unnecessary work in the form hot path; wrap
the schema creation and the resolver creation in useMemo so the same schema and
resolver instances are passed to useForm. Specifically memoize the result of
getApiKeyFormSchema(t) into a schema variable (used by zodResolver) and then
memoize zodResolver(schema) before passing it to useForm<ApiKeyFormValues> so
the form/resolver stays stable across field updates.

In `@web/default/src/i18n/locales/ja.json`:
- Line 2924: Replace the sentence-literal translation keys in the locale JSON
with semantic hierarchical keys (e.g., change "Please fix the highlighted fields
before saving" to validation.fixHighlightedFieldsBeforeSaving and the other
literal at the referenced location to validation.quota.nonNegative), update the
ja.json entries accordingly, and then find and update all usages in the codebase
(components, hooks, and tests) that reference the old literal keys to use the
new hierarchical keys (e.g.,
i18n.t('validation.fixHighlightedFieldsBeforeSaving')) to maintain naming
consistency across web/default/src/i18n/**/*.{ts,tsx,json}.

In `@web/default/src/i18n/locales/ru.json`:
- Line 2924: Replace the source-sentence JSON key "Please fix the highlighted
fields before saving" with a hierarchical, semantic key to ensure stability;
e.g. change the key to something like
form.validation.highlightedFields.fixBeforeSave (or a similar namespace that
fits your app's i18n convention) and move the Russian string as its value,
updating any consumers to use the new key (search for usages of the original
sentence key and replace them with
form.validation.highlightedFields.fixBeforeSave or chosen semantic key).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1ce758c2-29d9-4b58-ba18-17f6b8fd63dc

📥 Commits

Reviewing files that changed from the base of the PR and between 18282e6 and 8ee51e8.

📒 Files selected for processing (9)
  • web/default/src/features/keys/components/api-keys-mutate-drawer.tsx
  • web/default/src/features/keys/lib/api-key-form.ts
  • web/default/src/features/keys/lib/index.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

Copy link
Copy Markdown
Collaborator

@Calcium-Ion Calcium-Ion left a comment

Choose a reason for hiding this comment

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

LGTM. 审了 diff:

根因分析正确:当 unlimited_quota = trueremain_quota_dollars 字段被隐藏,但 zod schema 仍然要求 min(0) 校验。用户切换到无限额度后再提交,隐藏的 remain_quota_dollars 可能是 undefined 导致 validation 静默失败,表现为"保存无响应"。

修复要点

  1. apiKeyFormSchemagetApiKeyFormSchema(t) 工厂函数:支持 i18n 的校验消息。
  2. .superRefine 中判断 unlimited_quota — 如果开启了无限额度就跳过 remain_quota_dollars 校验,否则要求 >= 0。逻辑正确。
  3. transformApiKeyToFormDefaults 中当 unlimited_quotaremain_quota_dollars 置为 0 而非从 API 取值 — 避免编辑时回填一个可能过时的数值到隐藏字段。
  4. onInvalid handler + toast — 让 zod 校验失败时用户能看到提示而非静默无反应。
  5. i18n keys 全语种都补了。

改动只涉及前端 form schema,无后端影响。

@Calcium-Ion Calcium-Ion merged commit 8a10ded into QuantumNous:main May 16, 2026
2 checks passed
chenglu added a commit to chenglu/new-api that referenced this pull request May 17, 2026
Merged 28 commits from QuantumNous/new-api upstream/main, including:

Backend:
- feat: support request_header key source (QuantumNous#4903)
- fix: apply group filter to channel list queries (QuantumNous#4885, QuantumNous#4847)
- fix: enforce header nav access control for public modules (QuantumNous#4889)
- fix: correct usage logs filtering (QuantumNous#4883)
- fix: allow clearing channel remark (QuantumNous#4886)
- feat: track upstream request ID and prevent response header override
- feat: require compliance confirmation for paid features

Frontend:
- fix: 修复新 UI 语言与文案显示问题 (QuantumNous#4876)
- fix(web): handle unlimited API key quota validation (QuantumNous#4881)
- fix(web/default): batch fix new UI issues (QuantumNous#4880, QuantumNous#4893, QuantumNous#4817, QuantumNous#4877, QuantumNous#4898)
- fix: prevent combobox from over-filtering options on focus (QuantumNous#4829)
- fix(default): support DropdownMenuItem onSelect (QuantumNous#4787)
- chore(deps): bump axios to 1.15.2

Conflict resolution:
- Locale JSONs: union merge (design overrides preserved, upstream new keys added)
- router/api-router.go: kept design /public/session route, accepted upstream HeaderNavModuleAuth
- common-logs-filter-bar.tsx: kept design refactor, added upstream upstreamRequestId field
- summary-cards.tsx: kept design layout, adapted to new useSummaryCardsConfig interface
- _reports/*.untranslated.json: design state kept (fr/vi removed, ja/ru ours)
- Other UI conflicts resolved per .gitattributes ours strategy

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

2 participants