Skip to content

feat: 为 Provider 和 Routes 页面添加搜索功能#118

Merged
lxw15337674 merged 1 commit intomainfrom
feat/add-search-to-providers-and-routes
Jan 18, 2026
Merged

feat: 为 Provider 和 Routes 页面添加搜索功能#118
lxw15337674 merged 1 commit intomainfrom
feat/add-search-to-providers-and-routes

Conversation

@Bowl42
Copy link
Collaborator

@Bowl42 Bowl42 commented Jan 17, 2026

Summary

  • Provider 列表页添加搜索框,支持按名称和显示信息过滤
  • Client Routes 页面 (/routes/claude 等) 添加搜索框,同时过滤已配置路由和可用 Provider
  • 添加 Custom Provider 模板的 Model Mapping 支持
  • 添加 NVIDIA 模板 (OpenAI 兼容,默认模型映射 * -> minimaxai/minimax-m2.1)
  • Provider 创建页面增加 Model Mapping 编辑功能
  • Provider 新增 Logo 字段,支持模板自动设置
  • 添加 88code、aicodemirror、nvidia 图标资源
  • 补充 i18n 翻译

Test plan

  • 访问 Provider 列表页,验证搜索框可按名称过滤
  • 访问 /routes/claude 页面,验证搜索框同时过滤路由列表和 Available Providers
  • 创建 Custom Provider,选择 NVIDIA 模板,验证 Model Mapping 自动填充
  • 验证 Provider 创建时可手动添加/编辑 Model Mapping
  • 验证模板 Logo 正确显示

Summary by CodeRabbit

发版说明

  • 新功能
    • 为客户端路由和提供商页面添加搜索功能,可按提供商名称和类型进行过滤
    • 在提供商配置中新增模型映射管理功能
    • 新增 NVIDIA NIM 提供商模板
    • 提供商现支持徽标显示
    • 扩展可用模型选项,包括 Llama 和 Meta 相关模型

✏️ Tip: You can customize this high-level summary in your review settings.

- Provider 列表页添加搜索框,支持按名称和显示信息过滤
- Client Routes 页面 (/routes/claude 等) 添加搜索框
- 搜索同时过滤已配置路由和可用 Provider
- 添加 Custom Provider 模板的 Model Mapping 支持
- 添加 NVIDIA 模板 (OpenAI 兼容,默认模型映射)
- Provider 创建页面增加 Model Mapping 编辑功能
- Provider 新增 Logo 字段,支持模板自动设置
- 添加 88code、aicodemirror、nvidia 图标资源
- 补充 i18n 翻译
@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

总体概览

此拉取请求为提供商(Provider)实体添加了徽标字段支持,实现了客户端路由和提供商管理页面的搜索功能,新增了NVIDIA提供商模板,并实现了提供商自定义流程中的模型映射管理UI及关联创建逻辑。

变更明细

队列/文件 变更摘要
数据模型与类型定义
internal/domain/model.go, web/src/lib/transport/types.ts
为Provider结构体/接口添加可选的logo字段(字符串类型),支持存储徽标URL或数据URI。无其他行为或结构变更。
国际化配置
web/src/locales/en.json, web/src/locales/zh.json
添加新的翻译键:"search"和"searchProviders";新增NVIDIA提供商模板条目,包含名称和描述。
搜索功能集成
web/src/components/routes/ClientTypeRoutesContent.tsx, web/src/pages/client-routes/index.tsx, web/src/pages/providers/index.tsx
为路由内容和提供商页面实现搜索过滤:添加searchQuery状态和Input UI元素;按提供商名称/类型过滤项目(不区分大小写);更新相关依赖项以支持动态过滤。
模型与模板管理
web/src/components/ui/model-input.tsx, web/src/pages/providers/types.ts
扩展COMMON_MODELS列表增加NVIDIA和Meta相关模型及通配符;定义新的TemplateModelMapping类型;扩展QuickTemplate和ProviderFormData以支持modelMappings和logo字段;为现有模板添加logoUrl,新增NVIDIA提供商模板。
提供商创建与定制流程
web/src/pages/providers/components/custom-config-step.tsx, web/src/pages/providers/components/select-type-step.tsx
custom-config-step新增模型映射UI部分(包含添加/删除映射的界面);集成useCreateModelMapping hook以在提供商创建后异步创建多个模型映射;select-type-step更新以应用模板时同步设置modelMappings和logo字段。

序列图

sequenceDiagram
    actor User
    participant UI as 自定义步骤UI
    participant Service as 提供商服务
    participant MappingAPI as 模型映射API
    
    User->>UI: 填写提供商信息和模型映射
    User->>UI: 点击保存
    UI->>Service: 创建提供商 (含logo)
    Service-->>UI: 返回提供商ID
    
    alt 存在模型映射
        loop 对每个映射
            UI->>MappingAPI: 创建模型映射 (pattern→target)
            MappingAPI-->>UI: 映射创建成功
        end
    end
    
    UI->>UI: 标记保存成功
    UI-->>User: 显示成功提示
Loading

代码审查工作量评估

🎯 3 (中等复杂度) | ⏱️ ~25 分钟

相关联的拉取请求

建议审查者

  • awsl233777

庆祝诗

🐰 兔兔的庆祝之歌
搜索和映射齐上阵,
NVIDIA新宠入家门,
Logo闪闪耀光辉,
模板配置更便捷,
提供商管理升级啦!🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确反映了PR的主要变更:为Provider和Routes页面添加搜索功能,与代码变更内容相符。

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@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.

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (2)
web/src/components/routes/ClientTypeRoutesContent.tsx (1)

104-124: 过滤状态下允许拖拽会导致路由顺序错乱。
searchQuery 非空时只对可见子集排序更新,隐藏项保留旧 position,容易出现重复/错序。建议在过滤时禁用拖拽,或基于全量列表计算新顺序。

🛠️ 建议修复(示例:过滤时禁用拖拽)
-  const loading = routesLoading || providersLoading;
+  const loading = routesLoading || providersLoading;
+  const isFiltering = !!searchQuery.trim();
-  const handleDragStart = (event: DragStartEvent) => {
-    setActiveId(event.active.id as string);
-  };
+  const handleDragStart = (event: DragStartEvent) => {
+    if (isFiltering) return;
+    setActiveId(event.active.id as string);
+  };
-  const handleDragEnd = (event: DragEndEvent) => {
+  const handleDragEnd = (event: DragEndEvent) => {
+    if (isFiltering) return;
     const { active, over } = event;
web/src/pages/providers/components/custom-config-step.tsx (1)

34-60: 模型映射创建失败会导致“已创建 Provider 但页面报错”。
Provider 已创建后若映射创建失败会进入 error 状态,用户可能重复创建;同时空 pattern/target 也可能触发无效请求。建议过滤空映射并用 allSettled 处理失败(必要时提示用户或引导到编辑页重试)。

🛠️ 建议修复(示例)
-      // Create model mappings if template has any
-      if (formData.modelMappings && formData.modelMappings.length > 0) {
-        for (const mapping of formData.modelMappings) {
-          await createModelMapping.mutateAsync({
-            scope: 'provider',
-            providerID: provider.id,
-            pattern: mapping.pattern,
-            target: mapping.target,
-          });
-        }
-      }
+      const mappings = (formData.modelMappings ?? []).filter(
+        (m) => m.pattern.trim() && m.target.trim()
+      );
+      if (mappings.length > 0) {
+        await Promise.allSettled(
+          mappings.map((mapping) =>
+            createModelMapping.mutateAsync({
+              scope: 'provider',
+              providerID: provider.id,
+              pattern: mapping.pattern,
+              target: mapping.target,
+            })
+          )
+        );
+      }
🤖 Fix all issues with AI agents
In `@internal/domain/model.go`:
- Around line 91-92: The Provider GORM model is missing the Logo field added to
the domain model; update the Provider struct in
internal/repository/sqlite/models.go to include a Logo string field mapped to
the JSON/tag and GORM column (e.g., Logo string `json:"logo,omitempty"
gorm:"column:logo;size:2048"`), adding a size limit (suggest ~2048) to prevent
oversized data URIs and ensure AutoMigrate creates the logo column; keep the
JSON tag consistent with the domain model.

In `@web/src/pages/client-routes/index.tsx`:
- Around line 38-48: 为搜索输入补充无障碍标签:在使用的 Input 组件(在这段代码块中引用的 Input)上添加 aria-label
或为其生成关联的 <label>(使用相同的翻译文本 t('common.searchProviders') 以保持一致),确保 Input 保留现有的
placeholder、value 和 onChange;如果添加 <label>,给 Input 一个唯一 id 并将 <label
htmlFor={id}> 包裹或放在相应位置;同时保留 Search 图标不影响可访问性(图标保持装饰性,确保其 role 或 aria-hidden 设为
true 如有必要)。

In `@web/src/pages/providers/components/custom-config-step.tsx`:
- Around line 172-245: The delete Button that renders only the Trash2 icon in
the modelMappings list lacks accessible text—update the Button (the one with
variant="ghost" size="icon" wrapping <Trash2 /> inside the map iteration) to
include an aria-label and title (e.g.
aria-label={t('routes.modelMapping.removeMapping')}
title={t('routes.modelMapping.removeMapping')}) and mark the <Trash2 /> icon
aria-hidden="true" to avoid duplicate announcements; ensure the i-th removal
onClick logic remains unchanged so accessibility is added without affecting
behavior.

In `@web/src/pages/providers/components/select-type-step.tsx`:
- Around line 44-45: The template’s modelMappings reference is being assigned
directly (modelMappings: template.modelMappings) which can mutate the original
template if the form allows edits; in the SelectTypeStep component, replace the
direct reference with a copy of template.modelMappings (use a shallow copy for
arrays/objects via spread or a deep copy via JSON.parse(JSON.stringify(...)) or
structuredClone) so the form state owns its own data and does not mutate
template.modelMappings; keep logo: template.logoUrl as-is.

In `@web/src/pages/providers/index.tsx`:
- Around line 123-134: The search input lacks an explicit accessibility label;
update the Input used in this block (the Input component bound to searchQuery
with onChange={(e) => setSearchQuery(e.target.value)}) to include an aria-label
(or associate a visible <label>) such as aria-label={t('common.search')} so
screen readers can identify the field; ensure the Search icon remains decorative
(e.g., aria-hidden="true" or role="presentation") if applicable.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5eb630e and 9aa6aff.

⛔ Files ignored due to path filters (3)
  • web/src/assets/icons/88code.svg is excluded by !**/*.svg
  • web/src/assets/icons/aicodemirror.png is excluded by !**/*.png
  • web/src/assets/icons/nvidia.svg is excluded by !**/*.svg
📒 Files selected for processing (11)
  • internal/domain/model.go
  • web/src/components/routes/ClientTypeRoutesContent.tsx
  • web/src/components/ui/model-input.tsx
  • web/src/lib/transport/types.ts
  • web/src/locales/en.json
  • web/src/locales/zh.json
  • web/src/pages/client-routes/index.tsx
  • web/src/pages/providers/components/custom-config-step.tsx
  • web/src/pages/providers/components/select-type-step.tsx
  • web/src/pages/providers/index.tsx
  • web/src/pages/providers/types.ts
🧰 Additional context used
🧬 Code graph analysis (3)
web/src/components/routes/ClientTypeRoutesContent.tsx (3)
internal/domain/model.go (1)
  • Provider (76-99)
web/src/lib/transport/types.ts (1)
  • Provider (43-52)
internal/repository/sqlite/models.go (2)
  • Provider (115-121)
  • Provider (123-123)
web/src/pages/client-routes/index.tsx (4)
web/src/lib/transport/types.ts (1)
  • ClientType (8-8)
web/src/components/ui/index.ts (1)
  • Input (23-23)
web/src/components/ui/input.tsx (1)
  • Input (20-20)
web/src/components/routes/ClientTypeRoutesContent.tsx (1)
  • ClientTypeRoutesContent (54-371)
web/src/pages/providers/index.tsx (3)
web/src/pages/providers/types.ts (2)
  • PROVIDER_TYPE_CONFIGS (30-63)
  • ProviderTypeKey (14-14)
web/src/components/ui/index.ts (1)
  • Input (23-23)
web/src/components/ui/input.tsx (1)
  • Input (20-20)
🔇 Additional comments (14)
web/src/components/ui/model-input.tsx (1)

51-72: 新增 NVIDIA/Meta 常见模型清单 OK
扩展模型列表与现有过滤/分组逻辑兼容,整体看起来合理。

web/src/locales/en.json (2)

39-41: 新增搜索相关文案 OK
与新增搜索功能匹配。


574-576: 新增 NVIDIA 模板文案 OK
与模板扩展保持一致。

web/src/lib/transport/types.ts (1)

49-49: 类型扩展与后端对齐
新增 logo?: string 与后端字段一致。

web/src/locales/zh.json (2)

39-41: 新增搜索相关中文文案 OK
与新增搜索功能匹配。


573-576: 新增 NVIDIA 模板中文文案 OK
与模板扩展保持一致。

web/src/pages/client-routes/index.tsx (2)

6-19: 搜索状态与 i18n 接入清晰。


54-58: searchQuery 下传到内容组件很清晰。

web/src/components/routes/ClientTypeRoutesContent.tsx (2)

48-58: searchQuery 作为可选 prop 设计合理。


128-143: Available Providers 的搜索过滤符合预期。

web/src/pages/providers/index.tsx (1)

36-59: 按名称与显示信息过滤后再分组逻辑正确。

web/src/pages/providers/types.ts (3)

80-98: 模板模型映射类型与字段扩展清晰。


108-172: 模板 Logo 与 NVIDIA 模板补充到位。


198-200: ProviderFormData 新字段与创建流程一致。

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +91 to +92
// Logo URL 或 data URI
Logo string `json:"logo,omitempty"`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -type f \( -name "*migration*" -o -name "*migrations*" -o -name "*schema*" \) | head -20

Repository: awsl-project/maxx

Length of output: 188


🏁 Script executed:

rg -l "migrations|migration" --type go --type sql | head -20

Repository: awsl-project/maxx

Length of output: 171


🏁 Script executed:

rg -n "logo" -i -t go -t sql . 2>/dev/null | head -40

Repository: awsl-project/maxx

Length of output: 181


🏁 Script executed:

rg -n "type Provider struct" -A 50 internal/domain/model.go

Repository: awsl-project/maxx

Length of output: 1409


🏁 Script executed:

cat -n internal/repository/sqlite/migrations.go

Repository: awsl-project/maxx

Length of output: 5457


🏁 Script executed:

cat -n internal/repository/sqlite/models.go | head -100

Repository: awsl-project/maxx

Length of output: 2771


🏁 Script executed:

rg -n "validate|Validate" internal/domain/model.go

Repository: awsl-project/maxx

Length of output: 43


🏁 Script executed:

cat -n internal/repository/sqlite/models.go | grep -A 30 "type Provider struct"

Repository: awsl-project/maxx

Length of output: 1135


🏁 Script executed:

rg -n "Logo" internal/repository/sqlite/models.go

Repository: awsl-project/maxx

Length of output: 43


🏁 Script executed:

cat -n docs/database-migrations.md

Repository: awsl-project/maxx

Length of output: 6890


Logo 字段缺失 GORM 模型定义,导致数据无法持久化

Logo 字段已添加到域模型 (internal/domain/model.go:91-92),但在 GORM 模型 (internal/repository/sqlite/models.go:115-121) 中缺失。由于 AutoMigrate 仅处理 GORM 模型中定义的字段,缺少该定义会导致数据库列不被创建,Logo 数据将被丢弃。

必须在 Provider 结构体中补充 Logo 字段定义,建议添加长度限制以防止超长 data URI 导致存储膨胀。

🤖 Prompt for AI Agents
In `@internal/domain/model.go` around lines 91 - 92, The Provider GORM model is
missing the Logo field added to the domain model; update the Provider struct in
internal/repository/sqlite/models.go to include a Logo string field mapped to
the JSON/tag and GORM column (e.g., Logo string `json:"logo,omitempty"
gorm:"column:logo;size:2048"`), adding a size limit (suggest ~2048) to prevent
oversized data URIs and ensure AutoMigrate creates the logo column; keep the
JSON tag consistent with the domain model.

Comment on lines +38 to +48
<div className="relative">
<Search
size={14}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
/>
<Input
placeholder={t('common.searchProviders')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 w-48"
/>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

为搜索输入补充可访问性标签。
仅依赖 placeholder 不利于读屏器识别,建议添加 aria-label 或显式 label。

🧩 建议修复
-          <Input
-            placeholder={t('common.searchProviders')}
-            value={searchQuery}
-            onChange={(e) => setSearchQuery(e.target.value)}
-            className="pl-9 w-48"
-          />
+          <Input
+            type="search"
+            aria-label={t('common.searchProviders')}
+            placeholder={t('common.searchProviders')}
+            value={searchQuery}
+            onChange={(e) => setSearchQuery(e.target.value)}
+            className="pl-9 w-48"
+          />
📝 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
<div className="relative">
<Search
size={14}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
/>
<Input
placeholder={t('common.searchProviders')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 w-48"
/>
<div className="relative">
<Search
size={14}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
/>
<Input
type="search"
aria-label={t('common.searchProviders')}
placeholder={t('common.searchProviders')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 w-48"
/>
🤖 Prompt for AI Agents
In `@web/src/pages/client-routes/index.tsx` around lines 38 - 48,
为搜索输入补充无障碍标签:在使用的 Input 组件(在这段代码块中引用的 Input)上添加 aria-label 或为其生成关联的
<label>(使用相同的翻译文本 t('common.searchProviders') 以保持一致),确保 Input 保留现有的
placeholder、value 和 onChange;如果添加 <label>,给 Input 一个唯一 id 并将 <label
htmlFor={id}> 包裹或放在相应位置;同时保留 Search 图标不影响可访问性(图标保持装饰性,确保其 role 或 aria-hidden 设为
true 如有必要)。

Comment on lines +172 to +245
{/* Model Mapping Section */}
<div className="space-y-6">
<div className="flex items-center justify-between border-b border-border pb-2">
<h3 className="text-lg font-semibold text-text-primary">
{t('modelMappings.title')}
</h3>
<Button
variant="outline"
size="sm"
onClick={() => {
const newMappings = [...(formData.modelMappings || []), { pattern: '', target: '' }];
updateFormData({ modelMappings: newMappings });
}}
>
<Plus size={14} />
{t('routes.modelMapping.addMapping')}
</Button>
</div>

{formData.modelMappings && formData.modelMappings.length > 0 ? (
<div className="space-y-3">
{formData.modelMappings.map((mapping, index) => (
<div key={index} className="flex items-center gap-3 p-3 bg-muted/50 rounded-lg">
<div className="flex-1">
<label className="text-xs text-muted-foreground mb-1 block">
{t('settings.matchPattern')}
</label>
<Input
type="text"
value={mapping.pattern}
onChange={(e) => {
const newMappings = [...(formData.modelMappings || [])];
newMappings[index] = { ...newMappings[index], pattern: e.target.value };
updateFormData({ modelMappings: newMappings });
}}
placeholder="*claude*, *sonnet*, *"
className="font-mono text-sm"
/>
</div>
<ArrowRight size={16} className="text-muted-foreground shrink-0 mt-5" />
<div className="flex-1">
<label className="text-xs text-muted-foreground mb-1 block">
{t('settings.targetModel')}
</label>
<ModelInput
value={mapping.target}
onChange={(value) => {
const newMappings = [...(formData.modelMappings || [])];
newMappings[index] = { ...newMappings[index], target: value };
updateFormData({ modelMappings: newMappings });
}}
placeholder={t('modelInput.selectOrEnter')}
/>
</div>
<Button
variant="ghost"
size="icon"
className="shrink-0 mt-5 text-muted-foreground hover:text-destructive"
onClick={() => {
const newMappings = (formData.modelMappings || []).filter((_, i) => i !== index);
updateFormData({ modelMappings: newMappings });
}}
>
<Trash2 size={14} />
</Button>
</div>
))}
</div>
) : (
<div className="text-sm text-muted-foreground p-4 bg-muted/30 rounded-lg text-center">
{t('modelMappings.noMappings')}
</div>
)}
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

删除按钮为纯图标,建议补充可访问性文本。
为图标按钮添加 aria-label/title 可提升可访问性与可用性。

🧩 建议修复
-                    <Button
+                    <Button
                       variant="ghost"
                       size="icon"
                       className="shrink-0 mt-5 text-muted-foreground hover:text-destructive"
+                      aria-label={t('common.delete')}
+                      title={t('common.delete')}
                       onClick={() => {
                         const newMappings = (formData.modelMappings || []).filter((_, i) => i !== index);
                         updateFormData({ modelMappings: newMappings });
                       }}
                     >
🤖 Prompt for AI Agents
In `@web/src/pages/providers/components/custom-config-step.tsx` around lines 172 -
245, The delete Button that renders only the Trash2 icon in the modelMappings
list lacks accessible text—update the Button (the one with variant="ghost"
size="icon" wrapping <Trash2 /> inside the map iteration) to include an
aria-label and title (e.g. aria-label={t('routes.modelMapping.removeMapping')}
title={t('routes.modelMapping.removeMapping')}) and mark the <Trash2 /> icon
aria-hidden="true" to avoid duplicate announcements; ensure the i-th removal
onClick logic remains unchanged so accessibility is added without affecting
behavior.

Comment on lines +44 to +45
modelMappings: template.modelMappings,
logo: template.logoUrl,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

避免直接复用模板的 modelMappings 引用
如果后续允许在表单中编辑映射,直接复用模板数组/对象可能污染模板数据,影响再次选择模板的初始值。建议做浅/深拷贝后再写入表单状态。

🛠 建议修复
-        modelMappings: template.modelMappings,
+        modelMappings: template.modelMappings?.map((m) => ({ ...m })),
📝 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
modelMappings: template.modelMappings,
logo: template.logoUrl,
modelMappings: template.modelMappings?.map((m) => ({ ...m })),
logo: template.logoUrl,
🤖 Prompt for AI Agents
In `@web/src/pages/providers/components/select-type-step.tsx` around lines 44 -
45, The template’s modelMappings reference is being assigned directly
(modelMappings: template.modelMappings) which can mutate the original template
if the form allows edits; in the SelectTypeStep component, replace the direct
reference with a copy of template.modelMappings (use a shallow copy for
arrays/objects via spread or a deep copy via JSON.parse(JSON.stringify(...)) or
structuredClone) so the form state owns its own data and does not mutate
template.modelMappings; keep logo: template.logoUrl as-is.

Comment on lines +123 to +134
<div className="relative">
<Search
size={14}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
/>
<Input
placeholder={t('common.search')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 w-48"
/>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

搜索框缺少显式可访问性标签。
建议补充 aria-label(或 label)以提升读屏器可用性。

🧩 建议修复
-          <Input
-            placeholder={t('common.search')}
-            value={searchQuery}
-            onChange={(e) => setSearchQuery(e.target.value)}
-            className="pl-9 w-48"
-          />
+          <Input
+            type="search"
+            aria-label={t('common.search')}
+            placeholder={t('common.search')}
+            value={searchQuery}
+            onChange={(e) => setSearchQuery(e.target.value)}
+            className="pl-9 w-48"
+          />
📝 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
<div className="relative">
<Search
size={14}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
/>
<Input
placeholder={t('common.search')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 w-48"
/>
</div>
<div className="relative">
<Search
size={14}
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
/>
<Input
type="search"
aria-label={t('common.search')}
placeholder={t('common.search')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9 w-48"
/>
</div>
🤖 Prompt for AI Agents
In `@web/src/pages/providers/index.tsx` around lines 123 - 134, The search input
lacks an explicit accessibility label; update the Input used in this block (the
Input component bound to searchQuery with onChange={(e) =>
setSearchQuery(e.target.value)}) to include an aria-label (or associate a
visible <label>) such as aria-label={t('common.search')} so screen readers can
identify the field; ensure the Search icon remains decorative (e.g.,
aria-hidden="true" or role="presentation") if applicable.

@lxw15337674 lxw15337674 merged commit b919360 into main Jan 18, 2026
2 checks passed
@lxw15337674 lxw15337674 deleted the feat/add-search-to-providers-and-routes branch January 18, 2026 01:31
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