Skip to content

Feat/provider: add provider create and edit router & adjust some styles#122

Merged
Bowl42 merged 8 commits intoawsl-project:mainfrom
whhjdi:feat/provider
Jan 18, 2026
Merged

Feat/provider: add provider create and edit router & adjust some styles#122
Bowl42 merged 8 commits intoawsl-project:mainfrom
whhjdi:feat/provider

Conversation

@whhjdi
Copy link
Contributor

@whhjdi whhjdi commented Jan 18, 2026

Summary by CodeRabbit

版本更新说明

  • 新功能

    • 路由列表支持拖放排序(可按需重新排列)
    • 边栏新增流媒体指示与动画化导航项
  • 用户界面改进

    • 优化整体布局与间距,改进内容容器溢出行为
    • 调整认证/令牌界面配色与卡片样式
    • 优化代理地址复制交互与状态显示
    • 精简分页与按钮样式以改善可用性
  • 样式优化

    • 调整标签页间距及全局基线样式规则

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

…cross multiple components

- Updated import statements to use consistent single quotes.
- Reformatted code for better readability, including consistent spacing and line breaks.
- Enhanced the structure of function parameters for clarity.
- Improved the handling of conditional rendering and state management in provider components.
- Cleaned up comments and ensured they are relevant and concise.
@coderabbitai
Copy link

coderabbitai bot commented Jan 18, 2026

📝 Walkthrough

Walkthrough

在侧边栏引入新的可复用导航项组件 AnimatedNavItem,将多处导航项替换为该组件;为路由列表添加拖拽排序(DndContext + SortableContext + DragOverlay);并对多处布局与样式(app-layout、按钮、标签页、代理状态、provider 卡片等)进行样式和微结构调整,另有若干格式化更改。

Changes

Cohort / File(s) 变更摘要
布局与根样式
web/src/components/layout/app-layout.tsx, web/src/index.css
主容器/根元素和交互元素添加/调整 className(如 h-svh, min-h-0, overflow-hidden);移除全局边框色,加入按钮指针样式。
侧边栏与导航项
web/src/components/layout/app-sidebar/animated-nav-item.tsx, web/src/components/layout/app-sidebar/client-routes-items.tsx, web/src/components/layout/app-sidebar/requests-nav-item.tsx, web/src/components/layout/app-sidebar/index.tsx, web/src/components/layout/index.ts
新增 AnimatedNavItem,将若干 Sidebar 项重构为使用该组件;移除 SidebarNav 导出别名;在 Sidebar 上添加 border-border 类;导航项现在支持流播徽章、跑马灯背景和基于路径的 isActive 回调。
路由列表(拖拽)
web/src/components/routes/ClientTypeRoutesContent.tsx
引入 DndContextSortableContextDragOverlay,实现可排序的路由列表并用 activeId 跟踪拖拽项(重大行为改动)。
代理/状态与交互控件
web/src/components/layout/nav-proxy-status.tsx, web/src/components/ui/button.tsx
将外层 Button 替换为普通容器并在内部使用原生 button 处理复制交互;移除 button 基类的 shadow-xs
表单 / 提供商页面样式与行为
web/src/pages/providers/components/antigravity-token-import.tsx, web/src/pages/providers/components/kiro-provider-view.tsx, web/src/pages/providers/components/provider-edit-flow.tsx, web/src/pages/providers/components/provider-row.tsx, web/src/pages/providers/components/antigravity-provider-view.tsx, web/src/pages/providers/components/custom-config-step.tsx
认证模式卡片样式与布局调整;KiroProvider 添加配额获取及错误/更新时间显示;provider-edit-flow 增强模型映射字段与重置逻辑;若干格式化与小的 JSX 重构。
请求与统计页面
web/src/pages/requests/index.tsx, web/src/pages/stats/index.tsx
请求页主容器与表格容器的溢出与高度类调整;分页栏高度改为内边距;统计页若干卡片/图表布局与 props 微调(展示层)。
UI 小部件与布局细节
web/src/components/ui/tabs.tsx, web/src/components/ui/model-input.tsx
Tabs 根容器添加 gap-2,移除 TabsContentmin-h-0;模型输入常量仅做格式化调整。
类型、上下文与 Hooks(格式化)
web/src/lib/transport/types.ts, web/src/contexts/antigravity-quotas-context.tsx, web/src/hooks/queries/use-aggregated-stats.ts, web/src/hooks/queries/use-usage-stats.ts
导入、注释与参数列表格式化调整,无语义或签名改动(少数加入逗号或换行)。
小型格式化/表现调整
web/src/pages/client-routes/components/provider-row.tsx, web/src/pages/model-mappings/index.tsx, web/src/pages/providers/index.tsx
拖拽把手事件位置调整、文本换行/格式化与若干一行→多行的代码风格更改;行为不变。

Sequence Diagram(s)

sequenceDiagram
    participant User as 用户
    participant UI as 浏览器 UI
    participant Dnd as DndContext
    participant Sort as SortableContext
    participant Row as ProviderRow
    participant Overlay as DragOverlay

    User->>UI: 按下并开始拖拽某项
    UI->>Dnd: 通知开始拖拽(activeId)
    Dnd->>Sort: 标记活跃项,提供排序策略
    Sort->>Row: 渲染可拖拽行(包含 drag handle)
    Dnd->>Overlay: 显示拖动预览(ProviderRow 内容)
    User->>UI: 在目标位置释放鼠标
    UI->>Dnd: 触发 drop/重排 事件
    Dnd->>Sort: 更新项顺序并触发重渲染
    Sort->>Row: 重新排列列表
    Dnd->>Overlay: 隐藏预览
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 分钟

Possibly related PRs

Suggested reviewers

  • awsl233777

诗句

🐰 我在草丛中跳跃,代码轻轻唱,
新的导航闪亮,拖拽舞翩跹。
样式调整细腻,预览随手拿,
兔耳一竖笑,合并就要来!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.03% 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标题准确总结了主要改动:添加提供商创建和编辑路由功能,以及进行样式调整。标题与大量文件更改相关联,包括layout组件、provider编辑流程和多个UI样式改进。

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

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
web/src/pages/client-routes/components/provider-row.tsx (1)

273-278: Grip 容器简化后与新的拖拽模式一致。

由于拖拽监听器已移至父级 Button,这里的 grip 图标现在仅作为视觉提示。建议考虑移除 hover:bg-accent 效果,因为它暗示该区域有独立交互,但实际上整行都是可拖拽区域。

可选:移除 hover 效果以避免误导
-        <div className="p-1 rounded-md hover:bg-accent transition-colors">
+        <div className="p-1 rounded-md transition-colors">
📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fa36f8 and c6de6d8.

📒 Files selected for processing (1)
  • web/src/pages/client-routes/components/provider-row.tsx
🔇 Additional comments (3)
web/src/pages/client-routes/components/provider-row.tsx (3)

238-252: 拖拽交互区域扩大至整行,可能存在 UX 冲突。

dragHandleListeners 从 grip 图标移至整个 Button 组件,并添加 cursor-grab 样式,意味着用户可以从行的任意位置开始拖拽。但该 Button 同时绑定了 onClick={handleContentClick} 用于打开详情弹窗。

虽然 dnd-kit 通常能区分点击和拖拽(无位移的点击不会触发拖拽),但以下方面值得确认:

  1. 视觉误导:GripVertical 图标暗示"仅此处可拖拽",但实际上整行都可拖拽
  2. 移动端体验:触摸设备上用户滑动浏览时可能意外触发拖拽

如果这是预期行为,建议在 grip 图标区域添加 tooltip 说明整行可拖拽;如果希望仅 grip 区域可拖拽,应将 dragHandleListeners 移回 grip 容器。


240-245: 样式调整 LGTM。

cooldown 状态的冰冻视觉效果(teal 色系配合 shadow)和普通状态的样式简化看起来合理,视觉层次分明。


354-356: Claude 标签格式化调整 LGTM。

简化后的标签结构更清晰,样式保持一致。

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


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: 2

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/layout/nav-proxy-status.tsx (1)

61-88: 图标按钮缺少可访问性标签
该按钮只有图标,屏幕阅读器难以理解用途;title 不一定被读取。建议补充 aria-label(可结合 copied 状态)。

♿️ 建议补充无障碍标签
       <button
         type="button"
         onClick={handleCopy}
         className="shrink-0 text-muted-foreground relative w-4 h-4 cursor-pointer hover:text-foreground transition-colors"
         title={`Click to copy: ${fullUrl}`}
+        aria-label={copied ? t('proxy.copied') : t('proxy.clickToCopy')}
       >
web/src/components/routes/ClientTypeRoutesContent.tsx (1)

183-224: 搜索过滤下拖拽会写入错误排序
items 已被 searchQuery 过滤,但拖拽时仍用过滤后的顺序计算 position 并写回,隐藏项保留旧位置,可能产生重复/错乱排序。建议在过滤时禁用拖拽,或基于未过滤列表计算并写回完整顺序。

🧭 示例:过滤时阻止位置写回(避免错乱)
+  const isFiltering = !!searchQuery.trim();
+
   const handleDragEnd = (event: DragEndEvent) => {
+    if (isFiltering) {
+      setActiveId(null);
+      return;
+    }
     const { active, over } = event;
     setActiveId(null);

Also applies to: 243-290

🤖 Fix all issues with AI agents
In `@web/src/index.css`:
- Around line 290-297: Update the sizing rules for html, body, and `#root` to
avoid clipping and improve compatibility: replace height: 100svh with
min-height: 100svh on these selectors (or at least on `#root`) so content can
grow, and add a fallback for older browsers by keeping/adding a vh-based
fallback before the svh declaration (or use an `@supports` check for svh). Ensure
the change targets the existing selectors (html, body, `#root`) and that the
fallback order places the broader-supported value first followed by the svh
value so browsers that don't support svh will use the fallback.

In `@web/src/pages/providers/components/kiro-provider-view.tsx`:
- Line 1: 在 kiro-provider-view.tsx 中防止旧的异步配额响应覆盖新数据:为 fetchQuota/refresh
逻辑引入一个请求序号或 AbortController(例如 currentRequestIdRef 或
abortControllerRef),在每次触发拉取(包括 useEffect 和点击 Refresh 的处理函数)先递增序号或创建并替换
AbortController,然后在响应到达时只在序号匹配或未被中止时调用 setQuota/setLoading
等状态更新;另外在组件卸载或新请求发起时取消先前请求以避免竞态(定位到触发拉取的 useEffect 和 refresh handler,如
fetchQuota/loadQuota/handleRefresh)。
🧹 Nitpick comments (1)
web/src/pages/providers/components/antigravity-token-import.tsx (1)

290-327: Token 模式按钮与 OAuth 按钮样式保持一致。

两个按钮的样式模式完全相同,这很好地保持了 UI 一致性。

考虑将重复的按钮样式逻辑提取为可复用组件或配置对象,以减少代码重复并便于后续维护。

♻️ 可选:提取模式选择按钮组件
// 可以考虑提取为独立组件
interface ModeButtonProps {
  mode: ImportMode;
  currentMode: ImportMode;
  onClick: () => void;
  icon: React.ReactNode;
  title: string;
  description: string;
}

function ModeButton({ mode, currentMode, onClick, icon, title, description }: ModeButtonProps) {
  const isActive = mode === currentMode;
  return (
    <button
      onClick={onClick}
      className={cn(
        'relative group p-4 rounded-xl border-2 transition-all duration-200 text-left',
        isActive
          ? 'border-primary bg-primary/10 shadow-md'
          : 'border-border hover:border-primary/30 bg-secondary/50 hover:bg-secondary',
      )}
    >
      {/* ... 共用布局逻辑 */}
    </button>
  );
}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e80a703 and 7fa36f8.

📒 Files selected for processing (27)
  • web/src/components/layout/app-layout.tsx
  • web/src/components/layout/app-sidebar/animated-nav-item.tsx
  • web/src/components/layout/app-sidebar/client-routes-items.tsx
  • web/src/components/layout/app-sidebar/index.tsx
  • web/src/components/layout/app-sidebar/requests-nav-item.tsx
  • web/src/components/layout/index.ts
  • web/src/components/layout/nav-proxy-status.tsx
  • web/src/components/routes/ClientTypeRoutesContent.tsx
  • web/src/components/ui/button.tsx
  • web/src/components/ui/model-input.tsx
  • web/src/components/ui/tabs.tsx
  • web/src/contexts/antigravity-quotas-context.tsx
  • web/src/hooks/queries/use-aggregated-stats.ts
  • web/src/hooks/queries/use-usage-stats.ts
  • web/src/index.css
  • web/src/lib/transport/types.ts
  • web/src/pages/client-routes/components/provider-row.tsx
  • web/src/pages/model-mappings/index.tsx
  • web/src/pages/providers/components/antigravity-provider-view.tsx
  • web/src/pages/providers/components/antigravity-token-import.tsx
  • web/src/pages/providers/components/custom-config-step.tsx
  • web/src/pages/providers/components/kiro-provider-view.tsx
  • web/src/pages/providers/components/provider-edit-flow.tsx
  • web/src/pages/providers/components/provider-row.tsx
  • web/src/pages/providers/index.tsx
  • web/src/pages/requests/index.tsx
  • web/src/pages/stats/index.tsx
🧰 Additional context used
🧬 Code graph analysis (15)
web/src/components/ui/tabs.tsx (1)
web/src/lib/utils.ts (1)
  • cn (8-10)
web/src/contexts/antigravity-quotas-context.tsx (2)
web/src/lib/transport/types.ts (1)
  • AntigravityQuotaData (338-343)
web/src/lib/transport/index.ts (1)
  • AntigravityQuotaData (46-46)
web/src/lib/transport/types.ts (3)
internal/domain/model.go (1)
  • ModelMappingScope (535-535)
web/src/lib/transport/index.ts (2)
  • StatsGranularity (68-68)
  • UsageStatsFilter (67-67)
internal/repository/interfaces.go (1)
  • UsageStatsFilter (141-151)
web/src/hooks/queries/use-usage-stats.ts (3)
web/src/lib/transport/types.ts (1)
  • UsageStatsFilter (562-572)
web/src/lib/transport/index.ts (1)
  • UsageStatsFilter (67-67)
internal/repository/interfaces.go (1)
  • UsageStatsFilter (141-151)
web/src/pages/providers/components/provider-edit-flow.tsx (6)
web/src/lib/transport/types.ts (1)
  • Provider (43-53)
internal/repository/sqlite/models.go (2)
  • Provider (115-122)
  • Provider (124-124)
web/src/lib/transport/index.ts (1)
  • Provider (9-9)
web/src/hooks/queries/use-settings.ts (4)
  • useModelMappings (55-60)
  • useCreateModelMapping (62-71)
  • useUpdateModelMapping (73-83)
  • useDeleteModelMapping (85-94)
web/src/components/ui/model-input.tsx (1)
  • ModelInput (177-427)
web/src/components/ui/button.tsx (1)
  • Button (58-58)
web/src/components/layout/app-sidebar/animated-nav-item.tsx (3)
web/src/components/ui/sidebar.tsx (3)
  • SidebarMenuItem (688-688)
  • SidebarMenuButton (687-687)
  • SidebarMenuBadge (686-686)
web/src/lib/utils.ts (1)
  • cn (8-10)
web/src/components/ui/streaming-badge.tsx (1)
  • StreamingBadge (27-81)
web/src/components/layout/app-sidebar/requests-nav-item.tsx (2)
web/src/hooks/use-streaming.ts (1)
  • useStreamingRequests (29-114)
web/src/components/layout/app-sidebar/animated-nav-item.tsx (1)
  • AnimatedNavItem (28-60)
web/src/components/routes/ClientTypeRoutesContent.tsx (3)
web/src/hooks/queries/use-providers.ts (1)
  • useProviderStats (78-86)
web/src/pages/client-routes/components/provider-row.tsx (1)
  • ProviderRowContent (180-496)
web/src/components/icons/client-icons.tsx (1)
  • getClientName (51-53)
web/src/components/layout/app-sidebar/client-routes-items.tsx (2)
web/src/components/icons/client-icons.tsx (2)
  • getClientName (51-53)
  • ClientIcon (65-100)
web/src/components/layout/app-sidebar/animated-nav-item.tsx (1)
  • AnimatedNavItem (28-60)
web/src/pages/providers/components/kiro-provider-view.tsx (3)
web/src/hooks/queries/index.ts (4)
  • useModelMappings (91-91)
  • useCreateModelMapping (92-92)
  • useUpdateModelMapping (93-93)
  • useDeleteModelMapping (94-94)
web/src/hooks/queries/use-settings.ts (4)
  • useModelMappings (55-60)
  • useCreateModelMapping (62-71)
  • useUpdateModelMapping (73-83)
  • useDeleteModelMapping (85-94)
web/src/lib/transport/types.ts (1)
  • KiroQuotaData (431-442)
web/src/pages/requests/index.tsx (2)
web/src/components/ui/button.tsx (1)
  • Button (58-58)
web/src/components/ui/index.ts (1)
  • Button (2-2)
web/src/components/layout/app-sidebar/index.tsx (1)
web/src/components/ui/sidebar.tsx (1)
  • Sidebar (674-674)
web/src/pages/providers/components/custom-config-step.tsx (1)
web/src/pages/providers/context/provider-form-context.tsx (1)
  • useProviderForm (95-101)
web/src/pages/providers/components/antigravity-provider-view.tsx (2)
web/src/hooks/queries/index.ts (4)
  • useModelMappings (91-91)
  • useCreateModelMapping (92-92)
  • useUpdateModelMapping (93-93)
  • useDeleteModelMapping (94-94)
web/src/hooks/queries/use-settings.ts (4)
  • useModelMappings (55-60)
  • useCreateModelMapping (62-71)
  • useUpdateModelMapping (73-83)
  • useDeleteModelMapping (85-94)
web/src/pages/providers/components/antigravity-token-import.tsx (1)
web/src/lib/utils.ts (1)
  • cn (8-10)
🔇 Additional comments (38)
web/src/components/ui/model-input.tsx (1)

71-75: 格式化调整合理,未改变行为。
仅为可读性改动,无需进一步修改。

web/src/hooks/queries/use-usage-stats.ts (1)

126-140: LGTM!

仅添加了尾随逗号,这是一个纯格式化更改,有助于未来添加新参数时保持更简洁的 diff。类型定义 Omit<UsageStatsFilter, 'granularity' | 'start' | 'end'> 正确地排除了由 preset 自动设置的字段。

web/src/pages/providers/components/antigravity-token-import.tsx (1)

251-288: OAuth 模式按钮样式更新看起来不错。

样式更改与新的 primary/secondary 调色板保持一致。size-10 工具类是 w-10 h-10 的有效简写形式,使代码更简洁。

web/src/pages/client-routes/components/provider-row.tsx (1)

356-358: 格式调整无功能影响,LGTM。
仅为排版换行/缩进调整,渲染与数据逻辑保持一致。

web/src/pages/model-mappings/index.tsx (1)

144-144: 语法格式统一,行为不变。
仅增加参数括号,可读性更好且不影响逻辑。

web/src/hooks/queries/use-aggregated-stats.ts (1)

8-13: 仅为类型导入排版优化,LGTM。
不影响运行时与类型语义。

web/src/components/ui/button.tsx (1)

6-7: 基础样式微调无逻辑影响。
移除阴影类仅影响视觉一致性,其他变体行为未变。

web/src/components/ui/tabs.tsx (2)

11-11: 间距调整为纯样式改动,LGTM。
仅提升容器内元素间距,不影响交互逻辑。


67-67: 内容区样式简化可行。
移除 min-h-0 属于布局策略调整,无功能风险。

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

384-395: 注释与排版对齐,类型结构不变。
接口字段未变更,仅格式化。


530-541: 注释/对齐调整,无语义变化。
字段与类型保持一致。


554-559: 格式化变更,LGTM。
统计字段语义不变。


564-565: 仅注释与排版调整。
过滤器字段定义未变。

Also applies to: 571-571

web/src/contexts/antigravity-quotas-context.tsx (1)

23-26: 格式化改进,LGTM!

参数解构和函数签名的多行格式化提升了代码可读性,逻辑保持不变。

Also applies to: 49-51

web/src/pages/providers/components/custom-config-step.tsx (2)

14-23: 格式化改进,LGTM!

useProviderForm 的解构赋值改为多行格式,提高了可读性。


191-195: 数组操作格式化,LGTM!

新增和删除 mapping 的数组操作逻辑保持不变,多行格式更清晰。

Also applies to: 243-246

web/src/index.css (1)

611-615: 按钮交互体验优化,LGTM!

button[role='button'] 元素全局添加 cursor: pointer 是一个良好的 UX 改进,确保所有可点击按钮都有一致的鼠标指针样式。

web/src/pages/providers/components/antigravity-provider-view.tsx (3)

1-32: 导入语句格式化,LGTM!

导入语句的格式调整保持了一致性,无功能变化。


131-162: Hook 调用和状态管理格式化,LGTM!

ProviderModelMappings 组件中的 hook 调用和状态管理代码格式化改进,逻辑保持不变。


199-212: onChange 回调格式化,LGTM!

onChange 处理器的参数加上括号 (pattern) =>(target) =>,符合一致的代码风格。

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

37-43: 过滤逻辑简化,LGTM!

将多行 return 语句压缩为单行布尔表达式,逻辑保持不变,代码更简洁。

web/src/pages/requests/index.tsx (2)

126-140: Flex 布局修复,LGTM!

添加 min-h-0 是修复 flex 容器中滚动行为的正确做法。在 flex 布局中,子元素默认不会收缩到内容尺寸以下,min-h-0 允许元素收缩并启用正确的 overflow-auto 滚动行为。


208-228: 分页栏样式简化,LGTM!

分页栏使用 py-2 替代固定高度更灵活,按钮样式简化后依赖 Button 组件的默认样式,保持一致性。

web/src/components/layout/app-sidebar/animated-nav-item.tsx (1)

1-59: 组件封装清晰,复用性好
Active 判定、跑马灯与 StreamingBadge 集中处理,便于在侧边栏保持一致。

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

59-61: 状态与搜索过滤逻辑清晰
activeId/providerStats 接入与过滤条件调整保持可读性。

Also applies to: 110-114, 137-139


292-365: “可用 Provider”卡片布局一致性不错
卡片化列表、禁用态与颜色处理清晰。

web/src/pages/providers/components/provider-edit-flow.tsx (2)

45-177: Model Mapping 创建/更新字段补全,流程完整
新增 providerType/priority/isEnabled 并重置输入,逻辑清楚。


181-267: 支持模型增删流程简洁
去重、清空输入与按钮禁用逻辑合理。

web/src/pages/providers/components/kiro-provider-view.tsx (1)

126-258: Model Mapping 区块实现清晰
与自定义 provider 的处理一致,状态与禁用逻辑明确。

web/src/pages/providers/components/provider-row.tsx (1)

188-192: 仅格式调整,渲染逻辑不变
该段改动不影响行为。

web/src/pages/stats/index.tsx (3)

144-148: 聚合函数参数与依赖同步到位。

新增 timeConfig 入参并同步到 useMemo 依赖,避免图表使用过期时间配置,处理得当。

Also applies to: 335-337


403-405: 图表与卡片样式调整整体一致。

右侧 Y 轴、Tooltip 金额格式、刷新按钮动画与 SummaryCard 副标题展示都比较一致,UI 表现更清晰。

Also applies to: 501-509, 523-549, 554-625, 687-689


355-380: totalDurationMs 在类型定义中是必需字段,不存在缺失风险。

根据类型定义 (web/src/lib/transport/types.ts:541),UsageStats.totalDurationMs 被定义为 totalDurationMs: number(必需,非可选),TypeScript 类型系统会强制确保该字段存在。现有的守卫条件 totals.totalDurationMs > 0 已足以防止计算中出现 NaN。无需添加额外的空值检查。

Likely an incorrect or invalid review comment.

web/src/components/layout/app-sidebar/index.tsx (1)

19-19: Sidebar 边框样式收敛得不错。

增加 className="border-border" 有助于统一边框色,逻辑未变,OK。

web/src/components/layout/app-sidebar/requests-nav-item.tsx (1)

15-23: 改用 AnimatedNavItem 后更统一。

isActive 处理了 /requests/*,并保留 streamingCount/tooltip,行为一致。

web/src/components/layout/index.ts (1)

2-2: 导出名变更已验证完成,全仓库无遗留引用。

全仓库搜索已确认:

  • ✅ 无任何 SidebarNav 的引用残留
  • AppSidebar 已在 app-layout.tsx 中正确导入并使用
  • ✅ 导出迁移完整且正确
web/src/components/layout/app-layout.tsx (1)

16-23: 此项目使用 Tailwind CSS v4,其中重要性修饰符的正确语法是后缀形式(h-svh!),而非前缀形式(!h-svh)。代码库中已广泛一致地使用后缀风格,包括 size-8!p-2!hover:bg-sidebar-accent/50! 等,h-svh!min-h-0! 的用法正确无误。

Likely an incorrect or invalid review comment.

web/src/components/layout/app-sidebar/client-routes-items.tsx (1)

22-30: 当前实现是正确的,不需要修改。

应用中并未定义 /routes/${clientType} 下的嵌套路由。路由配置仅包括两条路由:

  • /routes - 全局路由页面
  • /routes/:clientType - 特定客户端类型的路由页面

由于不存在 /routes/claude/detail 这样的子路由,精确匹配 pathname === /routes/${clientType}` 的实现是正确的。

Likely an incorrect or invalid review comment.

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

Comment on lines 290 to 297
html,
body {
body,
#root {
width: 100%;
height: 100%;
height: 100svh;
margin: 0;
padding: 0;
}
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

🧩 Analysis chain

🌐 Web query:

CSS 100svh browser support 2025 viewport height

💡 Result:

Short answer

  • 100svh is a CSS viewport unit equal to 100% of the "small viewport height" (viewport when browser UI like address/tool bars is expanded). Use it as height:100svh. [1][2]

Browser support (summary as of Jan 18, 2026)

  • Widely supported in modern desktop and mobile browsers (Safari, Firefox, Chromium-based browsers) but some older engines, in-app/embedded browsers, or very old browser versions may not support it or may require experimental flags. Check live support for specific targets. [1][2][3]

Caveats and recommendations

  • Use min-height:100svh rather than height:100svh for content that must not be clipped. [2]
  • Some in-app or embedded webviews (messenger apps, some third‑party iOS wrappers) may ignore svh — test those environments. [7]
  • Provide fallbacks (e.g., height:100vh before height:100svh) or use an @supports check; a community polyfill exists if you need broader compatibility. [4][2]

Useful refs

  • MDN (viewport-percentage units, svh/lvh/dvh). [1]
  • Article explaining svh/lvh/dvh and usage caveats. [2]
  • Browser support summary / compatibility table. [3]
  • Polyfill repo for large/small/dynamic viewport units. [4]

If you want, I can fetch the current live caniuse/support matrix for particular browser versions or produce a small cross‑browser CSS snippet with fallbacks and @supports.


考虑使用 min-height 替代 height,并添加兼容性回退

#root 添加到尺寸规则中并使用 100svh 是一个好的改进,能更好地处理移动端浏览器的动态 UI(如地址栏收缩)。但以下几点需要注意:

  1. height vs min-height:建议将 height: 100svh 改为 min-height: 100svh,避免内容被裁剪。
  2. 兼容性回退100svh 在某些旧版浏览器和内嵌网页浏览器中支持不完整。建议添加回退方案:
    height: 100vh;
    height: 100svh;
    或使用 @supports 检查。
  3. 内嵌浏览器测试:某些应用内嵌网页(如 Messenger、某些 iOS 包装器)可能不支持 svh,建议在这些环境中测试。
🤖 Prompt for AI Agents
In `@web/src/index.css` around lines 290 - 297, Update the sizing rules for html,
body, and `#root` to avoid clipping and improve compatibility: replace height:
100svh with min-height: 100svh on these selectors (or at least on `#root`) so
content can grow, and add a fallback for older browsers by keeping/adding a
vh-based fallback before the svh declaration (or use an `@supports` check for
svh). Ensure the change targets the existing selectors (html, body, `#root`) and
that the fallback order places the broader-supported value first followed by the
svh value so browsers that don't support svh will use the fallback.

@@ -1,4 +1,4 @@
import { useState, useEffect, useMemo } from 'react'
import { useState, useEffect, useMemo } from 'react';
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

🧩 Analysis chain

🏁 Script executed:

find . -name "kiro-provider-view.tsx" -type f

Repository: awsl-project/maxx

Length of output: 120


🏁 Script executed:

wc -l ./web/src/pages/providers/components/kiro-provider-view.tsx

Repository: awsl-project/maxx

Length of output: 124


🏁 Script executed:

cat -n ./web/src/pages/providers/components/kiro-provider-view.tsx | head -20

Repository: awsl-project/maxx

Length of output: 721


🏁 Script executed:

cat -n ./web/src/pages/providers/components/kiro-provider-view.tsx | sed -n '250,290p'

Repository: awsl-project/maxx

Length of output: 1682


🏁 Script executed:

cat -n ./web/src/pages/providers/components/kiro-provider-view.tsx | sed -n '283,320p'

Repository: awsl-project/maxx

Length of output: 1924


🏁 Script executed:

cat -n ./web/src/pages/providers/components/kiro-provider-view.tsx | sed -n '320,380p'

Repository: awsl-project/maxx

Length of output: 3255


🏁 Script executed:

cat -n ./web/src/pages/providers/components/kiro-provider-view.tsx | sed -n '359,366p'

Repository: awsl-project/maxx

Length of output: 469


🏁 Script executed:

cat -n ./web/src/pages/providers/components/kiro-provider-view.tsx | sed -n '261,281p'

Repository: awsl-project/maxx

Length of output: 918


防止异步配额拉取中的旧响应覆盖新数据
快速切换 provider 或连续点击 Refresh 时,旧请求返回可能覆盖新数据。建议用请求序号或 AbortController 抑制过期响应。

💡 示例:用请求序号防止过期响应
-import { useState, useEffect, useMemo } from 'react';
+import { useState, useEffect, useMemo, useRef } from 'react';

 export function KiroProviderView({ provider, onDelete, onClose }: KiroProviderViewProps) {
   const [quota, setQuota] = useState<KiroQuotaData | null>(null);
   const [loading, setLoading] = useState(false);
   const [error, setError] = useState<string | null>(null);
+  const requestIdRef = useRef(0);

   const fetchQuota = async () => {
+    const requestId = ++requestIdRef.current;
     setLoading(true);
     setError(null);
     try {
       const data = await getTransport().getKiroProviderQuota(provider.id);
-      setQuota(data);
+      if (requestIdRef.current === requestId) {
+        setQuota(data);
+      }
     } catch (err) {
-      setError(err instanceof Error ? err.message : 'Failed to fetch quota');
+      if (requestIdRef.current === requestId) {
+        setError(err instanceof Error ? err.message : 'Failed to fetch quota');
+      }
     } finally {
-      setLoading(false);
+      if (requestIdRef.current === requestId) {
+        setLoading(false);
+      }
     }
   };

   useEffect(() => {
     fetchQuota();
+    return () => {
+      requestIdRef.current += 1;
+    };
   }, [provider.id]); // eslint-disable-line react-hooks/exhaustive-deps
🤖 Prompt for AI Agents
In `@web/src/pages/providers/components/kiro-provider-view.tsx` at line 1, 在
kiro-provider-view.tsx 中防止旧的异步配额响应覆盖新数据:为 fetchQuota/refresh 逻辑引入一个请求序号或
AbortController(例如 currentRequestIdRef 或 abortControllerRef),在每次触发拉取(包括
useEffect 和点击 Refresh 的处理函数)先递增序号或创建并替换 AbortController,然后在响应到达时只在序号匹配或未被中止时调用
setQuota/setLoading 等状态更新;另外在组件卸载或新请求发起时取消先前请求以避免竞态(定位到触发拉取的 useEffect 和 refresh
handler,如 fetchQuota/loadQuota/handleRefresh)。

@Bowl42 Bowl42 merged commit 1a236f4 into awsl-project:main Jan 18, 2026
2 checks passed
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.

3 participants