fix: enable provider group editing in edit user dialog#560
fix: enable provider group editing in edit user dialog#560NieiR wants to merge 2 commits intoding113:devfrom
Conversation
- Always show providerGroup field in edit mode (was hidden when user had no providerGroup) - Replace read-only Badge display with editable ProviderGroupSelect component - Move modelSuggestions hook after form declaration to support dynamic updates Regression from ding113#539
📝 WalkthroughWalkthrough编辑对话框的 providerGroup 字段在编辑模式下始终显示;将 modelSuggestions 的来源改为基于 currentUserDraft.providerGroup;将 providerGroup 的 UI 从 Badge 切换为 Changes
Estimated code review effort🎯 3 (中等) | ⏱️ ~20 分钟 Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Summary of ChangesHello @NieiR, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves a regression that prevented the modification of the 'providerGroup' field when editing existing user profiles. The changes ensure that the 'providerGroup' field is consistently displayed and fully editable within the user management interface, enhancing the overall user experience for administrators. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request successfully addresses a regression where the provider group for a user could not be edited. The changes correctly ensure the provider group field is always visible in the edit dialog and replace the read-only display with the editable ProviderGroupSelect component. Additionally, the useModelSuggestions hook has been refactored to react to changes in the form's state, which is a good improvement. I've identified one medium-severity issue regarding missing translations for the new component, which could impact user experience by showing untranslated error messages.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsx (1)
414-422: 验证默认值行为是否符合预期
ProviderGroupSelect组件的使用正确地修复了回归问题,使 providerGroup 字段可编辑。但需要注意:
- 第 415 行使用
user.providerGroup || PROVIDER_GROUP.DEFAULT作为回退值- 而 schema 中
providerGroup定义为nullable().optional()(edit-user-dialog.tsx 第 39 行)- 如果
normalizeProviderGroup返回 null/empty,但 UI 显示 DEFAULT,可能会导致用户困惑(显示值与实际存储值不一致)请确认这个默认值回退是否符合业务逻辑要求,或者是否应该允许显示空值/占位符。
另外,
disabled={false}是明确的但不是必需的(false 是默认值),可以考虑移除以简化代码:♻️ 可选的代码简化
<ProviderGroupSelect value={user.providerGroup || PROVIDER_GROUP.DEFAULT} onChange={(val) => emitChange("providerGroup", val)} - disabled={false} translations={{ label: translations.fields.providerGroup.label, placeholder: translations.fields.providerGroup.placeholder, }} />src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx (1)
228-228: 明确传递 showProviderGroup 属性显式传递
showProviderGroup属性确保 providerGroup 字段在编辑模式下始终显示,与第 76 行的意图一致。可选:由于该值始终为 true,可以考虑使用简写形式以提高可读性:
♻️ 可选的代码简化
- showProviderGroup + showProviderGroup={true}或者如果定义一个常量:
+ showProviderGroup但当前的明确写法也完全可以接受。
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
📒 Files selected for processing (2)
src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsxsrc/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (CLAUDE.md)
Use 2-space indentation in all code files
Files:
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsxsrc/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use double quotes for strings instead of single quotes
Use trailing commas in multi-line structures
Enforce maximum line length of 100 characters
Use path alias@/*to reference files from./src/*directory
**/*.{ts,tsx,js,jsx}: Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Use path alias@/*to reference files in./src/*directory
Files:
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsxsrc/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
src/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{tsx,jsx}: Uselucide-reactfor icons, no custom SVGs
Use React's automatic escaping to prevent XSS vulnerabilities
Files:
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsxsrc/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript strict mode for type safety
Use readonly or const assertions for immutable data structures
Files:
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsxsrc/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
**/*.{tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Use next-intl for internationalization with 5 locales: en, ja, ru, zh-CN, zh-TW
Files:
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsxsrc/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
🧠 Learnings (2)
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to src/components/**/*.{tsx,jsx} : Use shadcn/ui component library for high-quality, accessible UI components
Applied to files:
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsx
📚 Learning: 2026-01-05T03:02:06.594Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx:66-66
Timestamp: 2026-01-05T03:02:06.594Z
Learning: In the claude-code-hub project, the translations.actions.addKey field in UserKeyTableRowProps is defined as optional for backward compatibility, but all actual callers in the codebase provide the complete translations object. The field has been added to all 5 locale files (messages/{locale}/dashboard.json).
Applied to files:
src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: pr-review
- GitHub Check: Greptile Review
- GitHub Check: pr-description
- GitHub Check: Docker Build Test
🔇 Additional comments (3)
src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsx (1)
25-25: 导入语句正确正确导入了
ProviderGroupSelect组件以替换之前的只读 Badge 显示。src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx (2)
75-76: 正确修复了 providerGroup 字段隐藏问题此修改修复了从 PR #539 引入的回归问题。之前使用
Boolean(user.providerGroup?.trim())作为条件,当用户的 providerGroup 为空时会隐藏该字段,导致无法在编辑模式下设置或修改 providerGroup。现在始终显示 providerGroup 字段,这是编辑对话框的正确行为。
126-128: 优秀的改进:模型建议现在响应实时更改将
useModelSuggestions移至表单声明之后,并使用currentUserDraft.providerGroup而不是原始的user.providerGroup,这是一个很好的改进:
- Hook 调用顺序仍然正确(所有 hooks 在顶层按一致顺序调用)
- 现在模型建议会根据用户在表单中选择的 provider group 实时更新,而不是基于原始值
- 这提供了更好的用户体验,使表单更具交互性
There was a problem hiding this comment.
Code Review Summary
No significant issues identified in this PR. The changes correctly fix the regression from #539 by always showing the providerGroup field and replacing the read-only Badge display with the editable ProviderGroupSelect component.
PR Size: XS
- Lines changed: 36 (16 additions + 20 deletions)
- 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 - Manual testing documented in PR
- Code clarity - Good
Automated review by Claude AI
There was a problem hiding this comment.
Code Review Summary
No significant issues identified in this PR. The changes correctly fix the regression from #539 by always showing the providerGroup field and replacing the read-only Badge display with the editable ProviderGroupSelect component.
PR Size: XS
- Lines changed: 36 (16 additions + 20 deletions)
- 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 - Manual testing documented in PR
- Code clarity - Good
Automated review by Claude AI
…ialog Pass full translations object to ProviderGroupSelect including: - tagInputErrors for validation messages (empty, duplicate, too_long, etc.) - errors.loadFailed for API error handling - providersSuffix for provider count display This fixes untranslated error messages when users input invalid provider group tags.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts (1)
139-149: 将硬编码的最大长度值提取为常量。第 143 行的
max: 50在代码中多处重复出现(edit-key-form.tsx、add-key-form.tsx、user-form.tsx 等文件中均有相同的硬编码值,以及 Zod 验证模式中的.max(50))。建议在文件顶部定义常量统一管理,便于后续维护。♻️ 建议的重构方案
在文件顶部定义常量:
"use client"; import { useTranslations } from "next-intl"; import { useMemo } from "react"; +// 供应商分组标签配置 +const PROVIDER_GROUP_TAG_MAX_LENGTH = 50; + export interface UserEditTranslations {然后在第 143 行使用该常量:
tagInputErrors: { empty: tUi("emptyTag"), duplicate: tUi("duplicateTag"), - too_long: tUi("tooLong", { max: 50 }), + too_long: tUi("tooLong", { max: PROVIDER_GROUP_TAG_MAX_LENGTH }), invalid_format: tUi("invalidFormat"), max_tags: tUi("maxTags"), },
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
📒 Files selected for processing (7)
messages/en/dashboard.jsonmessages/ja/dashboard.jsonmessages/ru/dashboard.jsonmessages/zh-CN/dashboard.jsonmessages/zh-TW/dashboard.jsonsrc/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsxsrc/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/app/[locale]/dashboard/_components/user/forms/user-edit-section.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (CLAUDE.md)
Use 2-space indentation in all code files
Files:
messages/zh-TW/dashboard.jsonmessages/ru/dashboard.jsonmessages/ja/dashboard.jsonmessages/zh-CN/dashboard.jsonmessages/en/dashboard.jsonsrc/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
messages/**/*.json
📄 CodeRabbit inference engine (CLAUDE.md)
Support 5 locales via next-intl: en, ja, ru, zh-CN, zh-TW with messages in
messages/{locale}/*.jsonStore message translations in
messages/{locale}/*.jsonfiles
Files:
messages/zh-TW/dashboard.jsonmessages/ru/dashboard.jsonmessages/ja/dashboard.jsonmessages/zh-CN/dashboard.jsonmessages/en/dashboard.json
**/*.{tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Use next-intl for internationalization with 5 locales: en, ja, ru, zh-CN, zh-TW
Files:
messages/zh-TW/dashboard.jsonmessages/ru/dashboard.jsonmessages/ja/dashboard.jsonmessages/zh-CN/dashboard.jsonmessages/en/dashboard.json
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use double quotes for strings instead of single quotes
Use trailing commas in multi-line structures
Enforce maximum line length of 100 characters
Use path alias@/*to reference files from./src/*directory
**/*.{ts,tsx,js,jsx}: Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Use path alias@/*to reference files in./src/*directory
Files:
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript strict mode for type safety
Use readonly or const assertions for immutable data structures
Files:
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Hash API keys using SHA-256 before storing in database, never store plaintext keys
Mask API keys and sensitive data in application logs
Validate required environment variables at startup with clear error messages
Files:
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
src/app/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Implement Content-Security-Policy headers for XSS prevention
Files:
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx:66-66
Timestamp: 2026-01-05T03:02:06.594Z
Learning: In the claude-code-hub project, the translations.actions.addKey field in UserKeyTableRowProps is defined as optional for backward compatibility, but all actual callers in the codebase provide the complete translations object. The field has been added to all 5 locale files (messages/{locale}/dashboard.json).
📚 Learning: 2026-01-05T03:02:06.594Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx:66-66
Timestamp: 2026-01-05T03:02:06.594Z
Learning: In the claude-code-hub project, the translations.actions.addKey field in UserKeyTableRowProps is defined as optional for backward compatibility, but all actual callers in the codebase provide the complete translations object. The field has been added to all 5 locale files (messages/{locale}/dashboard.json).
Applied to files:
messages/ja/dashboard.jsonmessages/zh-CN/dashboard.jsonsrc/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
📚 Learning: 2026-01-03T09:08:20.573Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-03T09:08:20.573Z
Learning: Applies to messages/**/*.json : Support 5 locales via next-intl: en, ja, ru, zh-CN, zh-TW with messages in `messages/{locale}/*.json`
Applied to files:
messages/ja/dashboard.jsonmessages/zh-CN/dashboard.json
📚 Learning: 2026-01-05T03:01:39.354Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:39.354Z
Learning: In TypeScript interfaces, explicitly document and enforce distinct meanings for null and undefined. Example: for numeric limits like limitTotalUsd, use 'number | null | undefined' when null signifies explicitly unlimited (e.g., matches DB schema or special UI logic) and undefined signifies 'inherit default'. This pattern should be consistently reflected in type definitions across related fields to preserve semantic clarity between database constraints and UI behavior.
Applied to files:
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts
🧬 Code graph analysis (1)
src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts (1)
scripts/sync-settings-keys.js (1)
t(72-72)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Docker Build Test
🔇 Additional comments (8)
messages/ru/dashboard.json (1)
1340-1343:providerGroupSelect俄文文案与现有结构保持一致,LGTM
providersSuffix与下方providerGroup.providerCount的用法一致(“провайдеров”),loadFailed也与其它错误提示风格统一,JSON 结构与缩进正确,无需调整。messages/ja/dashboard.json (1)
1329-1332:providerGroupSelect日文翻译自然且与现有键兼容
providersSuffix与providerGroup.providerCount一致(“件のプロバイダー”),loadFailed采用项目中常见的“〜に失敗しました”表述,结构与缩进也都正确,可以直接使用。messages/zh-TW/dashboard.json (1)
1338-1341: 繁體中文providerGroupSelect鍵值與現有字串對齊,LGTM
providersSuffix與providerGroup.providerCount的量詞與名詞完全一致(“個供應商”),loadFailed也沿用本檔案的「載入…失敗」風格,結構與縮排正確。messages/en/dashboard.json (1)
1367-1370: 英文providerGroupSelect補全正確,與現有結構一致
providersSuffix: "providers"與下方providerGroup.providerCount的用法保持一致,loadFailed也沿用現有「Failed to …」錯誤訊息風格,JSON 結構無誤。messages/zh-CN/dashboard.json (1)
1368-1371: 简体中文providerGroupSelect词条补充完整且语义正确
providersSuffix与providerGroup.providerCount中的“{count} 个供应商”保持一致,loadFailed也符合本文件一贯的错误提示风格,JSON 结构无问题。src/app/[locale]/dashboard/_components/user/hooks/use-user-translations.ts (3)
29-39: 类型定义结构正确。新增的
providersSuffix、tagInputErrors和errors字段定义合理,所有字段都标记为可选,与父级providerGroup?字段的可选性保持一致。这种嵌套的可选结构符合 TypeScript 最佳实践。
112-112: 正确使用独立的翻译命名空间。为可复用的
ui.tagInput组件引入独立的翻译命名空间是合理的设计,有助于组件在不同上下文中复用。Hook 调用顺序符合 React 规则。
213-213: 正确更新了 memo 依赖项。依赖数组已正确更新为包含新增的
tUihook,确保当翻译命名空间变化时能够正确重新计算。所有使用的值都已包含在依赖项中,符合 ReactuseMemo最佳实践。
|
The user edit form itself does not allow modifying the provider group field. This logic was established in #424 |
Summary
Fixes regression from #539 where editing existing users could not modify the provider group field.
Changes
edit-user-dialog.tsxmodelSuggestionshook after form declarationuser-edit-section.tsxProviderGroupSelectcomponentRoot Cause
PR #539 introduced two issues:
showUserProviderGroup = Boolean(user.providerGroup?.trim())- field hidden when user had no providerGroupUserEditSectiondisplayed providerGroup as read-only Badges instead of editable inputTest Plan
Greptile Summary
Fixes regression from PR #539 that prevented editing the
providerGroupfield in the edit user dialog.Root cause analysis:
showUserProviderGroup = Boolean(user.providerGroup?.trim())hid the field when users had no existing providerGroupUserEditSectiondisplayed providerGroup as read-only Badges instead of an editable inputChanges made:
providerGroupfield in edit mode by settingshowProviderGroup: trueuseModelSuggestionshook after form declaration to react tocurrentUserDraft.providerGroupchangesProviderGroupSelectcomponent inuser-edit-section.tsxImpact:
Confidence Score: 5/5
Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant EditUserDialog participant useModelSuggestions participant UserEditSection participant ProviderGroupSelect participant Server User->>EditUserDialog: Open edit dialog EditUserDialog->>EditUserDialog: Always show providerGroup (showProviderGroup=true) EditUserDialog->>EditUserDialog: Read currentUserDraft.providerGroup EditUserDialog->>useModelSuggestions: Fetch models for current providerGroup useModelSuggestions->>Server: getModelSuggestionsByProviderGroup(providerGroup) Server-->>useModelSuggestions: Return model suggestions EditUserDialog->>UserEditSection: Render with editable providerGroup UserEditSection->>ProviderGroupSelect: Render editable select (not Badges) User->>ProviderGroupSelect: Change providerGroup value ProviderGroupSelect->>UserEditSection: onChange("providerGroup", newValue) UserEditSection->>EditUserDialog: handleUserChange("providerGroup", newValue) EditUserDialog->>EditUserDialog: Update form.values EditUserDialog->>useModelSuggestions: Re-fetch with new providerGroup useModelSuggestions->>Server: getModelSuggestionsByProviderGroup(newProviderGroup) Server-->>useModelSuggestions: Return updated suggestions User->>EditUserDialog: Submit form EditUserDialog->>Server: editUser(userId, formData) Server-->>EditUserDialog: Success EditUserDialog->>User: Show success toast