diff --git a/src/components/usage/hooks/useUsageData.ts b/src/components/usage/hooks/useUsageData.ts index 82bf526..a51b712 100644 --- a/src/components/usage/hooks/useUsageData.ts +++ b/src/components/usage/hooks/useUsageData.ts @@ -17,6 +17,7 @@ export interface UseUsageDataReturn { usage: UsagePayload | null; loading: boolean; error: string; + lastRefreshedAt: Date | null; modelPrices: Record; setModelPrices: (prices: Record) => void; loadUsage: () => Promise; @@ -38,6 +39,7 @@ export function useUsageData(): UseUsageDataReturn { const [modelPrices, setModelPrices] = useState>({}); const [exporting, setExporting] = useState(false); const [importing, setImporting] = useState(false); + const [lastRefreshedAt, setLastRefreshedAt] = useState(null); const importInputRef = useRef(null); const loadUsage = useCallback(async () => { @@ -47,6 +49,7 @@ export function useUsageData(): UseUsageDataReturn { const data = await usageApi.getUsage(); const payload = (data?.usage ?? data) as unknown; setUsage(payload && typeof payload === 'object' ? (payload as UsagePayload) : null); + setLastRefreshedAt(new Date()); } catch (err: unknown) { const message = err instanceof Error ? err.message : t('usage_stats.loading_error'); setError(message); @@ -140,6 +143,7 @@ export function useUsageData(): UseUsageDataReturn { usage, loading, error, + lastRefreshedAt, modelPrices, setModelPrices: handleSetModelPrices, loadUsage, diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 8f7f1a2..25372be 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -817,7 +817,8 @@ "credential_name": "Credential", "token_breakdown": "Token Type Breakdown", "input_tokens": "Input Tokens", - "output_tokens": "Output Tokens" + "output_tokens": "Output Tokens", + "last_updated": "Updated" }, "stats": { "success": "Success", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 9bd041e..3de775f 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -820,7 +820,8 @@ "credential_name": "Учётные данные", "token_breakdown": "Распределение типов токенов", "input_tokens": "Входные токены", - "output_tokens": "Выходные токены" + "output_tokens": "Выходные токены", + "last_updated": "Обновлено" }, "stats": { "success": "Успех", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index d7eafe3..208c6cb 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -817,7 +817,8 @@ "credential_name": "凭证", "token_breakdown": "Token 类型分布", "input_tokens": "输入 Tokens", - "output_tokens": "输出 Tokens" + "output_tokens": "输出 Tokens", + "last_updated": "更新于" }, "stats": { "success": "成功", diff --git a/src/pages/UsagePage.module.scss b/src/pages/UsagePage.module.scss index 462ad8e..35254ad 100644 --- a/src/pages/UsagePage.module.scss +++ b/src/pages/UsagePage.module.scss @@ -25,6 +25,12 @@ flex-wrap: wrap; } +.lastRefreshed { + font-size: 11px; + color: var(--text-tertiary); + white-space: nowrap; +} + .timeRangeGroup { display: inline-flex; align-items: center; diff --git a/src/pages/UsagePage.tsx b/src/pages/UsagePage.tsx index 6814ce3..7bb7924 100644 --- a/src/pages/UsagePage.tsx +++ b/src/pages/UsagePage.tsx @@ -137,6 +137,7 @@ export function UsagePage() { usage, loading, error, + lastRefreshedAt, modelPrices, setModelPrices, loadUsage, @@ -308,6 +309,11 @@ export function UsagePage() { style={{ display: 'none' }} onChange={handleImportChange} /> + {lastRefreshedAt && ( + + {t('usage_stats.last_updated')}: {lastRefreshedAt.toLocaleTimeString()} + + )}