Skip to content

fix: 恢复当前构建与单测基线#879

Open
NieiR wants to merge 3 commits intoding113:devfrom
NieiR:fix/ci-build-recovery
Open

fix: 恢复当前构建与单测基线#879
NieiR wants to merge 3 commits intoding113:devfrom
NieiR:fix/ci-build-recovery

Conversation

@NieiR
Copy link
Contributor

@NieiR NieiR commented Mar 7, 2026

This PR only contains:

  • 修复 src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsxsrc/components/ui/chart.tsx 的 tooltip 类型假设,恢复 typecheck / build
  • 补齐 messages/zh-TW/settings/prices.jsonmessages/ja/settings/prices.jsonmessages/ru/settings/prices.json 中缺失的 prices.badges.multi
  • 对齐 tests/unit/lib/cost-calculation-breakdown.test.ts 与当前 long-context 整单计价语义
  • 更新 tests/unit/proxy/response-handler-lease-decrement.test.ts 的夹具与入口,使其匹配当前 response-handler 的成本追踪路径

This PR intentionally excludes:

  • 日志页 UI 改动
  • pricing 业务语义实现变更
  • lease 生产逻辑变更
  • 其他与当前 CI 失败无关的重构或清理

Why split this way:

  • 当前多个小 PR 会被公共的构建/单测失败连坐,先恢复基线才能让后续 PR 有独立可审阅性
  • 这 4 类问题共同构成了当前 CI 红灯的主要来源,合并修复可以减少重复失败和重复审阅成本
  • 该 PR 只处理“让当前基线重新变绿”所需的最小改动,不混入新的功能需求

How to verify:

  • 运行 bun run typecheck
  • 运行 bun run build
  • 运行 bun run test -- tests/unit/ --passWithNoTests
  • 可额外单跑以下文件确认关键修复点:
    • node /home/opus/projects/claude-code-hub/node_modules/vitest/vitest.mjs run tests/unit/i18n/settings-split-guards.test.ts
    • node /home/opus/projects/claude-code-hub/node_modules/vitest/vitest.mjs run tests/unit/lib/cost-calculation-breakdown.test.ts
    • node /home/opus/projects/claude-code-hub/node_modules/vitest/vitest.mjs run tests/unit/proxy/response-handler-lease-decrement.test.ts
    • node /home/opus/projects/claude-code-hub/node_modules/vitest/vitest.mjs run tests/unit/dashboard/availability/latency-chart.test.tsx

Greptile Summary

This PR restores CI green by addressing four independent failure categories: TypeScript tooltip type errors in the chart components, missing badges.multi i18n keys in three locales, misaligned cost-calculation test expectations (now reflecting the "whole-request" long-context pricing semantics), and an outdated response-handler test fixture/entry-point that no longer matched the current finalizeRequestStats API shape.

Key changes:

  • src/components/ui/chart.tsx — introduces ChartTooltipValue, TooltipPayloadEntry, and normalizePayloadKey helpers to eliminate unsafe type assertions in the tooltip render pipeline; also fixes zero-value display (item.value && …item.value !== undefined && item.value !== null)
  • src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx — imports TooltipContentProps and adds a local normalizeTooltipKey helper for safe key derivation
  • messages/{ja,ru,zh-TW}/settings/prices.json — backfills the missing prices.badges.multi key that was causing i18n guard test failures
  • tests/unit/lib/cost-calculation-breakdown.test.ts — updates two tiered-pricing assertions to match the current "charge all tokens at the premium rate once threshold is exceeded" implementation (verified: 300k × $0.000003 × 2.0 = $1.80 input; 100 × $0.000015 × 1.5 = $0.00225 output)
  • tests/unit/proxy/response-handler-lease-decrement.test.ts — replaces ProxyResponseHandler.dispatch with the exported finalizeRequestStats function and extends the session fixture with resolvedPricingCache, getResolvedPricingByBillingSource, and bypassResponseRectifier to match the current ProxySession interface

Confidence Score: 4/5

  • Safe to merge; all changes are minimal CI-restoration fixes with no production logic alterations.
  • All four fix categories are well-scoped and cross-verified against the implementation. The arithmetic in the cost tests has been manually validated. Two non-blocking style issues exist in chart.tsx (formatter condition broadening and potential toLocaleString on array values), but neither introduces a runtime error under current usage.
  • src/components/ui/chart.tsx — minor formatter condition and array toLocaleString concerns worth a second look before the next feature builds on this component.

Important Files Changed

Filename Overview
src/components/ui/chart.tsx Broadens ChartTooltipValue type to include ReadonlyArray, replaces inline type assertions with typed helpers, and fixes the key/value rendering pipeline. Two minor style concerns: the formatter condition change from truthy to !== undefined and calling toLocaleString() on a potentially array-typed value.
src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx Imports TooltipContentProps type from recharts and introduces a local normalizeTooltipKey helper to safely derive string keys from potentially non-string dataKey values. Logic is correct; helper is a minor duplication of normalizePayloadKey in chart.tsx.
tests/unit/lib/cost-calculation-breakdown.test.ts Correctly updates two tiered-pricing tests to reflect the "whole-request" long-context pricing semantics. Verified against the implementation: 300k tokens × 0.000003 × 2.0 = 1.8 (input), 100 × 0.000015 × 1.5 = 0.00225 (output). Math is accurate.
tests/unit/proxy/response-handler-lease-decrement.test.ts Migrates test entry-point from ProxyResponseHandler.dispatch to the exported finalizeRequestStats function; adds resolvedPricingCache, bypassResponseRectifier, getResolvedPricingByBillingSource, and SessionManager.updateSessionUsage mock to match the current session shape. Changes are well-scoped and structurally correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["ChartTooltip payload item"] --> B{item.value\n!== undefined\n&& !== null?}
    B -- No --> C[Skip rendering value span]
    B -- Yes --> D{tooltipFormatter\n&& item.name\n!== undefined?}
    D -- Yes --> E["tooltipFormatter(value, itemName, item, index, payload)"]
    D -- No --> F{item.value\nis array?}
    F -- Yes --> G["item.value.toLocaleString()\n→ comma-joined string ⚠️"]
    F -- No --> H["item.value.toLocaleString()\n→ formatted number/string ✅"]
    E --> I[Custom formatter output]
    G --> J[Rendered span]
    H --> J
Loading

Last reviewed commit: 825a444

Greptile also left 3 inline comments on this PR.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on restoring the continuous integration (CI) baseline by addressing several critical issues that were causing build and unit test failures. The changes are minimal and specifically target these identified problems, ensuring that the project's foundational tests and build processes are stable and green. This restoration is crucial for enabling independent reviewability of subsequent pull requests and streamlining the development workflow.

Highlights

  • Tooltip Type Assumptions: Fixed tooltip type assumptions in src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx and src/components/ui/chart.tsx to resolve typecheck and build failures.
  • Internationalization Updates: Completed missing prices.badges.multi translations in messages/zh-TW/settings/prices.json, messages/ja/settings/prices.json, and messages/ru/settings/prices.json.
  • Cost Calculation Alignment: Aligned tests/unit/lib/cost-calculation-breakdown.test.ts with the current long-context full order pricing semantics.
  • Proxy Response Handler Tests: Updated fixtures and entry points for tests/unit/proxy/response-handler-lease-decrement.test.ts to match the current response-handler cost tracking path.
Changelog
  • messages/ja/settings/prices.json
    • Added missing 'multi' badge translation.
  • messages/ru/settings/prices.json
    • Added missing 'multi' badge translation.
  • messages/zh-TW/settings/prices.json
    • Added missing 'multi' badge translation.
  • src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx
    • Imported TooltipContentProps type from recharts.
    • Introduced normalizeTooltipKey function for robust tooltip key handling.
    • Applied normalizeTooltipKey to chart tooltip rendering logic.
  • src/components/ui/chart.tsx
    • Introduced TooltipPayloadEntry type and normalizePayloadKey function for robust tooltip payload key handling.
    • Applied normalizePayloadKey to tooltip content rendering for labelKey, dataKey, and name.
  • tests/unit/lib/cost-calculation-breakdown.test.ts
    • Updated expected cost calculations in test cases to align with the new long-context pricing rule.
    • Added comments explaining the updated pricing logic.
  • tests/unit/proxy/response-handler-lease-decrement.test.ts
    • Imported ResolvedPricing type.
    • Replaced ProxyResponseHandler import with finalizeRequestStats.
    • Modified createSession to include resolvedPricingCache and getResolvedPricingByBillingSource.
    • Updated endpointPolicy in createSession to include bypassResponseRectifier.
    • Mocked SessionManager.updateSessionUsage.
    • Replaced ProxyResponseHandler.dispatch with finalizeRequestStats across multiple test cases.
    • Adjusted response handling in tests to match the new finalizeRequestStats signature.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

📝 Walkthrough

Walkthrough

本次改动新增多语言“multi”价格徽章键,重构 Chart Tooltip 的载荷键/标签归一化与类型定义,调整成本计算测试以采用长上下文整体计价规则,并将响应处理测试从 ProxyResponseHandler.dispatch 迁移为 finalizeRequestStats 并扩展会话模拟。

Changes

Cohort / File(s) Summary
多语言价格标签本地化
messages/ja/settings/prices.json, messages/ru/settings/prices.json, messages/zh-TW/settings/prices.json
在各语言的 badges 对象中新增 "multi" 条目(分别为 日/俄/繁中 文本),并调整 JSON 以容纳新字段。
Chart 组件 Tooltip 重构
src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx, src/components/ui/chart.tsx
新增/使用类型 TooltipPayloadEntryChartTooltipValueTooltipFormatter 等,添加 normalizePayloadKey/normalizeTooltipKey 辅助函数,改为稳健的键与标签派生、索引感知的 tooltip 渲染、支持自定义 formatter 与图例图标/颜色回退。
成本计算与响应处理测试调整
tests/unit/lib/cost-calculation-breakdown.test.ts, tests/unit/proxy/response-handler-lease-decrement.test.ts
成本计算测试改为:跨越 200k 阈值时整个请求使用长上下文定价;响应处理测试用 finalizeRequestStats 替换 ProxyResponseHandler.dispatch,并在测试会话工厂中添加 resolvedPricingCachegetResolvedPricingByBillingSource 以及 SessionManager.updateSessionUsage 的模拟。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR标题清晰准确地概括了主要改动:恢复CI构建与单测基线,与所有文件变更相符。
Description check ✅ Passed PR描述详细说明了四类独立的CI修复:tooltip类型问题、缺失i18n键、成本计算测试对齐和response-handler测试入口更新。

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@github-actions github-actions bot added bug Something isn't working area:UI area:i18n labels Mar 7, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

此拉取请求主要致力于修复持续集成(CI)流水线,以恢复构建和单元测试的基线。主要变更包括: * 修复 latency-chart.tsxchart.tsx 中图表工具提示的类型定义,解决了构建失败的问题。 * 在 prices.json 文件中为多种语言添加了缺失的翻译。 * 更新成本计算的单元测试(cost-calculation-breakdown.test.ts),使其与新的长上下文请求定价逻辑保持一致。 * 重构租约递减测试(response-handler-lease-decrement.test.ts),以匹配响应处理器中更新后的成本追踪逻辑。 总体而言,这些更改清晰、必要,并有效地实现了让 CI 恢复绿色的目标。代码质量良好,我没有发现任何问题。

@github-actions github-actions bot added the size/M Medium PR (< 500 lines) label Mar 7, 2026
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

This PR addresses CI build and test failures through targeted fixes in four areas: tooltip type safety, i18n completeness, and test alignment with current pricing/billing logic. The changes are appropriately scoped for a CI recovery PR.

PR Size: M

  • Lines changed: 280 (161 additions, 119 deletions)
  • Files changed: 7

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 1 0
Simplification 0 0 0 0

Medium Priority Issues (Should Consider)

[TEST-BRITTLE] Manual ProxySession construction in tests

  • File: tests/unit/proxy/response-handler-lease-decrement.test.ts
  • Issue: The session mock uses Object.create(ProxySession.prototype) with manual property assignment, which bypasses TypeScript constructor validation and creates a brittle test that will break when ProxySession changes.
  • Suggestion: Consider creating a test factory helper or using vi.mock() for proper type-safe mocking in future refactors.

Review Coverage

  • Logic and correctness - All fixes are correct
  • Security (OWASP Top 10) - No security concerns
  • Error handling - Proper type normalization prevents runtime errors
  • Type safety - Type fixes are appropriate
  • Documentation accuracy - Comments match implementation
  • Test coverage - Tests updated to match current pricing semantics
  • Code clarity - Well-structured changes

Verification Notes

  1. Tooltip Type Fix: The normalizeTooltipKey helper correctly handles dataKey types from Recharts.

  2. i18n Completeness: prices.badges.multi translations properly added for ja, ru, zh-TW locales.

  3. Pricing Test Update: Expectations correctly updated to reflect long-context whole request pricing.

  4. Response Handler Test: Correctly updated to use finalizeRequestStats.


Automated review by Claude AI

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/ui/chart.tsx`:
- Line 148: The code uses logical OR fallbacks when computing the payload key
which incorrectly treats valid falsy values as missing; update the expression
that sets key (currently using labelKey || item?.dataKey || item?.name with
normalizePayloadKey) to use nullish coalescing (labelKey ?? item?.dataKey ??
item?.name) so normalizePayloadKey receives legitimate 0/"" values; apply the
same change to the other occurrence mentioned (the second chained fallback) to
use ?? consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 595eb969-6c68-468f-93bf-930d83753d9f

📥 Commits

Reviewing files that changed from the base of the PR and between 2b60af9 and 292166e.

📒 Files selected for processing (7)
  • messages/ja/settings/prices.json
  • messages/ru/settings/prices.json
  • messages/zh-TW/settings/prices.json
  • src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx
  • src/components/ui/chart.tsx
  • tests/unit/lib/cost-calculation-breakdown.test.ts
  • tests/unit/proxy/response-handler-lease-decrement.test.ts


const [item] = payload;
const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
const key = normalizePayloadKey(labelKey || item?.dataKey || item?.name, "value");
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:

cd /repo && find . -name "chart.tsx" -type f | head -5

Repository: ding113/claude-code-hub

Length of output: 122


🏁 Script executed:

cat -n src/components/ui/chart.tsx | sed -n '140,210p'

Repository: ding113/claude-code-hub

Length of output: 3117


🏁 Script executed:

ast-grep --pattern 'function normalizePayloadKey($$$) {
  $$$
}'

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

rg "normalizePayloadKey" src/components/ui/chart.tsx -B 2 -A 10

Repository: ding113/claude-code-hub

Length of output: 1767


🏁 Script executed:

rg "function normalizePayloadKey|const normalizePayloadKey" src/ -A 10

Repository: ding113/claude-code-hub

Length of output: 616


🏁 Script executed:

cat -n src/components/ui/chart.tsx | sed -n '1,50p'

Repository: ding113/claude-code-hub

Length of output: 1620


🏁 Script executed:

cat -n src/components/ui/chart.tsx | sed -n '145,160p'

Repository: ding113/claude-code-hub

Length of output: 688


🏁 Script executed:

rg "typeof value|dataKey|item\.name" src/components/ui/chart.tsx -B 1 -A 1 | head -50

Repository: ding113/claude-code-hub

Length of output: 1214


|| 改为 ??,以支持合法的 falsy 键值。

Line 156 和 Line 195 在使用 || 进行链式回退时,会跳过合法的 falsy 值(如数字 0 和空字符串 "")。由于 normalizePayloadKey 函数明确支持 string 和 number 类型,应使用 ??(nullish coalescing)仅在 null/undefined 时回退。

建议修改
-    const key = normalizePayloadKey(labelKey || item?.dataKey || item?.name, "value");
+    const key = normalizePayloadKey(labelKey ?? item?.dataKey ?? item?.name, "value");
-            const key = normalizePayloadKey(nameKey || item.name || item.dataKey, "value");
+            const key = normalizePayloadKey(nameKey ?? item.name ?? item.dataKey, "value");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const key = normalizePayloadKey(labelKey || item?.dataKey || item?.name, "value");
const key = normalizePayloadKey(labelKey ?? item?.dataKey ?? item?.name, "value");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/chart.tsx` at line 148, The code uses logical OR fallbacks
when computing the payload key which incorrectly treats valid falsy values as
missing; update the expression that sets key (currently using labelKey ||
item?.dataKey || item?.name with normalizePayloadKey) to use nullish coalescing
(labelKey ?? item?.dataKey ?? item?.name) so normalizePayloadKey receives
legitimate 0/"" values; apply the same change to the other occurrence mentioned
(the second chained fallback) to use ?? consistently.

indicator === "dot" && "items-center"
)}
>
{tooltipFormatter && item?.value !== undefined && item.name !== undefined ? (
Copy link

Choose a reason for hiding this comment

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

Formatter condition broadened to include empty-string names

Changing the condition from item.name (truthy) to item.name !== undefined means items whose name is an empty string "" will now invoke the tooltipFormatter, whereas previously they would have fallen through to the default rendering block.

In practice recharts usually provides a non-empty name, but any series registered with an empty string key will silently change rendering behaviour. Consider being explicit about the intent:

Suggested change
{tooltipFormatter && item?.value !== undefined && item.name !== undefined ? (
{tooltipFormatter && item?.value !== undefined && !!item.name ? (

This preserves the previous truthy-check semantics while keeping the cleaner variable name.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/ui/chart.tsx
Line: 209

Comment:
**Formatter condition broadened to include empty-string names**

Changing the condition from `item.name` (truthy) to `item.name !== undefined` means items whose `name` is an empty string `""` will now invoke the `tooltipFormatter`, whereas previously they would have fallen through to the default rendering block.

In practice recharts usually provides a non-empty name, but any series registered with an empty string key will silently change rendering behaviour. Consider being explicit about the intent:

```suggestion
                {tooltipFormatter && item?.value !== undefined && !!item.name ? (
```

This preserves the previous truthy-check semantics while keeping the cleaner variable name.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +255 to +259
{item.value !== undefined && item.value !== null && (
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
Copy link

Choose a reason for hiding this comment

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

toLocaleString() called on a potentially array-typed value

item.value is now typed as ChartTooltipValue = number | string | ReadonlyArray<number | string>. When item.value is a ReadonlyArray, Array.prototype.toLocaleString() returns a comma-joined string (e.g. "12,345" for [12, 345]), which would be visually indistinguishable from a plain number but semantically incorrect.

Range/area-band chart configurations can surface array values in the payload. Consider narrowing the display branch:

Suggested change
{item.value !== undefined && item.value !== null && (
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
{item.value !== undefined && item.value !== null && !Array.isArray(item.value) && (
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/ui/chart.tsx
Line: 255-259

Comment:
**`toLocaleString()` called on a potentially array-typed value**

`item.value` is now typed as `ChartTooltipValue = number | string | ReadonlyArray<number | string>`. When `item.value` is a `ReadonlyArray`, `Array.prototype.toLocaleString()` returns a comma-joined string (e.g. `"12,345"` for `[12, 345]`), which would be visually indistinguishable from a plain number but semantically incorrect.

Range/area-band chart configurations can surface array values in the payload. Consider narrowing the display branch:

```suggestion
                      {item.value !== undefined && item.value !== null && !Array.isArray(item.value) && (
                        <span className="text-foreground font-mono font-medium tabular-nums">
                          {item.value.toLocaleString()}
                        </span>
                      )}
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +33 to +42
function normalizeTooltipKey(
value: TooltipPayloadEntry["dataKey"] | string | undefined,
fallback: string
) {
if (typeof value === "string" || typeof value === "number") {
return String(value);
}

return fallback;
}
Copy link

Choose a reason for hiding this comment

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

Duplicate helper – consider extracting to a shared utility

normalizeTooltipKey here is functionally identical to normalizePayloadKey introduced in src/components/ui/chart.tsx in this same PR. Having two copies means any future edge-case fix must be applied twice.

A small shared helper (e.g. in src/lib/utils/chart.ts) would eliminate the drift risk. Alternatively, normalizePayloadKey could be exported from chart.tsx and imported here.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/app/[locale]/dashboard/availability/_components/provider/latency-chart.tsx
Line: 33-42

Comment:
**Duplicate helper – consider extracting to a shared utility**

`normalizeTooltipKey` here is functionally identical to `normalizePayloadKey` introduced in `src/components/ui/chart.tsx` in this same PR. Having two copies means any future edge-case fix must be applied twice.

A small shared helper (e.g. in `src/lib/utils/chart.ts`) would eliminate the drift risk. Alternatively, `normalizePayloadKey` could be exported from `chart.tsx` and imported here.

How can I resolve this? If you propose a fix, please make it concise.

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

♻️ Duplicate comments (2)
src/components/ui/chart.tsx (2)

156-156: ⚠️ Potential issue | 🟡 Minor

建议使用 ?? 替代 || 以支持合法的 falsy 值

labelKey || item?.dataKey || item?.name 使用逻辑或运算符会跳过合法的 falsy 值(如数字 0 或空字符串 "")。由于 normalizePayloadKey 明确支持 number 类型,应使用 nullish coalescing ?? 仅在 null/undefined 时回退。

建议修改
-    const key = normalizePayloadKey(labelKey || item?.dataKey || item?.name, "value");
+    const key = normalizePayloadKey(labelKey ?? item?.dataKey ?? item?.name, "value");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/chart.tsx` at line 156, The expression using logical OR in
the key computation can incorrectly skip valid falsy values; replace the
fallback chain `labelKey || item?.dataKey || item?.name` with nullish coalescing
so `normalizePayloadKey` receives 0 or "" when valid — update the assignment
that produces `key` (the call to normalizePayloadKey) to use `labelKey ??
item?.dataKey ?? item?.name` ensuring only null/undefined trigger the next
fallback.

193-199: ⚠️ Potential issue | 🟡 Minor

建议 Line 195 同样使用 ?? 替代 ||

与 Line 156 相同的问题,nameKey || item.name || item.dataKey 会跳过 falsy 但合法的值。

建议修改
-            const key = normalizePayloadKey(nameKey || item.name || item.dataKey, "value");
+            const key = normalizePayloadKey(nameKey ?? item.name ?? item.dataKey, "value");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/chart.tsx` around lines 193 - 199, Replace the
nullish-handling that uses logical OR with nullish coalescing in the tooltip
payload mapping: in the expression that builds key (currently using nameKey ||
item.name || item.dataKey) switch to using ?? to avoid skipping valid falsy
values; also update any similar uses in this block (e.g., where item.name ||
item.dataKey is used to build itemName) so normalizePayloadKey receives the
first non-null/undefined value; locate these in the map callback that calls
normalizePayloadKey, getPayloadConfigFromPayload, and assigns itemKey/itemName.
🧹 Nitpick comments (1)
src/components/ui/chart.tsx (1)

209-216: formatter 调用前的前置条件检查可以更宽松

当前仅在 item.name !== undefined 时才调用 formatter,但某些场景下 payload 项可能没有 name 属性但有 dataKey。考虑是否需要放宽条件或使用 itemName(已通过 normalizePayloadKey 处理过的值)作为判断依据。

可选优化
-                {tooltipFormatter && item?.value !== undefined && item.name !== undefined ? (
+                {tooltipFormatter && item?.value !== undefined ? (
                   tooltipFormatter(
                     item.value,
                     itemName,
                     item,
                     index,
                     payload as ReadonlyArray<TooltipPayloadEntry>
                   )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/chart.tsx` around lines 209 - 216, The current conditional
only calls tooltipFormatter when item?.value !== undefined and item.name !==
undefined, which prevents formatting for payload entries that lack name but have
a dataKey or normalized key; update the check in the render branch that calls
tooltipFormatter (where tooltipFormatter, item, itemName and TooltipPayloadEntry
are used) to allow calling the formatter when itemName (the result from
normalizePayloadKey) is truthy or when item.dataKey is present, i.e. replace the
strict item.name check with a check that uses itemName || item.dataKey so the
formatter is invoked for entries that have a usable identifier even if item.name
is undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/ui/chart.tsx`:
- Line 181: The cast to TooltipFormatter masks Recharts v3's Formatter which can
return a tuple; update the TooltipFormatter type to return "[React.ReactNode,
string] | React.ReactNode" (or union with the original TName) and then handle
the tuple when using tooltipFormatter in the render path (where tooltipFormatter
is invoked) by checking if the result is an array and extracting the display
value (first element) or label (second element) before embedding in JSX; change
the declaration "const tooltipFormatter = formatter as TooltipFormatter |
undefined" to reflect the updated type and adjust the rendering logic that
consumes tooltipFormatter to safely handle both tuple and single-node returns.

---

Duplicate comments:
In `@src/components/ui/chart.tsx`:
- Line 156: The expression using logical OR in the key computation can
incorrectly skip valid falsy values; replace the fallback chain `labelKey ||
item?.dataKey || item?.name` with nullish coalescing so `normalizePayloadKey`
receives 0 or "" when valid — update the assignment that produces `key` (the
call to normalizePayloadKey) to use `labelKey ?? item?.dataKey ?? item?.name`
ensuring only null/undefined trigger the next fallback.
- Around line 193-199: Replace the nullish-handling that uses logical OR with
nullish coalescing in the tooltip payload mapping: in the expression that builds
key (currently using nameKey || item.name || item.dataKey) switch to using ?? to
avoid skipping valid falsy values; also update any similar uses in this block
(e.g., where item.name || item.dataKey is used to build itemName) so
normalizePayloadKey receives the first non-null/undefined value; locate these in
the map callback that calls normalizePayloadKey, getPayloadConfigFromPayload,
and assigns itemKey/itemName.

---

Nitpick comments:
In `@src/components/ui/chart.tsx`:
- Around line 209-216: The current conditional only calls tooltipFormatter when
item?.value !== undefined and item.name !== undefined, which prevents formatting
for payload entries that lack name but have a dataKey or normalized key; update
the check in the render branch that calls tooltipFormatter (where
tooltipFormatter, item, itemName and TooltipPayloadEntry are used) to allow
calling the formatter when itemName (the result from normalizePayloadKey) is
truthy or when item.dataKey is present, i.e. replace the strict item.name check
with a check that uses itemName || item.dataKey so the formatter is invoked for
entries that have a usable identifier even if item.name is undefined.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce8a927a-bcb6-4e8a-b940-ca89fcb3dee7

📥 Commits

Reviewing files that changed from the base of the PR and between 292166e and 825a444.

📒 Files selected for processing (1)
  • src/components/ui/chart.tsx

}

const nestLabel = payload.length === 1 && indicator !== "dot";
const tooltipFormatter = formatter as TooltipFormatter | undefined;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Recharts v3 TooltipContentProps formatter signature

💡 Result:

In Recharts v3, TooltipContentProps extends TooltipProps, and the formatter prop comes from DefaultTooltipContentProps as Formatter<TValue, TName>. Its TypeScript signature is:

export type Formatter<TValue extends ValueType, TName extends NameType> = (
  value: TValue | undefined,
  name: TName | undefined,
  item: Payload<TValue, TName>,
  index: number,
  payload: ReadonlyArray<Payload<TValue, TName>>
) => [React.ReactNode, TName] | React.ReactNode;

Source: Recharts v3 type definitions for DefaultTooltipContent / Formatter and TooltipContentProps / TooltipProps. (app.unpkg.com)

Citations:


🏁 Script executed:

# First, let's find and examine the chart.tsx file around line 181
wc -l src/components/ui/chart.tsx

Repository: ding113/claude-code-hub

Length of output: 98


🏁 Script executed:

# Read the area around line 181 to see the context
sed -n '170,190p' src/components/ui/chart.tsx

Repository: ding113/claude-code-hub

Length of output: 695


🏁 Script executed:

# Search for TooltipFormatter type definition in the file
rg "type TooltipFormatter" src/components/ui/chart.tsx -A 5

Repository: ding113/claude-code-hub

Length of output: 240


🏁 Script executed:

# Also check for interface TooltipFormatter definition
rg "interface TooltipFormatter" src/components/ui/chart.tsx -A 5

Repository: ding113/claude-code-hub

Length of output: 49


🏁 Script executed:

# Search in the entire src directory for TooltipFormatter
rg "TooltipFormatter" src/ -B 2 -A 2

Repository: ding113/claude-code-hub

Length of output: 650


🏁 Script executed:

# Get the complete TooltipFormatter type definition
sed -n '1,363p' src/components/ui/chart.tsx | grep -A 10 "type TooltipFormatter"

Repository: ding113/claude-code-hub

Length of output: 426


🏁 Script executed:

# Also check for ChartTooltipValue and TooltipPayloadEntry types
rg "type ChartTooltipValue|interface ChartTooltipValue" src/components/ui/chart.tsx -A 2

Repository: ding113/claude-code-hub

Length of output: 241


🏁 Script executed:

# Check TooltipPayloadEntry definition
rg "type TooltipPayloadEntry|interface TooltipPayloadEntry" src/components/ui/chart.tsx -A 3

Repository: ding113/claude-code-hub

Length of output: 203


🏁 Script executed:

# Get the full context of where formatter comes from (the function parameters)
sed -n '150,175p' src/components/ui/chart.tsx

Repository: ding113/claude-code-hub

Length of output: 882


🏁 Script executed:

# Check how tooltipFormatter is used after line 181
sed -n '181,250p' src/components/ui/chart.tsx

Repository: ding113/claude-code-hub

Length of output: 3095


🏁 Script executed:

# Also check the function signature to see where formatter comes from
sed -n '120,160p' src/components/ui/chart.tsx

Repository: ding113/claude-code-hub

Length of output: 1034


修复 TooltipFormatter 的返回类型以与 Recharts v3 兼容

Recharts v3 的 Formatter 类型返回值为 [React.ReactNode, TName] | React.ReactNode(可以返回元组或单个节点),但此处的自定义 TooltipFormatter 类型仅声明返回 React.ReactNode。此类型转换会掩盖不兼容性,当 Recharts 实际返回元组时,直接在 JSX 中渲染(第 197-202 行)会导致运行时错误。需要修改 TooltipFormatter 的返回类型为 [React.ReactNode, string] | React.ReactNode 或在使用时处理元组情况。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/chart.tsx` at line 181, The cast to TooltipFormatter masks
Recharts v3's Formatter which can return a tuple; update the TooltipFormatter
type to return "[React.ReactNode, string] | React.ReactNode" (or union with the
original TName) and then handle the tuple when using tooltipFormatter in the
render path (where tooltipFormatter is invoked) by checking if the result is an
array and extracting the display value (first element) or label (second element)
before embedding in JSX; change the declaration "const tooltipFormatter =
formatter as TooltipFormatter | undefined" to reflect the updated type and
adjust the rendering logic that consumes tooltipFormatter to safely handle both
tuple and single-node returns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:i18n area:UI bug Something isn't working size/M Medium PR (< 500 lines)

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant