fix(web): handle unlimited API key quota validation#4881
Conversation
WalkthroughThe 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. ChangesAPI Key Form Validation Refactor
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
web/default/src/features/keys/components/api-keys-mutate-drawer.tsx (1)
155-158: ⚡ Quick winMemoize the schema and resolver.
getApiKeyFormSchema(t)andzodResolver(schema)are rebuilt on every render, including every field change. Wrapping them inuseMemokeeps 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: UseuseMemoanduseCallbackjudiciously to reduce unnecessary re-renders; avoid creating new objects/arrays in render paths; useReact.memowhen 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 winUse 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 winUse semantic hierarchical i18n keys for these new entries.
Both new keys are sentence literals. Please switch them to structured keys (for example,
validation.fixHighlightedFieldsBeforeSavingandvalidation.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 asdashboard.overview.titleand 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
📒 Files selected for processing (9)
web/default/src/features/keys/components/api-keys-mutate-drawer.tsxweb/default/src/features/keys/lib/api-key-form.tsweb/default/src/features/keys/lib/index.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
Calcium-Ion
left a comment
There was a problem hiding this comment.
LGTM. 审了 diff:
根因分析正确:当 unlimited_quota = true 时 remain_quota_dollars 字段被隐藏,但 zod schema 仍然要求 min(0) 校验。用户切换到无限额度后再提交,隐藏的 remain_quota_dollars 可能是 undefined 导致 validation 静默失败,表现为"保存无响应"。
修复要点:
apiKeyFormSchema→getApiKeyFormSchema(t)工厂函数:支持 i18n 的校验消息。.superRefine中判断unlimited_quota— 如果开启了无限额度就跳过remain_quota_dollars校验,否则要求 >= 0。逻辑正确。transformApiKeyToFormDefaults中当unlimited_quota时remain_quota_dollars置为 0 而非从 API 取值 — 避免编辑时回填一个可能过时的数值到隐藏字段。onInvalidhandler + toast — 让 zod 校验失败时用户能看到提示而非静默无反应。- i18n keys 全语种都补了。
改动只涉及前端 form schema,无后端影响。
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>
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
修复 default 主题下 API Key 编辑表单的隐藏额度校验问题。
当 API Key 开启无限额度时,后端返回的负数剩余额度仍会被写入前端表单的隐藏额度字段,导致 zod 在提交前拦截校验,表现为点击保存无请求、无错误提示。现在在无限额度场景下会将该隐藏额度归一化为 0,并跳过额度字段校验;非无限额度仍保持非负校验。同时补充了表单校验失败提示和相关 i18n 文案,避免静默失败。
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)
Summary by CodeRabbit
Improvements
Localization