feat(webui): Enhance dashboard, global styles, and settings module
## Dashboard Enhancements
- Add Request Volume trend chart with Chart.js line graph
- Support Family/Model display modes for aggregation levels
- Show Total/Today/1H usage statistics
- Hierarchical filter dropdown with Smart select (Top 5 by 24h usage)
- Persist chart preferences to localStorage
- Improve account health detection logic
- Core models (sonnet/opus/pro/flash) require >5% quota to be healthy
- Dynamic quota ring chart supporting any model family
- Unify table styles with standard-table class
## Global Style Refactoring
- Add CSS variable system for theming
- Space color scale (950/900/850/800/border)
- Neon accent colors (purple/green/cyan/yellow/red)
- Text hierarchy (main/dim/muted/bright)
- Chart palette (16 colors)
- Add unified component classes
- .view-container for consistent page layouts
- .section-header/.section-title/.section-desc
- .standard-table for table styling
- Update scrollbar, nav-item, progress-bar to use theme variables
## Settings Module Extensions
- Add model mapping column in Models tab
- Enhance model selectors with family color indicators
- Support horizontal scroll for tabs on narrow screens
- Add defaultCooldownMs and maxWaitBeforeErrorMs config options
## New Module
- Add src/modules/usage-stats.js for request tracking
- Track /v1/messages and /v1/chat/completions endpoints
- Hierarchical storage: { hour: { family: { model: count } } }
- Auto-save every minute, 30-day retention
- GET /api/stats/history endpoint for dashboard chart
## Backend Changes
- Add direct account manipulation helpers (bypass AccountManager)
- Add POST /api/config/password endpoint for WebUI password change
- Auto-reload AccountManager after account operations
- Use CSS variables in OAuth callback pages
## Other
- Update .gitignore for runtime data directory
- Add i18n keys for new UI elements (EN/zh_CN)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
<div x-data="accountManager" class="max-w-4xl mx-auto space-y-6">
|
||||
<div class="flex justify-between items-center">
|
||||
<div x-data="accountManager" class="view-container">
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-white tracking-tight" x-text="$store.global.t('accessCredentials')">
|
||||
Access
|
||||
Credentials</h2>
|
||||
<p class="text-gray-500 text-sm" x-text="$store.global.t('manageTokens')">Manage OAuth tokens
|
||||
and session
|
||||
states</p>
|
||||
<h2 class="section-title" x-text="$store.global.t('accessCredentials')">
|
||||
Access Credentials
|
||||
</h2>
|
||||
<p class="section-desc" x-text="$store.global.t('manageTokens')">
|
||||
Manage OAuth tokens and session states
|
||||
</p>
|
||||
</div>
|
||||
<button class="btn btn-sm bg-neon-purple hover:bg-purple-600 text-white border-none gap-2"
|
||||
<button class="btn btn-primary btn-sm gap-2"
|
||||
onclick="document.getElementById('add_account_modal').showModal()">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
@@ -18,8 +18,8 @@
|
||||
</div>
|
||||
|
||||
<div class="glass-panel rounded-xl overflow-hidden">
|
||||
<table class="table w-full">
|
||||
<thead class="bg-space-900/50 text-gray-500 font-mono text-xs uppercase border-b border-space-border">
|
||||
<table class="standard-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="pl-6 w-24" x-text="$store.global.t('enabled')">Enabled</th>
|
||||
<th x-text="$store.global.t('identity')">Identity (Email)</th>
|
||||
@@ -28,17 +28,14 @@
|
||||
<th class="text-right pr-6" x-text="$store.global.t('operations')">Operations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-space-border/50">
|
||||
<tbody>
|
||||
<template x-for="acc in $store.data.accounts" :key="acc.email">
|
||||
<tr class="hover:bg-white/5 transition-colors">
|
||||
<tr>
|
||||
<td class="pl-6">
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" class="sr-only peer" :checked="acc.enabled !== false"
|
||||
@change="toggleAccount(acc.email, $el.checked)">
|
||||
<div
|
||||
class="w-9 h-5 bg-space-800 border border-space-border peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-neon-purple rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-gray-400 after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-neon-green/20 peer-checked:border-neon-green peer-checked:after:bg-neon-green peer-checked:after:shadow-[0_0_8px_rgba(34,197,94,0.8)]">
|
||||
</div>
|
||||
</label>
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-success toggle-sm"
|
||||
:checked="acc.enabled !== false"
|
||||
@change="toggleAccount(acc.email, $el.checked)">
|
||||
</td>
|
||||
<td class="font-medium text-gray-200" x-text="acc.email"></td>
|
||||
<td class="font-mono text-xs text-gray-400" x-text="acc.projectId || '-'"></td>
|
||||
@@ -52,11 +49,12 @@
|
||||
<!-- Fix Button -->
|
||||
<button x-show="acc.status === 'invalid'"
|
||||
class="btn btn-xs bg-yellow-500/10 text-yellow-500 hover:bg-yellow-500/20 border-none mr-1 px-2 font-mono"
|
||||
@click="fixAccount(acc.email)">
|
||||
@click="fixAccount(acc.email)"
|
||||
x-text="$store.global.t('fix')">
|
||||
FIX
|
||||
</button>
|
||||
<button class="btn btn-xs btn-square btn-ghost text-gray-400 hover:text-white"
|
||||
@click="refreshAccount(acc.email)" title="Refresh Token">
|
||||
@click="refreshAccount(acc.email)" :title="$store.global.t('refreshData')">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
|
||||
Reference in New Issue
Block a user