Conversation
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthrough新增后端批量更新路由位置的类型、接口、事务性仓储实现与缓存重载;新增 /admin/routes/batch-positions PUT 管理端点及服务方法;前端改为单次批量请求并实现乐观更新;大量前端组件接入 i18n 并做若干样式调整。 Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Client UI
participant QC as QueryClient (react-query)
participant T as HttpTransport (frontend)
participant H as AdminHandler (backend)
participant S as AdminService
participant R as RouteRepository (sqlite)
participant DB as Database
participant C as CachedRepo
UI->>QC: 用户拖拽完成,触发 reorder
QC->>UI: 立即应用乐观更新(更新本地 routes 列表)
UI->>T: PUT /routes/batch-positions {updates[]}
T->>H: HTTP PUT /admin/routes/batch-positions
H->>S: 调用 BatchUpdateRoutePositions(updates)
S->>R: 执行 BatchUpdatePositions(updates)
R->>DB: 开启事务,执行多次 UPDATE ... WHERE id=?
DB-->>R: 返回执行结果
R->>DB: 提交事务
R-->>S: 返回成功
S-->>H: 返回成功
H-->>T: 返回 200 OK
T-->>QC: 请求成功 -> 可能触发 invalidate / 确认状态
QC-->>UI: 保持或确认最终数据
Note over R,C: 若使用缓存层,BatchUpdatePositions 后触发 C.Load() 刷新缓存
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 分钟 Possibly related PRs
Suggested reviewers
Poem
🚥 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
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
✏️ Tip: You can disable this entire section by setting 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.
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 (12)
web/src/pages/projects/tabs/sessions.tsx (1)
65-74: 遗漏国际化:空状态提示文本未翻译。第 70 行的 "No sessions for this project" 仍是硬编码的英文字符串,与本文件其他部分的 i18n 实现不一致。
🌐 建议修复
{projectSessions.length === 0 && ( <TableRow> <TableCell colSpan={4} className="h-32 text-center text-muted-foreground border-border"> <div className="flex flex-col items-center justify-center gap-2"> <Users className="h-8 w-8 opacity-20" /> - <p>No sessions for this project</p> + <p>{t('sessions.noSessions')}</p> </div> </TableCell> </TableRow> )}请确保在翻译文件中添加对应的
sessions.noSessions键。web/src/pages/providers/components/provider-edit-flow.tsx (1)
349-391:DeleteConfirmModal组件中t未定义,会导致运行时错误。
t函数在第 36 行通过useTranslation()hook 定义,作用域仅限于ProviderEditFlow组件。DeleteConfirmModal是一个独立的函数组件,无法访问该变量,第 385 行使用t()会抛出ReferenceError。🐛 修复方案:在 DeleteConfirmModal 中添加 useTranslation hook
function DeleteConfirmModal({ providerName, deleting, open, onConfirm, onCancel, }: { providerName: string deleting: boolean open: boolean onConfirm: () => void onCancel: () => void }) { + const { t } = useTranslation() return ( <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onCancel()}>web/src/pages/providers/components/antigravity-provider-view.tsx (1)
92-105: ModelQuotaCard 组件中t未定义会导致运行时错误。
t仅在父组件 AntigravityProviderView 中通过useTranslation()声明,在 ModelQuotaCard 中直接使用会触发"undefined"错误。应在组件内调用useTranslation()获取t函数。function ModelQuotaCard({ model }: { model: AntigravityModelQuota }) { + const { t } = useTranslation() const displayName = modelDisplayNames[model.name] || model.name const color = getQuotaColor(model.percentage)web/src/pages/requests/detail/RequestSidebar.tsx (1)
105-106: 国际化不完整:存在硬编码字符串第 105 行的
Request字符串未翻译。同样,第 135 行的Upstream Attempts和第 172 行的Attempt也需要国际化处理。🔧 建议修复
- {getClientName(request.clientType as ClientType)} Request + {getClientName(request.clientType as ClientType)} {t('requests.request')}第 135 行:
- <Server size={12} /> Upstream Attempts + <Server size={12} /> {t('requests.upstreamAttempts')}第 172 行:
- Attempt {index + 1} + {t('requests.attempt')} {index + 1}web/src/components/force-project-dialog.tsx (3)
234-240: 国际化不完整:拒绝按钮文本未使用翻译第 234、239 行的 "拒绝中..." 和 "拒绝" 字符串仍为硬编码中文,应使用
t()函数以保持与其他翻译一致。🔧 建议修复
- <span className="text-sm font-bold">拒绝中...</span> + <span className="text-sm font-bold">{t('sessions.rejecting')}</span>- <span className="text-sm font-bold">拒绝</span> + <span className="text-sm font-bold">{t('sessions.reject')}</span>
259-271: 国际化不完整:确认按钮文本未使用翻译第 260、270 行的 "绑定中..." 和 "确认绑定" 字符串仍为硬编码中文。
🔧 建议修复
- <span className="text-sm font-bold text-white"> - 绑定中... - </span> + <span className="text-sm font-bold text-white"> + {t('sessions.binding')} + </span>- <span className="text-sm font-bold text-amber-400 group-hover:text-white transition-colors"> - 确认绑定 - </span> + <span className="text-sm font-bold text-amber-400 group-hover:text-white transition-colors"> + {t('sessions.confirmBind')} + </span>
278-281: 国际化不完整:提示信息未使用翻译第 280 行的提示文本 "如果未在规定时间内选择项目,请求将被拒绝。" 应使用翻译函数。
🔧 建议修复
- <p>如果未在规定时间内选择项目,请求将被拒绝。</p> + <p>{t('sessions.timeoutWarning')}</p>web/src/pages/providers/components/kiro-provider-view.tsx (1)
65-74:QuotaCard组件中的t未定义。
该组件在第 73 行使用了t('proxy.resetsIn')和formatResetDays(quota.days_until_reset, t),但t在组件内未被定义,会导致运行时 ReferenceError。需在QuotaCard内调用useTranslation()来获取t。🛠️ 建议修改
function QuotaCard({ quota }: { quota: KiroQuotaData }) { + const { t } = useTranslation() const percentage = quota.total_limit > 0 ? Math.round((quota.available / quota.total_limit) * 100) : 0web/src/components/layout/nav-proxy-status.tsx (1)
66-78: 按钮title硬编码为英文,与中文界面混用。应使用已有的
proxy.clickToCopyTooltip翻译键进行本地化处理。该翻译键已支持{{url}}参数。🛠️ 建议修改
- title={`Click to copy: ${fullUrl}`} + title={t('proxy.clickToCopyTooltip', { url: fullUrl })}web/src/main.tsx (1)
12-46: 修复ErrorFallback中的 Hook 违规问题。
ErrorFallback包含useTranslation()钩子但被作为普通函数调用。TransportProvider在context.tsx第 109 行调用errorFallback(state.error)时,会违反 React Rules of Hooks,导致运行时错误。建议改为组件方式调用:
- 修改
ErrorFallback接收error作为 props:function ErrorFallback({ error }: { error: Error }) { const { t } = useTranslation(); // ... }- 在
main.tsx中传递为组件:errorFallback={<ErrorFallback error={...} />}或修改TransportProvider的类型定义支持组件方式。web/src/components/cooldown-details-dialog.tsx (1)
21-21: 移除未使用的 CooldownReason 导入以修复 ESLint 失败CI 已报
CooldownReason未使用(no-unused-vars),会阻断合并。🧹 建议修改
-import type { Cooldown, CooldownReason } from '@/lib/transport/types' +import type { Cooldown } from '@/lib/transport/types'web/src/pages/providers/components/provider-card.tsx (1)
132-152: CustomProviderCard 中缺少 useTranslation,导致 t 未定义
CustomProviderCard组件在第 151、176、228、235 行多处使用t(...)进行国际化,但组件内未调用useTranslation()钩子,导致运行时会抛出"t is not defined"错误。🛠️ 建议修改
export function CustomProviderCard({ provider, onClick, streamingCount, }: ProviderCardProps) { + const { t } = useTranslation() const { getCooldownForProvider, formatRemaining, clearCooldown, isClearingCooldown, } = useCooldowns()
🤖 Fix all issues with AI agents
In `@web/src/components/cooldown-details-dialog.tsx`:
- Line 2: 删除未使用的类型导入 CooldownReason,并把 getReasonInfo 的 t 参数类型从 (key: string) =>
string 改为 i18next 的 TFunction(引入或使用 useTranslation 提供的 TFunction 类型),然后在
getReasonInfo 内使用 i18next 的 defaultValue 对象形式(即传入 t(key, { defaultValue: '...'
}) 而非第二个 string 参数);确保相关导入 useTranslation/ TFunction 一并调整并移除多余的 CooldownReason
引入以消除 ESLint 错误。
In `@web/src/components/provider-details-dialog.tsx`:
- Line 2: getReasonInfo currently types its t parameter as (key: string) =>
string which disallows passing the second options argument; change the type to
TFunction from react-i18next (import it alongside useTranslation) and update
calls inside getReasonInfo to pass the defaultValue via the second argument
(e.g. t('key', { defaultValue: '...' })) so TypeScript accepts the two-argument
form and default copy is provided.
In `@web/src/components/ui/model-input.tsx`:
- Around line 130-138: The default parameter for placeholder currently calls
t('modelInput.selectOrEnter') before t is defined, causing a runtime error;
update the ModelInput component by removing the placeholder default that invokes
t and instead compute the placeholder inside the function body after const { t }
= useTranslation() (e.g., derive a local placeholderValue = placeholder ??
t('modelInput.selectOrEnter')) and use that value throughout the component;
reference the ModelInput function and the t symbol when making this change.
In `@web/src/lib/transport/http-transport.ts`:
- Around line 172-174: batchUpdateRoutePositions 使用了 RoutePositionUpdate 类型但未从
types.ts 导入,导致 TS 编译失败;修复方法是在该文件的导入列表中添加 RoutePositionUpdate(从 types.ts 导出),以便
batchUpdateRoutePositions(updates: RoutePositionUpdate[]) 能正确解析类型(定位符:函数名
batchUpdateRoutePositions、类型名 RoutePositionUpdate、来源 types.ts)。
In `@web/src/lib/transport/interface.ts`:
- Line 69: batchUpdateRoutePositions uses the type RoutePositionUpdate which is
not imported; fix by adding RoutePositionUpdate to the existing import list at
the top of the file (the import block that brings in other route-related types)
and import it from the module where RoutePositionUpdate is defined so the
batchUpdateRoutePositions signature compiles correctly.
In `@web/src/locales/en.json`:
- Around line 348-373: The file has duplicated top-level keys (e.g., "routes",
"requests", "routingStrategies", "projects", "sessions", "common") which causes
later entries to overwrite earlier ones; open en.json and merge all fragments
for each duplicated key into a single object per key (for example combine the
"routes" object entries like "modelMapping", "modelMappingHelp", "update",
"create", "customRoutes", etc. into one "routes" object), deduplicate any
repeated nested keys while preserving all unique translation strings, remove the
extra repeated top-level blocks, and validate the resulting JSON to ensure no
duplicate keys remain.
- Around line 375-386: The i18n interpolation in the locale entries uses JS
template syntax instead of the i18n placeholder format, so update the values for
the "requestId" and "attemptId" keys to use the i18n interpolation syntax
(replace "Request #${id}" with "Request #{{id}}" and "Attempt #${id}" with
"Attempt #{{id}}") so the runtime will substitute the id correctly; locate and
edit the "requestId" and "attemptId" entries in the JSON to apply these changes.
In `@web/src/locales/zh.json`:
- Around line 239-464: The file contains duplicate top-level keys (e.g.,
"routes", "requests", "routingStrategies", "projects", "sessions", "common")
which causes earlier translations to be overwritten; locate each repeated key
(such as the second "routes" block and the later "requests",
"routingStrategies", "projects", "sessions", "common") and merge their
properties into the original objects instead of re-declaring the keys, removing
the duplicate key blocks and resolving any property conflicts by keeping unique
translations or combining entries, then validate the JSON to ensure a single
definition per top-level key.
- Around line 375-386: Replace the non-i18next interpolation placeholders
"${id}" used in the translation values for keys like "requestId" and "attemptId"
with i18next-style "{{id}}"; update the strings "请求 #${id}" and "尝试 #${id}" to
use "请求 #{{id}}" and "尝试 #{{id}}" so i18next will interpolate the id correctly.
In `@web/src/pages/api-tokens/index.tsx`:
- Line 2: Replace hardcoded English "Project #" strings in
web/src/pages/api-tokens/index.tsx (occurrences around lines ~2, ~50, and
~164-168) with a translation key via useTranslation (e.g., t('project.label') or
similar) and update the locale JSONs to include that key and localized values;
ensure you import/use useTranslation in the component where "Project #" appears
and update any JSX or helper functions that build those labels to call t(...)
instead of the literal string so translations will be used consistently.
In `@web/src/pages/client-routes/components/provider-row.tsx`:
- Line 25: The runtime failure is caused by t being out of scope: call
useTranslation() inside the ProviderRowContent component to obtain the t
function, remove the unused t declaration from SortableProviderRow, and update
formatResetTime to accept t as a parameter (e.g., formatResetTime(t, ...)) then
pass that t from ProviderRowContent into formatResetTime wherever it's called
(also update any call sites inside this file to pass the t argument).
In `@web/src/pages/projects/index.tsx`:
- Around line 112-148: The CardHeader currently renders project.slug twice
inside the same row (two sibling divs with class "flex items-center gap-1.5
text-xs font-mono ..." each containing <Hash /> and {project.slug}); remove the
duplicate by deleting one of those sibling divs so only a single slug badge
remains, keeping the remaining badge inside the parent container (the div with
class "flex items-center gap-3 mb-2") and ensuring layout/styles are preserved.
In `@web/src/pages/providers/components/provider-row.tsx`:
- Around line 234-236: The component calls formatResetTime(claudeInfo.resetTime,
t) and formatKiroResetDays(kiroInfo.resetDays, t) but `t` is not defined; import
and call useTranslation to get the translation function and pass it as `t` to
those calls. Specifically, add an import for useTranslation from the i18n
library used in the project, call const { t } = useTranslation() (or equivalent
hook) inside the component where formatResetTime and formatKiroResetDays are
used, and replace the undefined `t` reference so both
formatResetTime(claudeInfo.resetTime, t) and
formatKiroResetDays(kiroInfo.resetDays, t) receive the proper (key: string) =>
string function.
In `@web/src/pages/requests/index.tsx`:
- Around line 146-166: The Token column header is hard-coded as "Token" and
should use the translation helper like the other headers; update the TableHead
that currently contains the literal "Token" to call the i18n function (e.g.,
replace "Token" with t('requests.token') or the correct translation key) so it
matches the pattern used in the other TableHead elements (TableHead components
around the Token header).
🧹 Nitpick comments (11)
web/src/pages/providers/components/clients-config-section.tsx (2)
14-14: 缺少分号。此行缺少语句末尾的分号,与代码库中其他地方的风格不一致。
🔧 建议修复
- const { t } = useTranslation() + const { t } = useTranslation();
42-49: 国际化覆盖不完整:标签未翻译。
placeholder已使用t('common.default')进行国际化,但第 43 行的"Endpoint Override"标签仍然是硬编码的英文字符串。作为 i18n 改造的一部分,建议将标签也进行翻译以保持一致性。♻️ 建议修复
<label className="text-xs font-medium text-muted-foreground block mb-1.5 uppercase tracking-wide"> - Endpoint Override + {t('providers.endpointOverride')} </label>请确保在相应的翻译文件中添加
providers.endpointOverride键值。web/src/pages/providers/components/provider-edit-flow.tsx (1)
193-211: i18n 覆盖不完整:仍有多处硬编码字符串。以下 UI 文本尚未使用
t()进行国际化:
- 第 194 行: "Edit Provider"
- 第 197 行: "Update your custom provider settings"
- 第 207 行: "Delete"
- 第 210 行: "Cancel"
- 以及后续的表单标签、描述文字、错误信息和删除确认弹窗内容
建议保持一致性,将所有用户可见文本都纳入 i18n 范围。
web/src/pages/projects/tabs/overview.tsx (1)
87-100: 建议:日期格式化应与 i18n 语言环境保持一致。当前使用
toLocaleString()不带参数,会使用浏览器默认语言环境。为了与应用的国际化设置保持一致,建议使用 i18next 的当前语言作为 locale 参数。♻️ 建议的改进方案
+import { useTranslation } from 'react-i18next'; + export function OverviewTab({ project }: OverviewTabProps) { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); // ... <div className="grid grid-cols-2 gap-4 text-sm"> <div> <span className="text-text-secondary">{t('projects.created')}</span>{' '} <span className="text-text-primary"> - {new Date(project.createdAt).toLocaleString()} + {new Date(project.createdAt).toLocaleString(i18n.language)} </span> </div> <div> <span className="text-text-secondary">{t('projects.updated')}</span>{' '} <span className="text-text-primary"> - {new Date(project.updatedAt).toLocaleString()} + {new Date(project.updatedAt).toLocaleString(i18n.language)} </span> </div> </div>web/src/pages/routing-strategies/index.tsx (2)
84-86: “Global” 仍有硬编码入口,建议统一使用同一翻译键。
Line 85 已改为 t('common.global'),但下拉选项仍显示 “Global”,可能导致语言不一致;建议复用同一 key。
165-205: 表格区翻译完成,但同页仍有硬编码英文。
例如空状态 “No strategies”、页面标题/按钮、表单标题/标签、删除确认提示等未走 t(...),建议补齐以免 i18n 覆盖不全。web/src/pages/providers/components/antigravity-provider-view.tsx (1)
47-69: 时间单位仍硬编码,i18n 不完整。
目前仅对空值/过期文案做了翻译,d/h/m仍是英文;建议使用翻译 key(含复数/插值)或Intl.DurationFormat统一本地化。web/src/pages/client-routes/components/provider-row.tsx (1)
127-127: 为 dragHandleListeners 提供明确类型并核对 dnd-kit 接入
dragHandleListeners?: any会丢失类型约束,建议改为 dnd-kit 的监听器类型(如DraggableSyntheticListeners)。另外,拖拽把手现在只绑定 listeners,建议再确认 dnd-kit 对 drag handle 的推荐绑定方式(listeners / attributes / activator)是否满足你们的键盘与无障碍需求。♻️ 建议改进
import { useSortable } from '@dnd-kit/sortable' +import type { DraggableSyntheticListeners } from '@dnd-kit/core' @@ type ProviderRowContentProps = { @@ - dragHandleListeners?: any + dragHandleListeners?: DraggableSyntheticListeners }Also applies to: 162-162, 214-214, 301-304
web/src/pages/requests/detail/RequestSidebar.tsx (1)
40-53: 代码重复:EmptyState 组件已存在此本地
EmptyState组件与web/src/pages/requests/detail/components/EmptyState.tsx中的实现完全相同。建议删除本地定义,直接从 components 目录导入复用。♻️ 建议修复
+import { EmptyState } from './components'然后删除第 40-53 行的本地定义。
internal/repository/sqlite/route.go (1)
70-95: 建议检测 RowsAffected 以避免静默失败。
当前 Exec 可能在 id 不存在时返回 0 行更新但不报错;批量接口更容易被误判为成功。♻️ 建议改动(检测受影响行)
import ( "database/sql" + "fmt" "time" "github.com/awsl-project/maxx/internal/domain" ) @@ for _, update := range updates { - if _, err := stmt.Exec(update.Position, now, update.ID); err != nil { - return err - } + result, err := stmt.Exec(update.Position, now, update.ID) + if err != nil { + return err + } + rows, err := result.RowsAffected() + if err != nil { + return err + } + if rows == 0 { + return fmt.Errorf("route not found: %d", update.ID) + } }web/src/components/routes/ClientTypeRoutesContent.tsx (1)
170-210: 建议补齐乐观更新的快照回滚与 onSettled 刷新。
当前仅在失败时 invalidate,缺少快照回滚;并发请求或服务端规范化时可能导致 UI 短暂错位或残留旧序。♻️ 建议的回滚/刷新处理
- // 乐观更新:立即更新本地缓存 + // 乐观更新:立即更新本地缓存 + const previousRoutes = + queryClient.getQueryData<typeof allRoutes>(routeKeys.list()) + void queryClient.cancelQueries({ queryKey: routeKeys.list() }) queryClient.setQueryData(routeKeys.list(), (oldRoutes: typeof allRoutes) => { if (!oldRoutes) return oldRoutes return oldRoutes.map(route => { const newPosition = updates[route.id] if (newPosition !== undefined) { return { ...route, position: newPosition } } return route }) }) // 发送 API 请求 updatePositions.mutate(updates, { onError: () => { - // 失败时回滚:重新获取服务器数据 - queryClient.invalidateQueries({ queryKey: routeKeys.list() }) + // 失败时回滚:恢复快照 + if (previousRoutes) { + queryClient.setQueryData(routeKeys.list(), previousRoutes) + } }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey: routeKeys.list() }) + }, })
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (47)
internal/domain/model.gointernal/handler/admin.gointernal/repository/cached/route.gointernal/repository/interfaces.gointernal/repository/sqlite/route.gointernal/service/admin.goweb/src/App.tsxweb/src/components/cooldown-details-dialog.tsxweb/src/components/force-project-dialog.tsxweb/src/components/layout/header.tsxweb/src/components/layout/nav-proxy-status.tsxweb/src/components/provider-details-dialog.tsxweb/src/components/routes/ClientTypeRoutesContent.tsxweb/src/components/ui/model-input.tsxweb/src/hooks/queries/use-routes.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/index.tsweb/src/lib/transport/interface.tsweb/src/lib/transport/types.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/main.tsxweb/src/pages/api-tokens/index.tsxweb/src/pages/client-routes/components/provider-row.tsxweb/src/pages/projects/index.tsxweb/src/pages/projects/tabs/overview.tsxweb/src/pages/projects/tabs/routes.tsxweb/src/pages/projects/tabs/sessions.tsxweb/src/pages/providers/components/antigravity-provider-view.tsxweb/src/pages/providers/components/clients-config-section.tsxweb/src/pages/providers/components/kiro-provider-view.tsxweb/src/pages/providers/components/kiro-token-import.tsxweb/src/pages/providers/components/model-mapping-editor.tsxweb/src/pages/providers/components/provider-card.tsxweb/src/pages/providers/components/provider-create-flow.tsxweb/src/pages/providers/components/provider-edit-flow.tsxweb/src/pages/providers/components/provider-row.tsxweb/src/pages/providers/index.tsxweb/src/pages/requests/detail/RequestDetailPanel.tsxweb/src/pages/requests/detail/RequestDetailView.tsxweb/src/pages/requests/detail/RequestSidebar.tsxweb/src/pages/requests/detail/components/CopyButton.tsxweb/src/pages/requests/index.tsxweb/src/pages/retry-configs/index.tsxweb/src/pages/routes/form.tsxweb/src/pages/routing-strategies/index.tsxweb/src/pages/sessions.tsx
🧰 Additional context used
🧬 Code graph analysis (24)
web/src/lib/transport/types.ts (2)
internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/index.ts (1)
RoutePositionUpdate(19-19)
web/src/lib/transport/http-transport.ts (3)
internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/index.ts (1)
RoutePositionUpdate(19-19)web/src/lib/transport/types.ts (1)
RoutePositionUpdate(102-105)
internal/repository/cached/route.go (4)
internal/repository/interfaces.go (1)
RouteRepository(13-23)internal/repository/sqlite/route.go (1)
RouteRepository(10-12)internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/types.ts (1)
RoutePositionUpdate(102-105)
web/src/pages/providers/components/clients-config-section.tsx (4)
web/src/pages/providers/types.ts (1)
ClientConfig(137-142)internal/domain/model.go (1)
ClientType(6-6)web/src/lib/transport/types.ts (1)
ClientType(8-8)web/src/lib/theme.ts (1)
ClientType(25-25)
web/src/pages/requests/detail/RequestSidebar.tsx (2)
web/src/pages/requests/detail/components/EmptyState.tsx (1)
EmptyState(8-15)web/src/pages/requests/detail/components/index.ts (1)
EmptyState(5-5)
internal/service/admin.go (2)
internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/types.ts (1)
RoutePositionUpdate(102-105)
web/src/pages/providers/components/provider-create-flow.tsx (3)
web/src/components/ui/button.tsx (1)
Button(58-58)web/src/components/ui/index.ts (2)
Button(2-2)Input(30-30)web/src/components/ui/input.tsx (1)
Input(20-20)
web/src/pages/requests/detail/RequestDetailView.tsx (1)
web/src/pages/requests/detail/components/EmptyState.tsx (1)
EmptyState(8-15)
web/src/pages/requests/detail/RequestDetailPanel.tsx (2)
web/src/pages/requests/detail/components/CopyButton.tsx (1)
CopyButton(11-45)web/src/pages/requests/detail/components/EmptyState.tsx (1)
EmptyState(8-15)
web/src/lib/transport/interface.ts (2)
internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/types.ts (1)
RoutePositionUpdate(102-105)
web/src/components/layout/header.tsx (1)
web/src/components/theme-provider.tsx (1)
useTheme(73-80)
internal/repository/sqlite/route.go (2)
internal/repository/interfaces.go (1)
RouteRepository(13-23)internal/domain/model.go (1)
RoutePositionUpdate(156-159)
internal/repository/interfaces.go (3)
internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/index.ts (1)
RoutePositionUpdate(19-19)web/src/lib/transport/types.ts (1)
RoutePositionUpdate(102-105)
web/src/pages/providers/components/model-mapping-editor.tsx (1)
web/src/components/ui/model-input.tsx (1)
ModelInput(130-387)
web/src/pages/api-tokens/index.tsx (6)
web/src/components/ui/badge.tsx (1)
Badge(59-59)web/src/components/ui/index.ts (4)
Badge(27-27)Button(2-2)Card(6-6)Input(30-30)web/src/components/ui/button.tsx (1)
Button(58-58)web/src/lib/transport/http-transport.ts (1)
updateSetting(301-304)web/src/components/ui/card.tsx (1)
Card(96-96)web/src/components/ui/input.tsx (1)
Input(20-20)
web/src/pages/providers/components/provider-card.tsx (1)
web/src/components/icons/client-icons.tsx (1)
ClientIcon(65-100)
web/src/pages/projects/tabs/routes.tsx (1)
web/src/components/icons/client-icons.tsx (1)
getClientName(51-53)
web/src/pages/requests/detail/components/CopyButton.tsx (1)
web/src/pages/requests/detail/components/index.ts (1)
CopyButton(1-1)
internal/handler/admin.go (3)
internal/domain/model.go (1)
RoutePositionUpdate(156-159)web/src/lib/transport/index.ts (1)
RoutePositionUpdate(19-19)web/src/lib/transport/types.ts (1)
RoutePositionUpdate(102-105)
web/src/components/layout/nav-proxy-status.tsx (1)
web/src/components/layout/index.ts (1)
NavProxyStatus(7-7)
web/src/pages/sessions.tsx (3)
web/src/components/ui/index.ts (1)
TableHead(20-20)web/src/components/ui/table.tsx (1)
TableHead(95-95)web/src/lib/transport/http-transport.ts (1)
updateSessionProject(183-189)
web/src/pages/projects/tabs/sessions.tsx (3)
web/src/lib/transport/types.ts (1)
Project(60-67)web/src/pages/projects/tabs/index.ts (1)
SessionsTab(3-3)web/src/components/ui/index.ts (1)
TableHead(20-20)
web/src/components/routes/ClientTypeRoutesContent.tsx (2)
web/src/lib/query-client.ts (1)
queryClient(3-14)web/src/hooks/queries/use-routes.ts (1)
routeKeys(9-15)
web/src/components/ui/model-input.tsx (1)
web/src/components/ui/index.ts (1)
DialogTitle(45-45)
🪛 Biome (2.1.2)
web/src/locales/zh.json
[error] 257-258: The key routingStrategies was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
🪛 GitHub Actions: Lint
web/src/components/cooldown-details-dialog.tsx
[error] 21-21: ESLint: 'CooldownReason' is defined but never used. (no-unused-vars) @typescript-eslint/no-unused-vars
🪛 GitHub Check: lint
web/src/pages/client-routes/components/provider-row.tsx
[failure] 72-72:
't' is assigned a value but never used
🔇 Additional comments (82)
web/src/pages/projects/tabs/sessions.tsx (2)
5-5: LGTM!
useTranslationhook 的导入和使用方式正确。Also applies to: 12-12
29-31: LGTM!页面标题、描述和表头的国际化处理正确,翻译键命名规范清晰。
Also applies to: 40-43
web/src/pages/retry-configs/index.tsx (5)
104-106: 加载态文本样式更新无问题。仅是文案颜色 token 调整,符合主题迁移方向。
121-125: 标题与描述文字 token 调整 OK。保持层级与语义一致,样式更清晰。
179-183: 重试次数说明区域样式更新合理。文本主次层级清楚,无功能影响。
Also applies to: 196-196
205-209: 时间参数区的标签/说明文案样式一致性良好。统一为 text-text-* 体系,符合整体迁移。
Also applies to: 228-233, 252-256
276-282: 运行时展示区文案 token 更新 OK。颜色层级与强调信息更一致。
Also applies to: 286-287, 301-303, 309-311
web/src/pages/sessions.tsx (11)
53-57: 标题与副标题语义化文本色使用合理
与主题/ i18n 的文本层级一致,观感更统一。
74-84: 表头文本颜色统一为语义化 token
表头层级清晰且一致。
112-113: 未分配状态文本样式更清晰
text-text-muted + italic 的语义对齐很好。
213-216: 弹窗标题/副标题语义化样式 OK
与主页面风格一致。
233-237: Session ID 标题和值样式一致性提升
层级与可读性更好。
243-244: Created 标签语义化文本色一致
视觉层级更稳定。
253-255: 项目绑定标签样式统一
与其它 label 的语义化规则对齐。
264-266: 选中/未选中按钮主题色切换清晰
主色态与非选中态辨识度更高。
280-282: 项目按钮选中态样式一致且明确
主色方案与整体主题统一。
289-290: 提示文案的语义化弱化样式合适
辅助信息更柔和、不抢焦点。
299-299: i18n 调用格式更简洁
可读性提升,逻辑保持一致。web/src/pages/providers/components/provider-edit-flow.tsx (2)
3-3: LGTM!
useTranslation的引入和在ProviderEditFlow组件中的使用方式正确。Also applies to: 36-36
217-225: LGTM!保存按钮的三态文本(saving / saved / default)正确使用了 i18n 翻译函数。
web/src/pages/projects/tabs/overview.tsx (4)
8-8: LGTM!
useTranslation的导入和初始化正确,符合 react-i18next 的最佳实践。Also applies to: 15-15
59-84: LGTM!项目信息部分的国际化实现正确,翻译键命名遵循一致的命名空间模式 (
projects.*),CSS 类名更新与设计系统保持一致。
102-114: LGTM!保存按钮的国际化实现正确,按钮逻辑保持不变。
117-146: LGTM!代理配置部分的国际化实现正确,复制功能保持不变,CSS 类名与设计系统一致。
web/src/components/layout/header.tsx (2)
4-12: i18n 接入与样式调整整体 OK。
变更清晰、实现符合预期。
12-12: 翻译键app.title已在 web/src/locales/en.json 和 web/src/locales/zh.json 中定义,值为 "Maxx Next",无需修改。Likely an incorrect or invalid review comment.
web/src/components/ui/model-input.tsx (2)
3-3: 引入useTranslation没问题
新增的 i18n hook 导入符合预期。
292-292: i18n 文案替换一致且清晰
这些文本已统一走翻译键,符合整体国际化方向。Also applies to: 306-306, 354-371, 376-382
web/src/pages/routing-strategies/index.tsx (2)
24-28: useTranslation 引入 OK,但请确认 i18n 已在根部初始化。
如果未通过 I18nextProvider / initReactI18next 配置,t 会回退为 key 文本。请确认应用入口已完成初始化。
145-157: 国际化 keys 已在所有语言包中完整定义。已确认
common.cancel、common.saving、routes.update、routes.create这四个 key 均存在于英文和简体中文的语言包中,不存在缺失导致显示 key 的问题。web/src/pages/providers/components/antigravity-provider-view.tsx (3)
13-13: 新增 i18n 导入无问题。
若该页面可能被分包/懒加载,请确认该入口已完成 i18n 初始化覆盖。
127-127: 在容器组件内获取 t 的方式 OK。
当前用法清晰、易读。
360-369: 保存按钮状态文案已完成本地化。
状态切换逻辑清晰。web/src/pages/providers/components/provider-create-flow.tsx (1)
3-3: LGTM!国际化实现正确。
useTranslation钩子使用得当,所有 UI 字符串都已正确替换为翻译键。Also applies to: 25-25
internal/domain/model.go (1)
155-159: LGTM!
RoutePositionUpdate结构体定义清晰,JSON 标签正确,与前端类型定义一致。web/src/components/layout/nav-proxy-status.tsx (2)
11-14: 引入useTranslation的改动没问题。
55-59: 折叠态 Tooltip 文案已完成本地化。web/src/pages/providers/components/provider-row.tsx (2)
63-70: 重置时间的本地化处理清晰。
88-90: Kiro 重置天数的本地化逻辑 OK。web/src/pages/providers/index.tsx (3)
121-121: Header 描述文本改动无问题。
159-159: 加载态样式调整 OK。
222-224: 导入完成提示文本改动 OK。web/src/pages/providers/components/kiro-provider-view.tsx (3)
13-13: i18n Hook 集成到页面组件 OK。Also applies to: 135-135
36-39: 重置天数字符串本地化逻辑 OK。
362-369: 保存状态文案本地化处理 OK。web/src/App.tsx (1)
21-29: 加载态文案替换无问题。逻辑未变,文本已可本地化,OK。
web/src/pages/providers/components/model-mapping-editor.tsx (1)
21-75: 占位符已接入翻译,OK。修改仅限文案替换,不影响逻辑。
web/src/pages/providers/components/kiro-token-import.tsx (1)
29-56: 错误提示已本地化,逻辑保持不变。改动安全,OK。
web/src/components/provider-details-dialog.tsx (1)
2-2: i18n 文案替换与 locale 格式化处理良好整体替换一致,时间格式化也绑定了当前语言环境,符合预期。
Also applies to: 147-148, 177-184, 191-191, 218-218, 348-375, 388-388
web/src/pages/providers/components/provider-card.tsx (1)
27-29: Antigravity 相关文案 i18n 替换与样式微调 OK文本替换保持一致,非冷却状态背景由
bg-accent调整为bg-muted也更统一。Also applies to: 59-59, 111-118, 201-202
web/src/components/cooldown-details-dialog.tsx (1)
89-90: i18n 注入与时间格式化适配良好语言环境接入与关键文案替换整体一致,倒计时时间格式化也与当前语言对齐。
Also applies to: 121-128, 157-159, 264-265, 281-282, 286-286
web/src/lib/transport/types.ts (1)
102-105: 新增 RoutePositionUpdate 类型定义清晰结构简单明确,便于批量位置更新传输。
web/src/lib/transport/index.ts (1)
19-19: 导出 RoutePositionUpdate 没问题公共类型导出补齐,符合预期。
internal/service/admin.go (1)
206-208: 服务层委托实现清晰。
直接调用routeRepo.BatchUpdatePositions,与其他 Route API 的风格一致。internal/repository/cached/route.go (1)
76-82: 批量更新后刷新缓存的处理合理。
更新后调用Load()以保持缓存与数据库一致。web/src/hooks/queries/use-routes.ts (1)
97-102: 批量 payload 构造清楚且与新 API 对齐。
从Record转换为{ id, position }[]并调用批量接口,逻辑简洁。web/src/pages/routes/form.tsx (2)
2-2: 引入 useTranslation 并初始化 t 的做法合适。
请确认该页面加载了对应的 i18n 资源/命名空间,避免运行期缺失。Also applies to: 26-26
90-186: 请确认新增的翻译 key 在所有语言包中存在。
否则 UI 可能直接显示 key 文本而非期望文案。web/src/pages/projects/tabs/routes.tsx (3)
20-20: 引入 i18n hook 没问题。
useTranslation 的引入与本文件的文案替换一致。
45-66: 标题区文案已完成本地化替换。
t(...) 结合 count 的呈现清晰,语义也更直观。
81-86: 空状态文案本地化到位。
使用 client 占位符可读性好。internal/handler/admin.go (2)
51-55: 路由分发到 batch-positions 端点清晰。
路径分支逻辑易读且不影响现有 routes 处理。
325-344: 批量更新处理流程完整。
方法校验、解码、调用 service 与响应都覆盖到位。web/src/pages/requests/detail/RequestDetailView.tsx (5)
13-13: i18n hook 接入正确。
后续文案替换依赖该 hook 的使用方式一致。Also applies to: 46-46
70-93: 请求头与标签页文案已本地化。
对齐 requests.* 的键值使用规范。
120-123: Copy 按钮文案统一为通用翻译键。
便于后续复用与统一维护。Also applies to: 146-157
185-186: 空状态提示已使用翻译键。
两处 EmptyState 文案保持一致性很好。Also applies to: 282-283
217-221: 响应区 Copy 文案已本地化。
与请求区保持一致体验。Also applies to: 243-254
internal/repository/interfaces.go (1)
21-22: 新增批量更新接口已完整同步。已确认所有 RouteRepository 实现均已同步更新:
- SQLite 实现(internal/repository/sqlite/route.go:70-95):完整的事务处理逻辑
- Cached 实现(internal/repository/cached/route.go:76-82):正确委托并重加载缓存
接口定义与所有实现方法对齐完整,无遗漏。
web/src/pages/requests/detail/components/CopyButton.tsx (1)
4-12: 文案回退与复制状态提示清晰。
未传入 label 时自动回退到默认文案,行为一致。Also applies to: 35-40
web/src/pages/projects/index.tsx (1)
79-86: 表单标签层级调整 OK。web/src/pages/api-tokens/index.tsx (4)
180-247: 页面头部与鉴权状态文案替换后更一致。
255-374: 表格与空状态文案替换到位。
389-649: 创建/编辑/删除及新 Token 弹窗文案统一。
659-695: 项目选择弹窗文案替换 OK。web/src/pages/requests/index.tsx (3)
132-139: 空状态颜色调整无误。
220-237: 分页栏样式与文案调整清晰。
480-482: 客户端徽标颜色调整 OK。web/src/pages/requests/detail/RequestDetailPanel.tsx (2)
13-13: 空状态与尝试编号文案已统一。Also applies to: 72-99, 120-122
180-186: 对比按钮与请求/响应空状态文案替换一致。Also applies to: 230-272, 302-303, 363-364
web/src/components/routes/ClientTypeRoutesContent.tsx (2)
237-237: 把 items 显式映射为 id 列表是正确的(更符合 dnd-kit 预期)。
这能减少 DnD 内部比较的歧义,LGTM。
33-58: queryKey 一致性已验证,无需修改。
useRoutes()的 queryKey 为routeKeys.list(),其值为['routes', 'list'];所有变更操作(如useCreateRoute、useUpdateRoute、useDeleteRoute等)的 invalidation 使用routeKeys.lists(),同样返回['routes', 'list']。两者完全一致,setQueryData和invalidateQueries会正确更新缓存。
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| @@ -1,4 +1,5 @@ | |||
| import { useEffect, useState, useCallback } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "cooldown-details-dialog.tsx" -type fRepository: awsl-project/maxx
Length of output: 109
🏁 Script executed:
cat -n ./web/src/components/cooldown-details-dialog.tsxRepository: awsl-project/maxx
Length of output: 12924
🏁 Script executed:
# 查找是否还有其他地方导入 CooldownReason 但未使用
rg "CooldownReason" --type tsx --type ts -A 3 -B 1Repository: awsl-project/maxx
Length of output: 88
🏁 Script executed:
# 查找 CooldownReason 的使用情况
rg "CooldownReason" -A 3 -B 1Repository: awsl-project/maxx
Length of output: 11192
🏁 Script executed:
# 查看 i18next 的 TFunction 定义和用法
rg "TFunction|useTranslation" -A 5 web/src --type-add "tsx:*.tsx" | head -100Repository: awsl-project/maxx
Length of output: 4993
🏁 Script executed:
# 查看 provider-details-dialog.tsx 中 CooldownReason 的使用
cat -n web/src/components/provider-details-dialog.tsx | grep -A 20 -B 5 "CooldownReason"Repository: awsl-project/maxx
Length of output: 1003
🏁 Script executed:
# 查看 provider-details-dialog.tsx 中是否实际使用了 CooldownReason
rg "CooldownReason" web/src/components/provider-details-dialog.tsx -A 10 -B 3Repository: awsl-project/maxx
Length of output: 523
🏁 Script executed:
# 检查 i18next 的完整使用模式,查看其他地方如何处理默认值
rg "t\(" web/src/components -A 1 | grep -E "(defaultValue|,\s*['\"])" | head -20Repository: awsl-project/maxx
Length of output: 1566
🏁 Script executed:
# 查看 provider-details-dialog.tsx 中 getReasonInfo 的完整实现
cat -n web/src/components/provider-details-dialog.tsx | grep -A 50 "getReasonInfo"Repository: awsl-project/maxx
Length of output: 4180
🏁 Script executed:
# 验证 i18next 的 TFunction 类型和正确用法
cd web && npm list react-i18next i18next 2>/dev/null | head -10Repository: awsl-project/maxx
Length of output: 106
🏁 Script executed:
# 查看 web 的 package.json 中的依赖
cat web/package.json | grep -A 20 '"dependencies"'Repository: awsl-project/maxx
Length of output: 711
🏁 Script executed:
# 检查 cooldown-details-dialog.tsx 中 CooldownReason 是否被使用(除了导入)
grep -n "CooldownReason" web/src/components/cooldown-details-dialog.tsxRepository: awsl-project/maxx
Length of output: 133
🏁 Script executed:
# 验证 i18next 文档中 TFunction 的正确用法和 defaultValue 参数
python3 << 'EOF'
# i18next 的 t 函数支持的参数形式:
# t(key) - 返回翻译
# t(key, defaultValue) - 如果没有翻译,返回 defaultValue
# t(key, { defaultValue: '...' }) - 同上,但用对象形式
# 两种方式都支持,但第二种方式需要使用对象
# 根据 i18next 的文档,当传入第二个参数时:
# - 如果是字符串,则被视为 defaultValue
# - 如果是对象,则是选项对象,可以包含 defaultValue
# 因此,以下两种调用方式都有效:
# t('key', 'defaultValue')
# t('key', { defaultValue: 'defaultValue' })
print("i18next TFunction 支持两种默认值语法:")
print("1. t('key', 'defaultValue') - 简洁形式")
print("2. t('key', { defaultValue: 'defaultValue' }) - 对象形式")
print("\n实际上,第一种形式已经被广泛使用,效果相同。")
print("但使用对象形式时,类型定义需要是 TFunction 而不是 (key: string) => string")
EOFRepository: awsl-project/maxx
Length of output: 147
🏁 Script executed:
# 确认 TypeScript 类型检查会对这个问题报错
# 查看是否有 tsconfig 或其他 TS 配置
find web -name "tsconfig.json" -o -name "vitest.config.ts" -o -name "vite.config.ts" | head -5Repository: awsl-project/maxx
Length of output: 97
删除未使用的 CooldownReason 导入并修正 getReasonInfo 的 t 参数类型
此文件存在两个问题:
- 第 21 行导入的
CooldownReason类型未被使用,导致 ESLint 报错。 getReasonInfo的t参数定义为单参函数(key: string) => string,但实际调用时传入了默认值文案作为第二参数,这会导致 TypeScript 类型检查失败。
建议改为 TFunction 类型并使用 defaultValue 对象形式。
建议修改
-import type { Cooldown, CooldownReason } from '@/lib/transport/types'
+import type { TFunction } from 'i18next'
+import type { Cooldown } from '@/lib/transport/types'
-const getReasonInfo = (t: (key: string) => string) => ({
+const getReasonInfo = (t: TFunction) => ({
server_error: {
label: t('provider.reasons.serverError'),
- description: t('provider.reasons.serverErrorDesc', '上游服务器返回 5xx 错误,系统自动进入冷却保护'),
+ description: t('provider.reasons.serverErrorDesc', { defaultValue: '上游服务器返回 5xx 错误,系统自动进入冷却保护' }),
icon: Server,
color: 'text-red-400',
bgColor: 'bg-red-400/10 border-red-400/20',
},
network_error: {
label: t('provider.reasons.networkError'),
- description: t('provider.reasons.networkErrorDesc', '无法连接到上游服务器,可能是网络故障或服务器宕机'),
+ description: t('provider.reasons.networkErrorDesc', { defaultValue: '无法连接到上游服务器,可能是网络故障或服务器宕机' }),
icon: Wifi,
color: 'text-amber-400',
bgColor: 'bg-amber-400/10 border-amber-400/20',
},
quota_exhausted: {
label: t('provider.reasons.quotaExhausted'),
- description: t('provider.reasons.quotaExhaustedDesc', 'API 配额已用完,等待配额重置'),
+ description: t('provider.reasons.quotaExhaustedDesc', { defaultValue: 'API 配额已用完,等待配额重置' }),
icon: AlertCircle,
color: 'text-red-400',
bgColor: 'bg-red-400/10 border-red-400/20',
},
rate_limit_exceeded: {
label: t('provider.reasons.rateLimitExceeded'),
- description: t('provider.reasons.rateLimitExceededDesc', '请求速率超过限制,触发了速率保护'),
+ description: t('provider.reasons.rateLimitExceededDesc', { defaultValue: '请求速率超过限制,触发了速率保护' }),
icon: Zap,
color: 'text-yellow-400',
bgColor: 'bg-yellow-400/10 border-yellow-400/20',
},
concurrent_limit: {
label: t('provider.reasons.concurrentLimit'),
- description: t('provider.reasons.concurrentLimitDesc', '并发请求数超过限制'),
+ description: t('provider.reasons.concurrentLimitDesc', { defaultValue: '并发请求数超过限制' }),
icon: Ban,
color: 'text-orange-400',
bgColor: 'bg-orange-400/10 border-orange-400/20',
},
unknown: {
label: t('provider.reasons.unknown'),
- description: t('provider.reasons.unknownDesc', '因未知原因进入冷却状态'),
+ description: t('provider.reasons.unknownDesc', { defaultValue: '因未知原因进入冷却状态' }),
icon: HelpCircle,
color: 'text-muted-foreground',
bgColor: 'bg-muted border-border',
},
})🤖 Prompt for AI Agents
In `@web/src/components/cooldown-details-dialog.tsx` at line 2, 删除未使用的类型导入
CooldownReason,并把 getReasonInfo 的 t 参数类型从 (key: string) => string 改为 i18next 的
TFunction(引入或使用 useTranslation 提供的 TFunction 类型),然后在 getReasonInfo 内使用 i18next 的
defaultValue 对象形式(即传入 t(key, { defaultValue: '...' }) 而非第二个 string 参数);确保相关导入
useTranslation/ TFunction 一并调整并移除多余的 CooldownReason 引入以消除 ESLint 错误。
| @@ -1,4 +1,5 @@ | |||
| import { useEffect, useState, useCallback } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
There was a problem hiding this comment.
修正 getReasonInfo 的 t 类型以支持默认文案参数
当前 getReasonInfo 将 t 限定为 (key: string) => string,但实际传入了第二参数,TS 会直接报 “Expected 1 arguments”。建议改用 TFunction 并通过 defaultValue 传默认文案。
🛠️ 建议修改
-import { useTranslation } from 'react-i18next'
+import { useTranslation } from 'react-i18next'
+import type { TFunction } from 'i18next'
-const getReasonInfo = (t: (key: string) => string) => ({
+const getReasonInfo = (t: TFunction) => ({
server_error: {
label: t('provider.reasons.serverError'),
- description: t('provider.reasons.serverErrorDesc', '上游服务器返回 5xx 错误,系统自动进入冷却保护'),
+ description: t('provider.reasons.serverErrorDesc', { defaultValue: '上游服务器返回 5xx 错误,系统自动进入冷却保护' }),
icon: Server,
color: 'text-rose-500 dark:text-rose-400',
bgColor:
'bg-rose-500/10 dark:bg-rose-500/15 border-rose-500/30 dark:border-rose-500/25',
},
network_error: {
label: t('provider.reasons.networkError'),
- description: t('provider.reasons.networkErrorDesc', '无法连接到上游服务器,可能是网络故障或服务器宕机'),
+ description: t('provider.reasons.networkErrorDesc', { defaultValue: '无法连接到上游服务器,可能是网络故障或服务器宕机' }),
icon: Wifi,
color: 'text-amber-600 dark:text-amber-400',
bgColor:
'bg-amber-500/10 dark:bg-amber-500/15 border-amber-500/30 dark:border-amber-500/25',
},
quota_exhausted: {
label: t('provider.reasons.quotaExhausted'),
- description: t('provider.reasons.quotaExhaustedDesc', 'API 配额已用完,等待配额重置'),
+ description: t('provider.reasons.quotaExhaustedDesc', { defaultValue: 'API 配额已用完,等待配额重置' }),
icon: AlertCircle,
color: 'text-rose-500 dark:text-rose-400',
bgColor:
'bg-rose-500/10 dark:bg-rose-500/15 border-rose-500/30 dark:border-rose-500/25',
},
rate_limit_exceeded: {
label: t('provider.reasons.rateLimitExceeded'),
- description: t('provider.reasons.rateLimitExceededDesc', '请求速率超过限制,触发了速率保护'),
+ description: t('provider.reasons.rateLimitExceededDesc', { defaultValue: '请求速率超过限制,触发了速率保护' }),
icon: Zap,
color: 'text-yellow-600 dark:text-yellow-400',
bgColor:
'bg-yellow-500/10 dark:bg-yellow-500/15 border-yellow-500/30 dark:border-yellow-500/25',
},
concurrent_limit: {
label: t('provider.reasons.concurrentLimit'),
- description: t('provider.reasons.concurrentLimitDesc', '并发请求数超过限制'),
+ description: t('provider.reasons.concurrentLimitDesc', { defaultValue: '并发请求数超过限制' }),
icon: Ban,
color: 'text-orange-600 dark:text-orange-400',
bgColor:
'bg-orange-500/10 dark:bg-orange-500/15 border-orange-500/30 dark:border-orange-500/25',
},
unknown: {
label: t('provider.reasons.unknown'),
- description: t('provider.reasons.unknownDesc', '因未知原因进入冷却状态'),
+ description: t('provider.reasons.unknownDesc', { defaultValue: '因未知原因进入冷却状态' }),
icon: HelpCircle,
color: 'text-muted-foreground',
bgColor: 'bg-muted/50 border-border',
},
})Also applies to: 51-100
🤖 Prompt for AI Agents
In `@web/src/components/provider-details-dialog.tsx` at line 2, getReasonInfo
currently types its t parameter as (key: string) => string which disallows
passing the second options argument; change the type to TFunction from
react-i18next (import it alongside useTranslation) and update calls inside
getReasonInfo to pass the defaultValue via the second argument (e.g. t('key', {
defaultValue: '...' })) so TypeScript accepts the two-argument form and default
copy is provided.
| @@ -1,4 +1,5 @@ | |||
| import { useState } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
There was a problem hiding this comment.
项目回退名称仍是英文硬编码。
既然已统一文案来源,建议把 Project # 也改为翻译 key,并补充 locale。
建议修复(翻译回退文案)
- return project?.name || `Project #${projectId}`
+ return project?.name || t('apiTokens.projectFallback', { id: projectId })Also applies to: 50-50, 164-168
🤖 Prompt for AI Agents
In `@web/src/pages/api-tokens/index.tsx` at line 2, Replace hardcoded English
"Project #" strings in web/src/pages/api-tokens/index.tsx (occurrences around
lines ~2, ~50, and ~164-168) with a translation key via useTranslation (e.g.,
t('project.label') or similar) and update the locale JSONs to include that key
and localized values; ensure you import/use useTranslation in the component
where "Project #" appears and update any JSX or helper functions that build
those labels to call t(...) instead of the literal string so translations will
be used consistently.
- Remove unused CooldownReason import from cooldown-details-dialog.tsx - Remove unused CooldownReason import from provider-details-dialog.tsx - Remove unused t and useTranslation from provider-row.tsx - Remove unused ArrowRight import from projects/index.tsx Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary by CodeRabbit
发布说明
新功能
优化改进
✏️ Tip: You can customize this high-level summary in your review settings.