From 5183cf2bfe15b7064d144ebaf4a47a3da871a2ff Mon Sep 17 00:00:00 2001 From: lzt404 <2596933790@qq.com> Date: Tue, 6 Oct 2026 13:27:45 +0800 Subject: [PATCH] style(home): color the success-rate meter by rate The home overview bar stayed brown down to 80%. Color it continuously from red through yellow to green so it follows the measured success rate. --- src/pages/HomeDashboard.css | 2 +- src/pages/HomeOverviewCards.tsx | 8 +++++--- tests/homeOverviewCards.test.tsx | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 tests/homeOverviewCards.test.tsx diff --git a/src/pages/HomeDashboard.css b/src/pages/HomeDashboard.css index e997747..0a3a507 100644 --- a/src/pages/HomeDashboard.css +++ b/src/pages/HomeDashboard.css @@ -283,7 +283,7 @@ .home-stat-card h3 { margin: 0; color: var(--text-secondary); font-size: 12px; font-weight: 500; line-height: 1.5; } .home-stat-value { display: block; color: var(--text-primary); font-family: var(--font-mono); font-size: 28px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.15; letter-spacing: -.03em; } .home-stat-track { height: 5px; margin: 2px 0; overflow: hidden; border-radius: 3px; background: color-mix(in srgb, var(--stat-color) 13%, transparent); } -.home-stat-track > span { display: block; height: 100%; border-radius: inherit; background: var(--stat-color); } +.home-stat-track > span { display: block; height: 100%; border-radius: inherit; background: var(--stat-color); transition: width .25s ease, background-color .25s ease; } .home-stat-card p { margin: 0; color: var(--text-tertiary); font-size: 11px; line-height: 1.6; overflow-wrap: anywhere; } /* Use the desktop workspace height; smaller windows retain natural scrolling. */ diff --git a/src/pages/HomeOverviewCards.tsx b/src/pages/HomeOverviewCards.tsx index e7c1139..e263187 100644 --- a/src/pages/HomeOverviewCards.tsx +++ b/src/pages/HomeOverviewCards.tsx @@ -1,6 +1,7 @@ -import type { ReactNode } from 'react'; +import type { CSSProperties, ReactNode } from 'react'; import { RefreshCw } from 'lucide-react'; import { useI18n } from '../i18n'; +import { requestRateColor } from '../services/authFileRequests'; import type { HomeOverviewSnapshot } from '../services/homeOverview'; export function HomeOverviewCards({ snapshot, loading, coreReady, onRefresh, actions }: { @@ -20,10 +21,11 @@ export function HomeOverviewCards({ snapshot, loading, coreReady, onRefresh, act id: 'usage', label: t('home.overview.successRate'), value: rate == null ? '—' : `${formatNumber(rate, { maximumFractionDigits: 1 })}%`, description: usage ? t(usage.totalRequests ? 'home.overview.requests' : 'home.overview.noRequests', { count: formatNumber(usage.totalRequests) }) : unavailable(false), - tone: rate == null ? 'neutral' : rate >= 95 ? 'success' : rate >= 80 ? 'warning' : 'error', + tone: 'neutral', error: snapshot?.errors.usage, percent: rate ?? null, meterLabel: t('home.overview.successRate'), + meterColor: rate == null ? undefined : requestRateColor(rate / 100), }, { id: 'credentials', label: t('home.overview.credentials'), @@ -56,7 +58,7 @@ export function HomeOverviewCards({ snapshot, loading, coreReady, onRefresh, act
{actions}
- {cards.map((card) =>
+ {cards.map((card) =>

{card.label}

{card.value} {'percent' in card &&
({ + usage: { + totalRequests: rate == null ? 0 : 100, + successCount: rate ?? 0, + failureCount: rate == null ? 0 : 100 - rate, + canceledCount: 0, + successRate: rate, + }, + credentials: null, + providerKeys: null, + models: null, + errors: {}, +}); + +const render = (rate: number | null) => renderToStaticMarkup( + + {}} /> + , +); + +it('colors the success meter continuously from red through yellow to green', () => { + expect(render(100)).toContain(`--stat-color:${requestRateColor(1)}`); + expect(render(50)).toContain(`--stat-color:${requestRateColor(0.5)}`); + expect(render(0)).toContain(`--stat-color:${requestRateColor(0)}`); + expect(render(95)).not.toContain('home-stat-card warning'); + expect(render(null)).not.toContain('--stat-color'); +});