Skip to content

feat: 优化 Antigravity Quota 批量查询与 UI 布局#115

Merged
Bowl42 merged 1 commit intomainfrom
feat/antigravity-quota-batch-optimization
Jan 17, 2026
Merged

feat: 优化 Antigravity Quota 批量查询与 UI 布局#115
Bowl42 merged 1 commit intomainfrom
feat/antigravity-quota-batch-optimization

Conversation

@Bowl42
Copy link
Collaborator

@Bowl42 Bowl42 commented Jan 17, 2026

Summary

  • 新增批量获取配额 API: GET /antigravity/providers/quotas,减少 N 个单独请求为 1 个批量请求
  • 缓存时间从 5 分钟延长到 10 分钟,减少不必要的 API 调用
  • 创建 AntigravityQuotasProvider 上下文实现懒加载,只有进入相关页面才发起请求
  • 优化 provider-row 布局:
    • 移除左侧类型图标,改为显示 Clients 图标(居中)
    • Antigravity provider 移除邮箱显示,只显示 Claude 余额进度条

Test plan

  • 验证 Providers 页面加载时只发起一个批量配额请求
  • 验证 Client Routes 页面加载时只发起一个批量配额请求
  • 验证 Claude 余额进度条正确显示在左侧
  • 验证 Clients 图标在左侧居中显示
  • 验证非 Antigravity provider(如 Kiro、Custom)仍显示邮箱/endpoint 信息
  • 验证缓存 10 分钟内不会重复请求

Summary by CodeRabbit

发布说明

  • 新功能

    • 增加了批量获取Antigravity提供商配额的功能
    • 优化了配额缓存机制,将有效期从5分钟延长至10分钟
  • 改进

    • 重新设计了提供商信息展示,新增支持的客户端类型集群显示
    • 改进了配额进度条的可视化效果,提供更清晰的动态显示

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

- 新增批量获取配额 API: GET /antigravity/providers/quotas
- 缓存时间从 5 分钟延长到 10 分钟
- 创建 AntigravityQuotasProvider 上下文实现懒加载
- 优化 provider-row 布局:
  - 移除左侧类型图标,改为显示 Clients 图标
  - Antigravity provider 移除邮箱显示,只显示 Claude 余额进度条
- 减少不必要的 API 请求,提升性能
@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

步骤说明

引入批量Antigravity配额查询功能,包括后端批量检索API、React context管理层、HTTP传输层支持和前端页面集成,实现统一的配额缓存策略。

变更

组群 / 文件 变更概览
后端批量配额检索
internal/handler/antigravity.go
新增 BatchQuotaResult 类型、GetBatchQuotas() 方法和 handleGetBatchQuotas() HTTP处理器;引入 GET /antigravity/providers/quotas 路由;将单个提供者配额缓存从5分钟扩展到10分钟;支持API调用失败时回退到缓存数据
React Context管理层
web/src/contexts/antigravity-quotas-context.tsx
新增 AntigravityQuotasProvider context提供者、useAntigravityQuotasContext() hook和 useAntigravityQuotaFromContext() 轻量级hook;实现批量配额获取、加载状态管理和按提供者ID的配额访问器
HTTP传输层
web/src/lib/transport/http-transport.ts, web/src/lib/transport/interface.ts, web/src/lib/transport/types.ts, web/src/lib/transport/index.ts
新增 getAntigravityBatchQuotas() 方法和 AntigravityBatchQuotaResult 类型;支持从 /api/antigravity/providers/quotas 端点检索批量配额
查询Hook层
web/src/hooks/queries/use-providers.ts, web/src/hooks/queries/index.ts
新增 useAntigravityBatchQuotas() hook;将单个配额查询刷新周期从60秒调整到10分钟;设置10分钟缓存有效期
页面组件集成
web/src/components/routes/ClientTypeRoutesContent.tsx, web/src/pages/providers/index.tsx
使用 AntigravityQuotasProvider 包装组件树,为子组件提供context可用性
配额数据源迁移
web/src/pages/client-routes/components/provider-row.tsx, web/src/pages/providers/components/provider-row.tsx
从直接Hook useAntigravityQuota() 迁移到Context-based useAntigravityQuotaFromContext();重构Claude配额显示为内联进度条;更新Antigravity提供者的UI布局和端点显示逻辑;重新设计左侧导航为支持客户端图标集群

序列图

sequenceDiagram
    participant Client as 浏览器客户端
    participant Context as AntigravityQuotasProvider
    participant Hook as useAntigravityBatchQuotas
    participant Transport as HttpTransport
    participant API as 后端API
    participant Cache as 配额缓存
    
    Client->>Context: 挂载页面(使用Provider包装)
    Context->>Hook: 初始化Hook
    Hook->>Transport: getAntigravityBatchQuotas()
    Transport->>API: GET /api/antigravity/providers/quotas
    
    alt 缓存有效(10分钟内)
        API->>Cache: 检查缓存
        Cache-->>API: 返回缓存数据
    else 缓存过期或不存在
        API->>API: 逐个获取提供者配额
        API->>API: 应用10分钟缓存窗口
        API->>Cache: 持久化结果
    end
    
    API-->>Transport: 返回 { quotas: Record<providerId, QuotaData> }
    Transport-->>Hook: 更新配额数据
    Hook-->>Context: 广播quotas和isLoading状态
    Context->>Client: 暴露getQuotaForProvider()访问器
    Client->>Client: 组件消费useAntigravityQuotaFromContext(providerId)
    Client->>Client: 渲染Claude配额进度条和重置时间
Loading

预估代码审查工作量

🎯 3 (中等) | ⏱️ ~20 分钟

建议审查员

  • awsl233777
  • whhjdi

🐰 批量配额齐声来,
Context提供者铺新路,
缓存十分钟安心在,
进度条闪闪展数据,
前后端握手舞起来!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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 标题使用中文清晰地概括了主要变更:批量查询 Antigravity Quota 和优化 UI 布局,与 raw_summary 和 PR 目标相符。

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

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
web/src/lib/transport/http-transport.ts (1)

381-386: 建议为 quotas 结果做兜底,避免返回 undefined。
如果服务端异常或字段缺失,当前实现会把 undefined 传到下游,类型上却是 Record

♻️ 建议修改
-  async getAntigravityBatchQuotas(): Promise<Record<number, AntigravityQuotaData>> {
-    const { data } = await axios.get<{ quotas: Record<number, AntigravityQuotaData> }>(
-      '/api/antigravity/providers/quotas',
-    );
-    return data.quotas;
-  }
+  async getAntigravityBatchQuotas(): Promise<Record<number, AntigravityQuotaData>> {
+    const { data } = await axios.get<{ quotas: Record<number, AntigravityQuotaData> }>(
+      '/api/antigravity/providers/quotas',
+    );
+    return data?.quotas ?? {};
+  }
web/src/contexts/antigravity-quotas-context.tsx (1)

23-35: 考虑使用 useMemouseCallback 稳定 context value

getQuotaForProvider 每次渲染都会创建新函数,并且 context value 对象也会重建,这可能导致所有消费者不必要的重新渲染。

♻️ 建议的优化
 export function AntigravityQuotasProvider({ children, enabled = true }: AntigravityQuotasProviderProps) {
   const { data: quotas, isLoading } = useAntigravityBatchQuotas(enabled);

-  const getQuotaForProvider = (providerId: number): AntigravityQuotaData | undefined => {
-    return quotas?.[providerId];
-  };
+  const getQuotaForProvider = useCallback(
+    (providerId: number): AntigravityQuotaData | undefined => {
+      return quotas?.[providerId];
+    },
+    [quotas]
+  );
+
+  const value = useMemo(
+    () => ({ quotas, isLoading, getQuotaForProvider }),
+    [quotas, isLoading, getQuotaForProvider]
+  );

   return (
-    <AntigravityQuotasContext.Provider value={{ quotas, isLoading, getQuotaForProvider }}>
+    <AntigravityQuotasContext.Provider value={value}>
       {children}
     </AntigravityQuotasContext.Provider>
   );
 }

需要更新 import:

-import { createContext, useContext, type ReactNode } from 'react';
+import { createContext, useContext, useCallback, useMemo, type ReactNode } from 'react';
web/src/pages/client-routes/components/provider-row.tsx (1)

142-178: 存在代码重复:getClaudeQuotaInfoformatResetTimeweb/src/pages/providers/components/provider-row.tsx 重复

这两个辅助函数在两个 provider-row 组件中完全相同。建议提取到共享的工具模块中。

♻️ 建议提取到共享模块

可以在 web/src/lib/quota-utils.ts 或类似位置创建共享模块:

// web/src/lib/quota-utils.ts
import type { AntigravityQuotaData } from '@/lib/transport';

export function getClaudeQuotaInfo(
  quota: AntigravityQuotaData | undefined,
): { percentage: number; resetTime: string } | null {
  if (!quota || quota.isForbidden || !quota.models) return null;
  const claudeModel = quota.models.find((m) => m.name.includes('claude'));
  if (!claudeModel) return null;
  return {
    percentage: claudeModel.percentage,
    resetTime: claudeModel.resetTime,
  };
}

export function formatResetTime(resetTime: string, t: (key: string) => string): string {
  // ... implementation
}
internal/handler/antigravity.go (1)

382-416: 考虑并发获取配额以提升性能

当前实现对每个 Antigravity provider 顺序调用 FetchQuotaForProvider。如果 provider 数量较多,这可能导致批量请求耗时过长。

♻️ 建议使用 goroutine 并发获取
// 使用 sync.WaitGroup 和 sync.Map 并发获取配额
var wg sync.WaitGroup
var mu sync.Mutex // 或使用 sync.Map

for _, provider := range providers {
    if provider.Type != "antigravity" || provider.Config == nil || provider.Config.Antigravity == nil {
        continue
    }
    
    wg.Add(1)
    go func(p *domain.Provider) {
        defer wg.Done()
        
        config := p.Config.Antigravity
        // ... 获取配额逻辑 ...
        
        mu.Lock()
        result.Quotas[p.ID] = quota
        mu.Unlock()
    }(provider)
}

wg.Wait()

注意:需要考虑并发数限制(如使用 semaphore)以避免对上游 API 造成过大压力。

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

115-115: displayInfo 在 Antigravity provider 有 claudeInfo 时未被使用

displayInfo 仅在 else 分支(Lines 207-217)中使用,但每次渲染都会调用 typeConfig.getDisplayInfo(provider)。虽然影响很小,但可以考虑延迟计算。

♻️ 可选:延迟计算 displayInfo
-  const displayInfo = typeConfig.getDisplayInfo(provider);
   // ...
-            <span className="truncate">{displayInfo}</span>
+            <span className="truncate">{typeConfig.getDisplayInfo(provider)}</span>

或者使用 useMemo:

const displayInfo = useMemo(() => {
  if (isAntigravity && claudeInfo) return null;
  return typeConfig.getDisplayInfo(provider);
}, [isAntigravity, claudeInfo, typeConfig, provider]);
📜 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 bbbdc11 and 9541b0c.

📒 Files selected for processing (12)
  • internal/handler/antigravity.go
  • web/src/components/routes/ClientTypeRoutesContent.tsx
  • web/src/contexts/antigravity-quotas-context.tsx
  • web/src/hooks/queries/index.ts
  • web/src/hooks/queries/use-providers.ts
  • web/src/lib/transport/http-transport.ts
  • web/src/lib/transport/index.ts
  • web/src/lib/transport/interface.ts
  • web/src/lib/transport/types.ts
  • web/src/pages/client-routes/components/provider-row.tsx
  • web/src/pages/providers/components/provider-row.tsx
  • web/src/pages/providers/index.tsx
🧰 Additional context used
🧬 Code graph analysis (8)
web/src/lib/transport/interface.ts (1)
web/src/lib/transport/types.ts (1)
  • AntigravityQuotaData (335-340)
web/src/hooks/queries/use-providers.ts (2)
web/src/hooks/queries/index.ts (2)
  • useAntigravityBatchQuotas (16-16)
  • providerKeys (7-7)
web/src/lib/transport/factory.ts (1)
  • getTransport (79-102)
web/src/contexts/antigravity-quotas-context.tsx (4)
web/src/lib/transport/index.ts (1)
  • AntigravityQuotaData (46-46)
web/src/lib/transport/types.ts (1)
  • AntigravityQuotaData (335-340)
web/src/hooks/queries/index.ts (1)
  • useAntigravityBatchQuotas (16-16)
web/src/hooks/queries/use-providers.ts (1)
  • useAntigravityBatchQuotas (111-120)
web/src/lib/transport/http-transport.ts (2)
web/src/lib/transport/index.ts (1)
  • AntigravityQuotaData (46-46)
web/src/lib/transport/types.ts (1)
  • AntigravityQuotaData (335-340)
internal/handler/antigravity.go (1)
internal/adapter/provider/antigravity/service.go (2)
  • QuotaData (52-57)
  • FetchQuotaForProvider (118-142)
web/src/components/routes/ClientTypeRoutesContent.tsx (1)
web/src/contexts/antigravity-quotas-context.tsx (1)
  • AntigravityQuotasProvider (23-35)
web/src/pages/providers/components/provider-row.tsx (3)
web/src/contexts/antigravity-quotas-context.tsx (1)
  • useAntigravityQuotaFromContext (46-49)
web/src/components/icons/client-icons.tsx (1)
  • ClientIcon (65-100)
web/src/lib/utils.ts (1)
  • cn (8-10)
web/src/pages/client-routes/components/provider-row.tsx (3)
web/src/contexts/antigravity-quotas-context.tsx (1)
  • useAntigravityQuotaFromContext (46-49)
web/src/lib/utils.ts (1)
  • cn (8-10)
internal/version/version.go (1)
  • Info (14-16)
🔇 Additional comments (19)
web/src/lib/transport/types.ts (1)

342-345: 新增批量配额类型可读性很好。
与批量接口返回结构一致,便于上下游复用。

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

43-48: 导出新增类型没问题。
对外暴露批量配额类型清晰且一致。

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

122-127: 接口扩展与实现一致。
新增批量配额方法签名清晰。

web/src/hooks/queries/use-providers.ts (2)

104-107: 刷新/缓存窗口调整符合 10 分钟目标。
节流请求与缓存策略一致。

Also applies to: 128-130


110-119: 批量额度 hook 设计清晰。
queryKey 与调用点明确,便于统一管理。

web/src/hooks/queries/index.ts (1)

15-17: 新增 hook 导出合理。
对外暴露批量额度查询能力清晰。

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

37-43: LGTM!

useAntigravityQuotasContext 正确实现了在 Provider 外使用时抛出错误的保护机制,这是 React context 的最佳实践。


45-49: LGTM!

useAntigravityQuotaFromContext 提供了一个安全的可选 hook,当在 Provider 外部使用时不会抛出错误而是返回 undefined,这对于需要条件渲染的场景非常有用。

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

11-11: LGTM!

正确切换到使用 useAntigravityQuotaFromContext,与批量配额优化目标一致。


352-391: LGTM!

条件渲染逻辑正确:

  • Antigravity provider 且有 claudeInfo 时显示 Claude 配额进度条
  • 其他情况显示 endpoint 信息

进度条颜色阈值(≥50% 绿色,≥20% 黄色,<20% 红色)清晰直观。

internal/handler/antigravity.go (4)

61-65: LGTM!

路由顺序正确,批量配额路径 /antigravity/providers/quotas 在单个 provider 路由之前匹配,避免了路径冲突。


287-288: LGTM!

缓存时间从 5 分钟延长到 10 分钟,与前端 useAntigravityBatchQuotas hook 的 refetchInterval: 600000 保持一致。


403-416: LGTM!

错误处理策略合理:单个 provider 的配额获取失败不会中断整个批量查询,而是优雅降级到使用缓存数据或跳过该 provider。这确保了批量接口的高可用性。


434-443: LGTM!

HTTP handler 实现简洁,正确调用 GetBatchQuotas 并返回 JSON 响应。

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

162-196: LGTM!

AntigravityQuotasProvider 正确包裹了 provider 列表内容,实现了懒加载:

  • 仅在有 providers 数据时才渲染 Provider,从而触发配额请求
  • Provider 放置在 else 分支内,避免在 loading 或空状态时不必要的请求
web/src/components/routes/ClientTypeRoutesContent.tsx (1)

216-347: 考虑在 loading 完成后再渲染 AntigravityQuotasProvider

当前 AntigravityQuotasProvider 在 loading 状态检查之后包裹整个内容,但如果将其移到 loading 检查之前,会导致在数据加载期间就发起配额请求。

当前实现已经正确:Provider 在 if (loading) 检查之后,仅在有数据时才渲染。

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

8-9: LGTM!

正确切换到使用 useAntigravityQuotaFromContext 获取 Antigravity 配额,同时保留 useKiroQuota 用于 Kiro provider。


151-167: LGTM!

新的 "Supported Clients" 图标集群实现良好:

  • 使用 -space-x-1.5 创建重叠效果
  • hover 时有 scale 和 translate 动画
  • 无支持客户端时显示 - 占位符

184-218: LGTM!

条件渲染逻辑与 client-routes/components/provider-row.tsx 保持一致:

  • Antigravity provider 显示 Claude 配额进度条
  • 其他类型显示邮箱(账户类型)或 endpoint(非账户类型)

✏️ 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.

@Bowl42 Bowl42 merged commit 5eb630e into main Jan 17, 2026
2 checks passed
@Bowl42 Bowl42 deleted the feat/antigravity-quota-batch-optimization branch January 17, 2026 17:45
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