feat(routes): 在路由页展示生效策略并支持行内编辑权重#605
Conversation
…tes pages The routes pages (global and per-project, both backed by ClientTypeRoutesContent) never showed which routing strategy was actually in effect, and route weight was hardcoded to 1 with no way to view or edit it from the UI — so weighted_random was effectively unusable for web-only users. - Add a banner above the routes list showing the effective strategy for the scope, resolved in the same order as the backend (project-specific → global → priority default), with an "inherited from Global" / "default" hint and a shortcut to the Routing Strategies page. - When the effective strategy is weighted_random, render an inline, editable weight input on each route row (commit on blur/Enter, clamps to >=1, no-op when unchanged, Esc to cancel). Reuses the existing updateRoute mutation. - Thread showWeight through the memoized row components and keep their equality checks in sync. - Add en/zh i18n keys. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ 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). (3)
📝 WalkthroughWalkthrough在路由列表顶部显示生效路由策略横幅(按项目/全局优先解析),在 weighted_random 策略下为 provider 行启用权重内联编辑,并对 provider 行 UI 与中英文文案做相应调整。 Changes路由策略与权重控制
Sequence DiagramsequenceDiagram
participant ClientTypeRoutesContent
participant useRoutingStrategies
participant RoutingStrategyBanner
participant ProviderRowContent
participant RouteWeightControl
ClientTypeRoutesContent->>useRoutingStrategies: 请求策略集合
useRoutingStrategies-->>ClientTypeRoutesContent: 返回策略列表
ClientTypeRoutesContent->>ClientTypeRoutesContent: 解析生效策略并计算 isWeighted
ClientTypeRoutesContent->>RoutingStrategyBanner: 传递策略信息并渲染横幅
ClientTypeRoutesContent->>ProviderRowContent: 传递 showWeight = isWeighted
ProviderRowContent->>RouteWeightControl: 条件渲染权重编辑器
RouteWeightControl->>updateRoute: 提交权重 (onBlur/Enter)
预估审查工作量🎯 3 (Moderate) | ⏱️ ~25 分钟 可能相关的 PR
建议审查人
兔兔之诗
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 (1)
web/src/locales/zh.json (1)
629-637: 💤 Low value可考虑统一中文标点符号为全角格式。
所有翻译内容准确清晰,仅有一处可选的样式改进:
Line 637 的 tooltip 中使用了半角括号
(加权随机策略),建议改为全角括号(加权随机策略)以符合中文排版习惯。不过本文件中已存在半角/全角混用的情况(如 Line 248-249 用全角),因此这只是可选的样式优化建议。♻️ 可选的标点优化
- "weightTooltip": "权重越大被选中的概率越高(加权随机策略)。" + "weightTooltip": "权重越大被选中的概率越高(加权随机策略)。"🤖 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/src/locales/zh.json` around lines 629 - 637, Update the "weightTooltip" translation value to use fullwidth Chinese parentheses: replace the halfwidth "(加权随机策略)" with fullwidth "(加权随机策略)" in the JSON entry for the "weightTooltip" key so the tooltip follows Chinese punctuation conventions; ensure the string remains valid JSON and only that punctuation is changed.
🤖 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/src/locales/zh.json`:
- Around line 629-637: Update the "weightTooltip" translation value to use
fullwidth Chinese parentheses: replace the halfwidth "(加权随机策略)" with fullwidth
"(加权随机策略)" in the JSON entry for the "weightTooltip" key so the tooltip follows
Chinese punctuation conventions; ensure the string remains valid JSON and only
that punctuation is changed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1bc9b64e-a072-43e2-8e2e-87d36644b7ab
📒 Files selected for processing (4)
web/src/components/routes/ClientTypeRoutesContent.tsxweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/client-routes/components/provider-row.tsx
📜 Review details
⏰ 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). (2)
- GitHub Check: e2e
- GitHub Check: playwright
🔇 Additional comments (13)
web/src/locales/en.json (1)
630-638: LGTM!web/src/components/routes/ClientTypeRoutesContent.tsx (4)
8-9: LGTM!Also applies to: 36-36, 43-43, 49-50
108-156: 策略横幅组件实现良好。
RoutingStrategyBanner组件清晰地展示了有效的路由策略,包括策略类型、继承/默认状态以及策略说明。Link 到/routing-strategies为用户提供了便捷的配置入口。结构合理,国际化文案正确集成,UI 层次清晰。
197-212: 策略解析逻辑正确镜像后端优先级。解析顺序(项目专属 → 全局 → 默认优先级)与 PR 目标中描述的后端
router.getRoutingStrategy一致:
own: 当前项目的策略global: projectID 为 0 的全局策略resolved: 优先使用项目策略,否则回退到全局inherited和isDefault的判断逻辑准确useMemo 依赖项正确,避免不必要的重新计算。
445-450: 策略驱动的权重显示集成正确。横幅渲染和
showWeight={isWeighted}的传递逻辑清晰:
- 横幅始终显示当前生效策略
- 仅当策略为
weighted_random时启用权重编辑器- 正确透传到每个路由行组件
功能按设计实现。
Also applies to: 473-473
web/src/pages/client-routes/components/provider-row.tsx (8)
9-15: LGTM!Also applies to: 20-20, 22-22
25-83: 权重编辑器实现完善,交互逻辑清晰。
RouteWeightControlBase组件的实现要点:
- 使用
editing状态标记,配合 useEffect 同步服务端值,避免在用户输入时覆盖本地编辑- 失焦/回车提交,Escape 取消并恢复原值
- 验证逻辑将
< 1或非法值归一到 1,与后端 Route 契约一致- 仅在值实际变化时才调用
updateRoute.mutate,避免无效请求stopPropagation阻止事件冒泡,防止触发拖拽或行点击事件处理和状态管理均符合 React 最佳实践。
117-117: showWeight 属性正确集成到组件接口与 memo 优化。新增的
showWeight?: boolean属性:
- 已添加到
SortableProviderRowProps和ProviderRowContentProps- 已纳入两个 memo 相等性比较函数(
areSortableProviderRowEqual和areProviderRowContentEqual)- 正确透传到子组件
确保策略切换时权重编辑器的显示/隐藏能触发必要的重新渲染。
Also applies to: 133-133, 144-144, 187-187, 230-230, 315-315, 329-329
638-638: 条件渲染逻辑正确。
{showWeight && item.route && <RouteWeightControl route={item.route} />}仅在策略为 weighted_random 且路由对象存在时渲染权重编辑器,逻辑严谨。
352-359: 健康级别计算重构提升可读性。将冷却状态的多级判断从内联表达式拆分为更清晰的多行条件结构:
- 无冷却 →
healthy- 存在全局冷却(无 clientType & model)→
frozen- 存在客户端级冷却(有 clientType,无 model)→
limited- 否则 →
degraded(模型级冷却)逻辑保持不变,可读性显著提升。
586-629: 统计网格结构简化,保持功能一致。将 SR/TKN/Cost 三个指标的 JSX 结构改为更紧凑的 span 布局,并优化类名分支。逻辑未变,代码更简洁。
665-691: 冷却区 UI 结构优化,样式表达更清晰。雪花图标、标签、倒计时与"清除冷却"按钮的 JSX 结构和类名被重新组织,提升了代码可维护性和一致性。
695-698: onClearCooldown 调用方式改为对象 API,提升可维护性。从位置参数
onClearCooldown?.(cd.clientType || undefined, cd.model || undefined)改为对象参数:onClearCooldown?.({ clientType: cd.clientType || undefined, model: cd.model || undefined, })与类型签名
(options?: { clientType?: string; model?: string }) => void匹配,代码意图更明确。
When the effective strategy is weighted_random, the banner now shows whether session affinity is on, plus its scope (token/conversation) and TTL — so the routes' weights are read in context. Affinity is intentionally not shown under priority (it's a no-op there per router.go). Adds en/zh copy.
|
Review note from checking the inline weight editor behavior: The new Current flow in } else if (e.key === 'Escape') {
setEditing(false);
setValue(String(route.weight ?? 1));
(e.target as HTMLInputElement).blur();
}
Suggested fix: add an explicit cancel guard/ref for the next blur, or split |
Esc reset setValue() then called blur(), but onBlur=commit() runs synchronously and reads the pre-reset value from its closure, so a changed weight was still committed instead of cancelled. Guard commit with a cancelRef set by Esc. Also switch zh weightTooltip parens to fullwidth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Good catch — confirmed and fixed in 857c2bb. You're right: Rather than thread the reset through async state, I added a const cancelRef = useRef(false);
const commit = () => {
setEditing(false);
if (cancelRef.current) {
cancelRef.current = false;
setValue(String(route.weight ?? 1));
return;
}
// ...normalize + mutate only when changed
};
// Escape:
cancelRef.current = true;
(e.target as HTMLInputElement).blur();Also applied the fullwidth-parens nitpick on |
awsl233777
left a comment
There was a problem hiding this comment.
Approved after re-checking the current head. Checks are green, CodeRabbit is successful, and the Esc-cancel issue raised in review was fixed in 857c2bb with a cancelRef guard so blur no longer commits cancelled edits.
背景
routes 页面(全局页和 project 页,二者共用
ClientTypeRoutesContent)一直存在两个缺口:priority还是weighted_random,策略配置和路由管理两个页面割裂。weight被硬编码为 1,列表里既不显示也无法修改,排序只能拖拽改 position。结果:即使把某 project 切到weighted_random,纯前端用户也看不到它生效、更调不了权重(只能靠 CLIroute set-weight或 API)。改动
router.getRoutingStrategy一致(project 专属 → 全局 → priority 默认),并标注「继承自全局」/「默认」,附带跳转到「路由策略」页的快捷入口。weighted_random时,每条路由行显示一个可编辑的权重输入框。失焦 / 回车提交,<1归一到 1,值未变不发请求,Esc 取消;pointer 事件做了stopPropagation,不会误触发拖拽或详情弹窗。复用已有的updateRoutemutation(后端早已支持 weight 字段)。weighted_random下横幅额外显示 session 亲和是否开启及其 scope(token/conversation)和 TTL。亲和需要在策略 config 里单独开启(只切weighted_random不会自动生效 —— 见router.go的三段式 gating),过去 routes 页完全看不到它,导致"权重明明配了却看不出被亲和黏住"。现在一眼可见;priority 下不显示(那里亲和是 no-op)。projectID区分作用域)。showWeight透传到 memo 化的行组件,并同步更新其 equality 比较函数,保持原有重渲染优化。改动文件
web/src/components/routes/ClientTypeRoutesContent.tsx—— 策略解析 + 横幅 + 传showWeightweb/src/pages/client-routes/components/provider-row.tsx——RouteWeightControl行内权重编辑 + prop 透传web/src/locales/{en,zh}.json—— 文案验证
tsc类型检查通过eslint干净prettier通过(pre-commit lint-staged 已跑)vite build生产构建成功截图
priority(默认) —— 横幅显示Priority (by position)+(default),提示拖拽排序,不显示权重:weighted_random—— 横幅切到Weighted Random,每行多出可编辑的权重输入框(5 / 3 / 2 / 1):weighted_random+ 会话亲和开启 —— 横幅多出一枚 📌Affinity on · by conversation · 30m徽章,直接暴露 sticky 的开关状态、scope 和 TTL:🤖 Generated with Claude Code
Summary by CodeRabbit
新功能
文档/本地化