fix: token tracking pipeline + premium usage dashboard redesign

Backend fixes:
- Fix totalTokens defaulting to 0 when API omits totalTokenCount (now computes prompt+completion)
- Fix streaming metadata extraction: unwrap response wrapper in Anthropic/Gemini handlers
- Fix Zod schemas: handle SQL SUM(null) with nullable().transform()
- Add is_estimated column migration to token_usage table

Frontend redesign:
- Rewrite Usage page with area charts (nivo/line), horizontal bar model ranking
- StatCard: add trend indicators (% vs previous period) and inline SVG sparklines
- Premium color palette, prompt/completion ratio bar, top models mini-list
- Live indicator with 15s auto-refresh

Design system migration:
- Standardize all components on Gemini Nexus tokens (rounded-xl, border-white/[0.06])
- Refine UI components, proxy tabs, cloud account list, provider groups
This commit is contained in:
Gemini Nexus Bot committed 2026-04-29 01:43:48 -03:00
1 parent b1c76f3b69
commit a648f2a281
44 files changed
+8920 -14566

No files matched your search

+27 -27
View File
@@ -79,8 +79,8 @@ function SettingsPage() {
return (
<div className="container mx-auto max-w-4xl space-y-5 p-6">
<div>
<h2 className="text-3xl font-bold tracking-tight">{t('settings.title')}</h2>
<p className="text-muted-foreground mt-1">{t('settings.description')}</p>
<h2 className="text-lg font-semibold tracking-tight">{t('settings.title')}</h2>
<p className="text-muted-foreground mt-1 text-[13px]">{t('settings.description')}</p>
</div>
<Tabs defaultValue="general" className="w-full">
@@ -92,16 +92,16 @@ function SettingsPage() {
{/* --- GENERAL TAB --- */}
<TabsContent value="general" className="space-y-5">
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.appearance.title')}</CardTitle>
<CardDescription>{t('settings.appearance.description')}</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<CardContent className="space-y-5">
<div className="flex items-center justify-between space-x-2">
<div className="space-y-1">
<Label htmlFor="dark-mode">{t('settings.darkMode')}</Label>
<p className="text-muted-foreground text-sm">
<p className="text-muted-foreground text-xs">
{t('settings.darkModeDescription')}
</p>
</div>
@@ -139,8 +139,8 @@ function SettingsPage() {
</Card>
{/* Account Settings Card */}
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.account.title')}</CardTitle>
<CardDescription>{t('settings.account.description')}</CardDescription>
</CardHeader>
@@ -149,7 +149,7 @@ function SettingsPage() {
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-1">
<Label>{t('settings.account.auto_refresh')}</Label>
<p className="text-xs text-gray-500">{t('settings.account.auto_refresh_desc')}</p>
<p className="text-muted-foreground text-xs">{t('settings.account.auto_refresh_desc')}</p>
</div>
<Switch
checked={config?.auto_refresh || false}
@@ -165,7 +165,7 @@ function SettingsPage() {
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-1">
<Label>{t('settings.account.auto_sync')}</Label>
<p className="text-xs text-gray-500">{t('settings.account.auto_sync_desc')}</p>
<p className="text-muted-foreground text-xs">{t('settings.account.auto_sync_desc')}</p>
</div>
<Switch
checked={config?.auto_sync || false}
@@ -180,8 +180,8 @@ function SettingsPage() {
</Card>
{isAutoStartSupported && (
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.startup.title')}</CardTitle>
<CardDescription>{t('settings.startup.description')}</CardDescription>
</CardHeader>
@@ -189,7 +189,7 @@ function SettingsPage() {
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-1">
<Label>{t('settings.startup.auto_startup')}</Label>
<p className="text-xs text-gray-500">
<p className="text-muted-foreground text-xs">
{t('settings.startup.auto_startup_desc')}
</p>
</div>
@@ -211,13 +211,13 @@ function SettingsPage() {
</Card>
)}
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.about.title')}</CardTitle>
<CardDescription>{t('settings.about.description')}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4 text-sm">
<div className="grid grid-cols-2 gap-4 text-[13px]">
<div className="text-muted-foreground">{t('settings.version')}</div>
<div className="font-medium">{appVersion || t('common.unknown')}</div>
@@ -230,7 +230,7 @@ function SettingsPage() {
<div className="text-muted-foreground">{t('action.openLogs')}</div>
<button
onClick={() => openLogDirectory()}
className="flex items-center gap-2 font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
className="flex items-center gap-2 font-medium text-accent hover:text-accent/80 transition-colors"
>
<FolderOpen className="h-4 w-4" />
<span>{t('settings.openLogDir')}</span>
@@ -240,8 +240,8 @@ function SettingsPage() {
</Card>
{/* Privacy & Error Reporting Card */}
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.privacy.title')}</CardTitle>
<CardDescription>{t('settings.privacy.description')}</CardDescription>
</CardHeader>
@@ -249,7 +249,7 @@ function SettingsPage() {
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-1">
<Label>{t('settings.privacy.error_reporting')}</Label>
<p className="text-xs text-gray-500">
<p className="text-muted-foreground text-xs">
{t('settings.privacy.error_reporting_desc')}
</p>
</div>
@@ -267,8 +267,8 @@ function SettingsPage() {
</Card>
{/* Notifications Card */}
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.notifications.title')}</CardTitle>
<CardDescription>{t('settings.notifications.description')}</CardDescription>
</CardHeader>
@@ -276,7 +276,7 @@ function SettingsPage() {
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-1">
<Label>{t('settings.notifications.quotaAlert')}</Label>
<p className="text-xs text-gray-500">
<p className="text-muted-foreground text-xs">
{t('settings.notifications.quotaAlertDesc')}
</p>
</div>
@@ -300,7 +300,7 @@ function SettingsPage() {
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-1">
<Label>{t('settings.notifications.quotaThreshold')}</Label>
<p className="text-xs text-gray-500">
<p className="text-muted-foreground text-xs">
{t('settings.notifications.quotaThresholdDesc')}
</p>
</div>
@@ -327,7 +327,7 @@ function SettingsPage() {
}
}
}}
className="w-16 rounded-md border bg-transparent px-2 py-1 text-center text-sm"
className="w-16 rounded-lg border border-white/[0.08] bg-muted/50 px-2 py-1 text-center text-[13px] text-foreground focus:outline-none focus:border-accent/50"
/>
<span className="text-muted-foreground text-sm">%</span>
</div>
@@ -343,8 +343,8 @@ function SettingsPage() {
{/* --- PROXY TAB (Upstream Proxy Config Only) --- */}
<TabsContent value="proxy" className="space-y-5">
<Card>
<CardHeader>
<Card className="bg-transparent border-0 shadow-none rounded-none border-b border-white/5 last:border-0 pb-6">
<CardHeader className="px-0 pt-4">
<CardTitle>{t('settings.proxy.title')}</CardTitle>
<CardDescription>{t('settings.proxy.description')}</CardDescription>
</CardHeader>