From 1e9e6d434922e4b910cbb914eccffb854e76e06a Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Sat, 25 Apr 2026 22:45:08 -0300 Subject: [PATCH] fix(dashboard): stabilize usage tab loading and refresh behavior Prevent repeated provider-limit refresh requests by guarding the bulk refresh flow with a ref-backed lock instead of a stale callback dependency. Also avoid tying eval data loading to translation updates and replace the fetch failure path with a static error so the effect runs predictably. Refresh English cost dashboard copy to provide clearer labels and empty state messaging. --- .../dashboard/usage/components/EvalsTab.tsx | 5 ++-- .../usage/components/ProviderLimits/index.tsx | 7 ++++-- src/i18n/messages/en.json | 24 ++++++++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx b/src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx index 22c195d2d3..b83341e721 100644 --- a/src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx +++ b/src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx @@ -353,7 +353,7 @@ export default function EvalsTab() { try { const response = await fetch("/api/evals"); if (!response.ok) { - throw new Error(t("notifyEvalRunFailed")); + throw new Error("Eval load failed"); } const payload = (await response.json()) as EvalsDashboardPayload; @@ -380,7 +380,8 @@ export default function EvalsTab() { return () => { isMounted = false; }; - }, [notify, t]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); useEffect(() => { if (targetOptions.length === 0) return; diff --git a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx index 095d67c4df..389f21fbe8 100644 --- a/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx +++ b/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx @@ -238,8 +238,10 @@ export default function ProviderLimits() { [fetchQuota] ); + const refreshingAllRef = useRef(false); const refreshAll = useCallback(async () => { - if (refreshingAll) return; + if (refreshingAllRef.current) return; + refreshingAllRef.current = true; setRefreshingAll(true); try { const response = await fetch("/api/usage/provider-limits", { method: "POST" }); @@ -256,9 +258,10 @@ export default function ProviderLimits() { } catch (error) { console.error("Error refreshing all:", error); } finally { + refreshingAllRef.current = false; setRefreshingAll(false); } - }, [refreshingAll, applyCachedQuotaState, fetchConnections]); + }, [applyCachedQuotaState, fetchConnections]); useEffect(() => { const init = async () => { diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index b055578f0d..4286b53820 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1784,29 +1784,35 @@ }, "costs": { "title": "Costs", + "pageDescription": "Track spending, analyze trends, and manage your AI budget across all providers", + "overview": "Overview", "budget": "Budget", "totalCost": "Total Cost", "breakdown": "Cost Breakdown", "noData": "No cost data", "byModel": "By Model", "byProvider": "By Provider", - "spend30d": "Spend30D", + "range7d": "7 Days", + "range30d": "30 Days", + "range90d": "90 Days", + "rangeAll": "All Time", + "spend30d": "Spend 30D", "activeModels": "Active Models", "selectedWindow": "Selected Window", "activeProviders": "Active Providers", - "overviewTitle": "Overview Title", - "spend7d": "Spend7D", - "avgCostPerRequest": "Avg Cost Per Request", - "noCostDataDescription": "No Cost Data Description", + "overviewTitle": "Cost Overview", + "spend7d": "Spend 7D", + "avgCostPerRequest": "Avg Cost / Request", + "noCostDataDescription": "Start making requests to see cost data appear here. Costs are tracked automatically for all providers.", "spendToday": "Spend Today", - "overviewLoadFailed": "Overview Load Failed", - "overviewDescription": "Overview Description", + "overviewLoadFailed": "Failed to load cost overview", + "overviewDescription": "Real-time spending breakdown across all connected providers and models", "providerShare": "Provider Share", "topProviders": "Top Providers", "costTrend": "Cost Trend", - "noCostDataTitle": "No Cost Data Title", + "noCostDataTitle": "No cost data yet", "topModels": "Top Models", - "requestsInWindow": "Requests In Window" + "requestsInWindow": "Requests in Window" }, "endpoint": { "title": "API Endpoint",