Skip to content

feat(logs): overhaul stats bar with i18n, clickable filters, and auto… - #6465

Open
Tsuki-wz wants to merge 1 commit into
QuantumNous:mainfrom
Tsuki-wz:main
Open

feat(logs): overhaul stats bar with i18n, clickable filters, and auto…#6465
Tsuki-wz wants to merge 1 commit into
QuantumNous:mainfrom
Tsuki-wz:main

Conversation

@Tsuki-wz

@Tsuki-wz Tsuki-wz commented Jul 24, 2026

Copy link
Copy Markdown

📝 Description

1. Fix Claude extended-thinking requests being cut off mid-stream
Added IsThinking to RelayInfo, set when the request carries a
Thinking parameter. The SSE idle timeout in stream_scanner.go now
branches on this flag: regular requests keep STREAMING_TIMEOUT
(default 300 s), thinking requests use a new THINKING_STREAMING_TIMEOUT
env var (default 900 s). The upstream produces no SSE chunks during the
thinking phase by design, so the old fixed 300 s timeout incorrectly
treated silence as a stall and dropped the connection.

2. Always record client IP on consume logs
Removed the per-user RecordIpLog gate. All consume logs now write
c.ClientIP() unconditionally so the IP column is always visible to
admins.

3. Fix log stats returning all-zeros on SQLite / PostgreSQL
The stats query used CAST(... AS SIGNED), which is MySQL-only syntax.
SQLite and PostgreSQL reject it, causing the entire stats fetch to fail
silently and fall back to the zero default. Fixed by branching on
UsingLogDatabase: MySQL keeps SIGNED, all others use INTEGER.

4. Clickable stat badges and auto-refresh on the stats bar

  • Clicking Today Req / Today RPM / Today TPM jumps the time range to
    today (00:00 – now).
  • Clicking Errors applies an Error-type filter.
  • A cycle button toggles auto-refresh through Off → 30 s → 60 s → 5 m,
    with a spinner while fetching.

5. i18n for new stats bar labels
Added translations for all new keys (stat labels, tooltips, auto-refresh
text) across seven locales: zh, zh-TW, en, ja, ru, fr, vi.

🚀 Type of change

  • Bug fix
  • New feature

🔗 Related Issue

  • Closes # (none)

✅ Checklist

  • I have written this description myself and have not pasted unedited AI output.
  • No duplicate issues or PRs found.
  • I understand how each change works and its potential impact.
  • All changes are directly related to this task.
  • Backend compiles clean (go build); frontend passes type-check (bunx tsc --noEmit); all locale JSON files are valid.
  • No credentials exposed; changes follow project conventions.

📸 Proof of Work

(Please attach a screenshot of the stats bar showing correct values,
clickable badge navigation, and the auto-refresh button in its active state.)
image
image

Summary by CodeRabbit

  • New Features
    • Added IP address filtering and display for usage logs, with privacy masking support.
    • Expanded usage statistics with request, token, latency, and error metrics.
    • Added clickable statistics for navigating to related logs.
    • Added configurable auto-refresh for usage statistics.
    • Added longer streaming timeouts for thinking-enabled requests.
    • Added translations for the new analytics and refresh controls.

…-refresh

- Fix SSE idle timeout for Claude extended-thinking requests by adding
  IsThinking to RelayInfo and a THINKING_STREAMING_TIMEOUT env var
  (default 900s)
- Always record client IP on consume logs; remove per-user RecordIpLog
  guard
- Fix log stats query failing on SQLite/PostgreSQL by replacing
  CAST(... AS SIGNED) with dialect-aware CAST(... AS INTEGER)
- Today Req/RPM/TPM badges navigate to today's time range on click;
  Errors badge filters to error-type logs on click
- Add auto-refresh cycle button (off → 30s → 60s → 5m) with spinner
- Add stats bar and auto-refresh i18n keys for zh, zh-TW, en, ja, ru,
  fr, vi
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change adds thinking-aware streaming timeout configuration and extends usage logs with IP capture, filtering, aggregate statistics, interactive metrics, auto-refresh, and localized labels.

Changes

Thinking-aware streaming timeout

Layer / File(s) Summary
Thinking state and timeout selection
constant/env.go, common/init.go, relay/common/relay_info.go, relay/claude_handler.go, relay/helper/stream_scanner.go
Thinking requests set relay state, and streams can use THINKING_STREAMING_TIMEOUT, defaulting to 900 seconds.

Usage log filtering and analytics

Layer / File(s) Summary
IP capture and statistics API
model/log.go, controller/log.go
Consume logs persist client IPs; log and statistics endpoints accept IP filters and return expanded aggregates.
Usage-log query and statistics contracts
web/src/features/usage-logs/types.ts, web/src/features/usage-logs/constants.ts, web/src/features/usage-logs/lib/*, web/src/routes/_authenticated/usage-logs/$section.tsx
Route validation, filter serialization, API parameters, default values, and statistics types support IP filtering and new metrics.
Usage-log filtering and analytics controls
web/src/features/usage-logs/components/common-logs-filter-bar.tsx, web/src/features/usage-logs/components/columns/common-logs-columns.tsx, web/src/features/usage-logs/components/common-logs-stats.tsx
The interface adds IP filtering and masking, expanded metric badges, navigation actions, and configurable auto-refresh.
Usage analytics translations
web/src/i18n/locales/*
Locale files add labels for statistics and auto-refresh controls.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ClaudeHelper
  participant RelayInfo
  participant StreamScannerHandler
  ClaudeHelper->>RelayInfo: set IsThinking=true
  RelayInfo->>StreamScannerHandler: provide thinking state
  StreamScannerHandler->>StreamScannerHandler: select thinking timeout
Loading
sequenceDiagram
  participant UsageLogsClient
  participant LogController
  participant LogModel
  participant LogsDatabase
  UsageLogsClient->>LogController: request logs or statistics with ip
  LogController->>LogModel: pass IP and query filters
  LogModel->>LogsDatabase: filter and aggregate logs
  LogsDatabase-->>LogModel: logs and statistics
  LogModel-->>LogController: return results
  LogController-->>UsageLogsClient: return data
Loading

Poem

I’m a rabbit with metrics to show,
IPs in neat columns, all masked in a row.
Thinking streams linger, timers grow bright,
Fresh stats hop in with each refresh of light.
Nibble, click, and analytics take flight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change set: usage-log stats bar updates with i18n, clickable filters, and auto-refresh.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/features/usage-logs/components/common-logs-filter-bar.tsx (1)

90-104: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

IP filter isn't wired into searchState/sourceKey/active-filter counts.

ip was added to CommonLogFilters and rendered in the UI (Line 413), but the state plumbing that hydrates it from the URL was missed:

  • buildSearchSourceKey's hash array (Lines 93-104) never includes values.ip despite the type accepting it (Line 90).
  • sourceValues (Lines 126-137) and the filters object (Lines 138-150) never read searchParams.ip.
  • The useMemo deps (Lines 156-167) don't include searchParams.ip.
  • hasExpandedFilters/expandedFilterCount (Lines 237-254) don't check filters.ip.

Net effect: after a fresh mount or page reload with ?ip=... in the URL, the IP input renders empty and the "active filters" badge undercounts, even though the backend request is still filtered by IP.

🐛 Proposed fix
   const sourceValues = {
     startTime: searchParams.startTime,
     endTime: searchParams.endTime,
     channel: searchParams.channel,
     model: searchParams.model,
     token: searchParams.token,
     group: searchParams.group,
     username: searchParams.username,
     requestId: searchParams.requestId,
     upstreamRequestId: searchParams.upstreamRequestId,
+    ip: searchParams.ip,
     type: searchParams.type,
   }
   const filters: CommonLogFilters = {
     ...
     upstreamRequestId: searchParams.upstreamRequestId || undefined,
+    ip: searchParams.ip || undefined,
   }
   ...
   }, [
     searchParams.startTime,
     ...
     searchParams.upstreamRequestId,
+    searchParams.ip,
     searchParams.type,
   ])

   function buildSearchSourceKey(values: { ... }) {
     return [
       ...
       values.upstreamRequestId,
+      values.ip,
       Array.isArray(values.type) ? values.type.join(',') : values.type,
     ]
       .map((value) => String(value ?? ''))
       .join('\u001f')
   }

   const hasExpandedFilters =
     !!filters.token ||
     !!filters.username ||
     !!filters.channel ||
     !!filters.requestId ||
-    !!filters.upstreamRequestId
+    !!filters.upstreamRequestId ||
+    !!filters.ip

   const expandedFilterCount = [
     filters.token,
     isAdmin ? filters.username : undefined,
     isAdmin ? filters.channel : undefined,
     filters.requestId,
     filters.upstreamRequestId,
+    filters.ip,
   ].filter(Boolean).length

Also applies to: 126-150, 156-167, 237-254

🤖 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/features/usage-logs/components/common-logs-filter-bar.tsx` around
lines 90 - 104, Wire the IP filter through the common log filter state: include
values.ip in buildSearchSourceKey, read searchParams.ip into sourceValues and
the filters object, and add searchParams.ip to the related useMemo dependencies.
Update hasExpandedFilters and expandedFilterCount to treat filters.ip as an
active expanded filter so URL hydration, source keys, and counts remain
consistent.
🧹 Nitpick comments (1)
model/log.go (1)

646-741: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Four sequential round-trips per stats request.

SumUsedQuota now issues four separate queries (quota, realtime rpm/tpm, range aggregate, today aggregate) against LOG_DB in sequence. With the new auto-refresh feature (30s/60s/5m) hitting this endpoint repeatedly, consider combining these into fewer round trips (e.g., a single query with multiple CASE-based aggregates, or UNION ALL subqueries) to reduce load, especially on the log database.

🤖 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 `@model/log.go` around lines 646 - 741, Reduce the four sequential LOG_DB
queries in SumUsedQuota to fewer round trips by combining the quota, realtime
rpm/tpm, range aggregate, and today aggregate calculations into a consolidated
query or equivalent UNION ALL approach. Preserve all existing filters,
time-window semantics, metric values, database-specific token casting, and error
behavior while continuing to populate Stat.
🤖 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.

Inline comments:
In `@common/init.go`:
- Line 178: Update the initialization of constant.ThinkingStreamingTimeout in
common/init.go to validate or clamp the parsed THINKING_STREAMING_TIMEOUT value
before publishing it, using a safe upper bound that prevents overflow or
unexpected normalization when relay/helper/stream_scanner.go passes it to
time.NewTicker. Preserve the existing default behavior for valid values.

In `@web/src/i18n/locales/en.json`:
- Around line 5217-5236: Remove the later duplicate "Auto refresh" entry from
the locale object in en.json, preserving the earlier existing definition and all
neighboring translation keys.

In `@web/src/i18n/locales/fr.json`:
- Around line 5217-5236: Remove the duplicate "Auto refresh" entry from the
locale additions and reuse the existing key/value earlier in fr.json; if the
shorter wording is required, update that single existing translation instead of
declaring the key again.

In `@web/src/i18n/locales/vi.json`:
- Line 5235: Remove the duplicate "Auto refresh" entry from the locale object,
keeping the existing definition near the earlier occurrence and leaving all
other translations unchanged.
- Around line 5220-5222: Update the Vietnamese locale entries for “Range RPM”
and “Range TPM” to use the natural translations “RPM trong khoảng” and “TPM
trong khoảng”, while leaving “Today RPM” unchanged.

In `@web/src/i18n/locales/zh-TW.json`:
- Line 5235: Remove the duplicate "Auto refresh" entry near the later locale
section in zh-TW.json, and update the existing earlier "Auto refresh" entry if
its translation needs changing. Ensure the JSON contains exactly one key with
the intended translation.

---

Outside diff comments:
In `@web/src/features/usage-logs/components/common-logs-filter-bar.tsx`:
- Around line 90-104: Wire the IP filter through the common log filter state:
include values.ip in buildSearchSourceKey, read searchParams.ip into
sourceValues and the filters object, and add searchParams.ip to the related
useMemo dependencies. Update hasExpandedFilters and expandedFilterCount to treat
filters.ip as an active expanded filter so URL hydration, source keys, and
counts remain consistent.

---

Nitpick comments:
In `@model/log.go`:
- Around line 646-741: Reduce the four sequential LOG_DB queries in SumUsedQuota
to fewer round trips by combining the quota, realtime rpm/tpm, range aggregate,
and today aggregate calculations into a consolidated query or equivalent UNION
ALL approach. Preserve all existing filters, time-window semantics, metric
values, database-specific token casting, and error behavior while continuing to
populate Stat.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 71022455-182d-48ca-b474-d5337a945992

📥 Commits

Reviewing files that changed from the base of the PR and between 84a79b6 and 7179a81.

📒 Files selected for processing (22)
  • common/init.go
  • constant/env.go
  • controller/log.go
  • model/log.go
  • relay/claude_handler.go
  • relay/common/relay_info.go
  • relay/helper/stream_scanner.go
  • web/src/features/usage-logs/components/columns/common-logs-columns.tsx
  • web/src/features/usage-logs/components/common-logs-filter-bar.tsx
  • web/src/features/usage-logs/components/common-logs-stats.tsx
  • web/src/features/usage-logs/constants.ts
  • web/src/features/usage-logs/lib/filter.ts
  • web/src/features/usage-logs/lib/utils.ts
  • web/src/features/usage-logs/types.ts
  • web/src/i18n/locales/en.json
  • web/src/i18n/locales/fr.json
  • web/src/i18n/locales/ja.json
  • web/src/i18n/locales/ru.json
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/zh-TW.json
  • web/src/i18n/locales/zh.json
  • web/src/routes/_authenticated/usage-logs/$section.tsx

Comment thread common/init.go

func initConstantEnv() {
constant.StreamingTimeout = GetEnvOrDefault("STREAMING_TIMEOUT", 300)
constant.ThinkingStreamingTimeout = GetEnvOrDefault("THINKING_STREAMING_TIMEOUT", 900)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n 'func GetEnvOrDefault|THINKING_STREAMING_TIMEOUT|time\.Duration\(.*time\.Second|time\.NewTicker' \
  common constant relay

Repository: QuantumNous/new-api

Length of output: 1985


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== common/env.go =="
cat -n common/env.go

echo
echo "== common/init.go (near init timeout settings) =="
sed -n '90,185p' common/init.go | cat -n

echo
echo "== relay/helper/stream_scanner.go (scanner timeout usage) =="
sed -n '75,105p' relay/helper/stream_scanner.go | cat -n

echo
echo "== constant package definitions/usages =="
rg -n 'var ThinkingStreamingTimeout|ThinkingStreamingTimeout|type Duration|Duration' constant relay helper common | head -n 80

echo
echo "== Go Duration overflow probe =="
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
cat > "$tmpdir/main.go" <<'EOF'
package main

import (
	"fmt"
	"time"
)

func main() {
	values := []int{900, 1<<30, 2147483647, (1 << 31), -1 << 31}
	for _, v := range values {
		d := time.Duration(v) * time.Second
		fmt.Printf("%d -> %d ns\n", v, d)
	}
}
EOF
go run "$tmpdir/main.go"

Repository: QuantumNous/new-api

Length of output: 15491


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package declarations for relay/helper and constant =="
sed -n '1,30p' relay/helper/stream_scanner.go | cat -n
fd -a '.*\.go$' relay/helper constant | while read -r f; do
  echo "--- $f"
  sed -n '1,60p' "$f" | cat -n
done

echo
echo "== Go Duration overflow probe =="
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
cat > "$tmpdir/main.go" <<'EOF'
package main

import (
	"fmt"
	"math"
	"time"
)

func main() {
	values := []int{900, 1 << 30, 2147483647, -1 << 31}
	for _, v := range values {
		d := time.Duration(v) * time.Second
		fmt.Printf("%d -> %d\n", v, d)
	}
	fmt.Printf("MaxDurationSeconds=%d\n", time.Duration(math.MaxInt64/time.Second/2)*time.Second/time.Second)
	panic(time.Duration(2147483647) * time.Second)
}
EOF
go run "$tmpdir/main.go" 2>&1 || true

Repository: QuantumNous/new-api

Length of output: 42741


Bound THINKING_STREAMING_TIMEOUT before publishing it.

common/init.go:178 stores the parsed value directly in constant.ThinkingStreamingTimeout, and relay/helper/stream_scanner.go:97 passes the converted time.Duration to time.NewTicker. Large configured values can overflow or normalize unexpectedly; normalize/reject values above a safe upper bound during initialization.

🤖 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 `@common/init.go` at line 178, Update the initialization of
constant.ThinkingStreamingTimeout in common/init.go to validate or clamp the
parsed THINKING_STREAMING_TIMEOUT value before publishing it, using a safe upper
bound that prevents overflow or unexpected normalization when
relay/helper/stream_scanner.go passes it to time.NewTicker. Preserve the
existing default behavior for valid values.

Comment on lines +5217 to 5236
"Zoom": "Zoom",
"Total Req": "Total Req",
"Today Req": "Today Req",
"Range RPM": "Range RPM",
"Today RPM": "Today RPM",
"Range TPM": "Range TPM",
"Today TPM": "Today TPM",
"Avg Latency": "Avg Latency",
"Errors": "Errors",
"Total consume requests in selected range": "Total consume requests in selected range",
"Consume requests since today 00:00": "Consume requests since today 00:00",
"Average requests per minute over selected range": "Average requests per minute over selected range",
"Average requests per minute since today 00:00": "Average requests per minute since today 00:00",
"Average tokens per minute over selected range": "Average tokens per minute over selected range",
"Average tokens per minute since today 00:00": "Average tokens per minute since today 00:00",
"Average response time for consume requests": "Average response time for consume requests",
"Error log count in selected range": "Error log count in selected range",
"Auto refresh: Off. Click to enable.": "Auto refresh: Off. Click to enable.",
"Auto refresh": "Auto refresh"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Duplicate "Auto refresh" key.

The key "Auto refresh" is already defined earlier in this file (existing entry, unchanged) and is redeclared here with the same value. Harmless in English, but see the companion note on fr.json where the duplicate carries a different value.

🧹 Suggested fix
     "Auto refresh: Off. Click to enable.": "Auto refresh: Off. Click to enable.",
-    "Auto refresh": "Auto refresh"
+    "Auto refresh": "Auto refresh"

Reuse the existing "Auto refresh" key (already present earlier in the file) instead of re-declaring it here; drop this duplicate line entirely.

🤖 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/i18n/locales/en.json` around lines 5217 - 5236, Remove the later
duplicate "Auto refresh" entry from the locale object in en.json, preserving the
earlier existing definition and all neighboring translation keys.

Comment on lines +5217 to 5236
"Zoom": "Zoom",
"Total Req": "Req. totales",
"Today Req": "Req. aujourd'hui",
"Range RPM": "RPM plage",
"Today RPM": "RPM aujourd'hui",
"Range TPM": "TPM plage",
"Today TPM": "TPM aujourd'hui",
"Avg Latency": "Latence moy.",
"Errors": "Erreurs",
"Total consume requests in selected range": "Total des requêtes de consommation sur la plage sélectionnée",
"Consume requests since today 00:00": "Requêtes de consommation depuis 00:00 aujourd'hui",
"Average requests per minute over selected range": "Moyenne des requêtes par minute sur la plage sélectionnée",
"Average requests per minute since today 00:00": "Moyenne des requêtes par minute depuis 00:00 aujourd'hui",
"Average tokens per minute over selected range": "Moyenne des tokens par minute sur la plage sélectionnée",
"Average tokens per minute since today 00:00": "Moyenne des tokens par minute depuis 00:00 aujourd'hui",
"Average response time for consume requests": "Temps de réponse moyen pour les requêtes de consommation",
"Error log count in selected range": "Nombre d'erreurs dans la plage sélectionnée",
"Auto refresh: Off. Click to enable.": "Actualisation auto : désactivée. Cliquez pour activer.",
"Auto refresh": "Actualisation auto"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Duplicate "Auto refresh" key silently overrides the existing translation.

"Auto refresh" already exists earlier in this file as "Actualisation automatique". This diff re-declares the same key at the end of the file with a different value, "Actualisation auto". Because JSON objects can't hold two values for one key, whichever loader parses this (e.g. i18next's JSON backend) will keep only the last occurrence — silently changing the translation for any other feature that already uses the "Auto refresh" key, not just this new stats bar.

🧹 Suggested fix
     "Auto refresh: Off. Click to enable.": "Actualisation auto : désactivée. Cliquez pour activer.",
-    "Auto refresh": "Actualisation auto"
+    "Auto refresh": "Actualisation auto"

Drop this duplicate line and reuse the pre-existing "Auto refresh" key/value (or, if the shorter phrasing is intentional, update the single existing entry instead of adding a second one).

🤖 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/i18n/locales/fr.json` around lines 5217 - 5236, Remove the duplicate
"Auto refresh" entry from the locale additions and reuse the existing key/value
earlier in fr.json; if the shorter wording is required, update that single
existing translation instead of declaring the key again.

Comment on lines +5220 to +5222
"Range RPM": "RPM khoảng",
"Today RPM": "RPM hôm nay",
"Range TPM": "TPM khoảng",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use natural Vietnamese wording for range metrics.

"RPM khoảng" and "TPM khoảng" are unclear. Translate them as "RPM trong khoảng" and "TPM trong khoảng".

🤖 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/i18n/locales/vi.json` around lines 5220 - 5222, Update the Vietnamese
locale entries for “Range RPM” and “Range TPM” to use the natural translations
“RPM trong khoảng” and “TPM trong khoảng”, while leaving “Today RPM” unchanged.

"Average response time for consume requests": "Thời gian phản hồi trung bình cho yêu cầu tiêu thụ",
"Error log count in selected range": "Số lượng lỗi trong khoảng thời gian đã chọn",
"Auto refresh: Off. Click to enable.": "Tự động làm mới: Tắt. Nhấn để bật.",
"Auto refresh": "Tự động làm mới"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the duplicate Auto refresh key.

"Auto refresh" is already defined at Line 506. Keeping a second object key can cause inconsistent parser/tooling behavior and is unnecessary.

🤖 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/i18n/locales/vi.json` at line 5235, Remove the duplicate "Auto
refresh" entry from the locale object, keeping the existing definition near the
earlier occurrence and leaving all other translations unchanged.

"Average response time for consume requests": "消費請求的平均回應時間",
"Error log count in selected range": "所選時間段內的錯誤日誌數",
"Auto refresh: Off. Click to enable.": "自動刷新:關閉,點擊開啟",
"Auto refresh": "自動刷新"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove the duplicate Auto refresh key.

"Auto refresh" already exists at Line 506. This duplicate may fail JSON validation or silently overwrite the earlier translation, while also introducing inconsistent wording. Update the existing entry instead of adding a second one.

🤖 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/i18n/locales/zh-TW.json` at line 5235, Remove the duplicate "Auto
refresh" entry near the later locale section in zh-TW.json, and update the
existing earlier "Auto refresh" entry if its translation needs changing. Ensure
the JSON contains exactly one key with the intended translation.

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.

1 participant