From 6e76e7dca686fb2e2ceb13bd2be83bcc55440727 Mon Sep 17 00:00:00 2001 From: Augustin Date: Thu, 23 Apr 2026 21:02:53 +0200 Subject: [PATCH] fix(dashboard): remove bg graphs, add scrollable lists, show used/total quota MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove BgGraph background SVGs that were misaligned with foreground graphs. Add max-height: 270px with overflow-y scroll to quota/processes/commands lists. Change API quota display from remaining/total to used/total. ๐Ÿ’˜ Generated with Crush Assisted-by: GLM-5.1 via Crush --- web/src/components/Dashboard.jsx | 157 +++++++++++-------------------- web/src/styles/global.css | 17 +--- 2 files changed, 60 insertions(+), 114 deletions(-) diff --git a/web/src/components/Dashboard.jsx b/web/src/components/Dashboard.jsx index ce2ad94..1c98f70 100644 --- a/web/src/components/Dashboard.jsx +++ b/web/src/components/Dashboard.jsx @@ -3,32 +3,6 @@ import { useI18n } from '../i18n' const MAX_POINTS = 30 -function BgGraph({ data, max, color }) { - if (!data || data.length < 2) return null - const m = max || Math.max(...data, 1) - const w = 120 - const h = 60 - const points = data.map((v, i) => { - const x = (i / (data.length - 1)) * w - const y = h - (v / m) * h - return `${x},${y}` - }) - const area = `${points.join(' ')} ${w},${h} 0,${h}` - const line = points.join(' ') - return ( - - - - - - - - - - - ) -} - function MiniGraph({ data, max, color, label, unit }) { if (!data || data.length < 2) return
collecting...
const m = max || Math.max(...data, 1) @@ -70,7 +44,6 @@ export default function Dashboard({ api, refreshRef }) { const memRef = useRef([]) const netRxRef = useRef([]) const netTxRef = useRef([]) - const procCountRef = useRef([]) const loadData = useCallback(async () => { try { @@ -90,7 +63,6 @@ export default function Dashboard({ api, refreshRef }) { netRxRef.current = [...netRxRef.current, metricsData.net_rx_kbs].slice(-MAX_POINTS) netTxRef.current = [...netTxRef.current, metricsData.net_tx_kbs].slice(-MAX_POINTS) } - procCountRef.current = [...procCountRef.current, procData.processes?.length || 0].slice(-MAX_POINTS) } catch (err) { console.error('Dashboard load error:', err) } @@ -105,99 +77,82 @@ export default function Dashboard({ api, refreshRef }) { const minimax = (quota || []).find(p => p.name === 'minimax') const zai = (quota || []).find(p => p.name === 'zai') - const totalQuotaUsed = minimax?.data?.models?.reduce((s, m) => s + (m.used || 0), 0) || 0 - const totalQuotaMax = minimax?.data?.models?.reduce((s, m) => s + (m.total || 0), 0) || 1 return (
{/* CPU */} -
- -
-
- CPU - {metrics ? metrics.cpu_percent.toFixed(0) : 'โ€”'}% -
- +
+
+ CPU + {metrics ? metrics.cpu_percent.toFixed(0) : 'โ€”'}%
+
{/* RAM */} -
- -
-
- RAM - {metrics ? `${metrics.mem_used_mb.toFixed(0)}/${metrics.mem_total_mb.toFixed(0)}` : 'โ€”'} -
- +
+
+ RAM + {metrics ? `${metrics.mem_used_mb.toFixed(0)}/${metrics.mem_total_mb.toFixed(0)}` : 'โ€”'}
+
{/* Network */} -
- -
-
- Network - {metrics ? `โ†“${metrics.net_rx_kbs.toFixed(0)} โ†‘${metrics.net_tx_kbs.toFixed(0)}` : 'โ€”'} -
- - +
+
+ Network + {metrics ? `โ†“${metrics.net_rx_kbs.toFixed(0)} โ†‘${metrics.net_tx_kbs.toFixed(0)}` : 'โ€”'}
+ +
{/* API Quota */} -
- 0 ? [totalQuotaUsed / totalQuotaMax * 100, ...(cpuRef.current.length > 0 ? [] : [0])] : []} max={100} color="#f472b6" /> -
-
- API Quota -
-
- {minimax && minimax.data?.models?.map((m, i) => ( -
- {String(m.model).replace('MiniMax-', '')} -
-
-
- {m.remaining}/{m.total} +
+
+ API Quota +
+
+ {minimax && minimax.data?.models?.map((m, i) => ( +
+ {String(m.model).replace('MiniMax-', '')} +
+
- ))} - {minimax && minimax.data?.models?.length === 0 && ( -
- MiniMax - {minimax.error || 'no data'} -
- )} - {zai && ( -
- Z.AI - {zai.healthy ? 'โœ“ active' : zai.error || 'โ€”'} -
- )} - {!minimax && !zai && No providers} -
+ {m.used}/{m.total} +
+ ))} + {minimax && minimax.data?.models?.length === 0 && ( +
+ MiniMax + {minimax.error || 'no data'} +
+ )} + {zai && ( +
+ Z.AI + {zai.healthy ? 'โœ“ active' : zai.error || 'โ€”'} +
+ )} + {!minimax && !zai && No providers}
{/* Running Processes */} -
- -
-
- Processes - {processes.length} -
-
- {processes.length === 0 && No relevant processes} - {processes.slice(0, 6).map((p, i) => ( -
- {p.name} - cpu {p.cpu}% ยท mem {p.mem}% -
- ))} -
+
+
+ Processes + {processes.length} +
+
+ {processes.length === 0 && No relevant processes} + {processes.map((p, i) => ( +
+ {p.name} + cpu {p.cpu}% ยท mem {p.mem}% +
+ ))}
@@ -208,7 +163,7 @@ export default function Dashboard({ api, refreshRef }) {
{recentCmds.length === 0 && No history} - {recentCmds.slice(0, 8).map((c, i) => ( + {recentCmds.map((c, i) => (
{c.shell} {c.cmd.length > 45 ? c.cmd.slice(0, 42) + '...' : c.cmd} diff --git a/web/src/styles/global.css b/web/src/styles/global.css index f6b3f06..41dcd5a 100644 --- a/web/src/styles/global.css +++ b/web/src/styles/global.css @@ -547,16 +547,7 @@ input::placeholder { color: var(--text-disabled); } display: flex; flex-direction: column; gap: 8px; overflow: hidden; } -.dash-card-graph { padding: 0; } -.dash-bg-graph { - position: absolute; inset: 0; width: 100%; height: 100%; - opacity: 0.35; pointer-events: none; -} -.dash-card-content { - position: relative; z-index: 1; - padding: 14px 16px; - display: flex; flex-direction: column; gap: 8px; -} + .dash-span-2 { grid-column: span 2; } .dash-card-head { display: flex; align-items: center; justify-content: space-between; @@ -585,7 +576,7 @@ input::placeholder { color: var(--text-disabled); } .dash-tool-tag.missing { color: var(--error); } /* Quota */ -.dash-quota-list { display: flex; flex-direction: column; gap: 6px; } +.dash-quota-list { display: flex; flex-direction: column; gap: 6px; max-height: 270px; overflow-y: auto; } .dash-quota-row { display: flex; align-items: center; gap: 8px; } .dash-quota-name { font-size: 11px; font-weight: 600; color: var(--text-primary); @@ -604,7 +595,7 @@ input::placeholder { color: var(--text-disabled); } } /* Processes */ -.dash-proc-list { display: flex; flex-direction: column; gap: 4px; } +.dash-proc-list { display: flex; flex-direction: column; gap: 4px; max-height: 270px; overflow-y: auto; } .dash-proc-row { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; @@ -618,7 +609,7 @@ input::placeholder { color: var(--text-disabled); } } /* Commands */ -.dash-cmd-list { display: flex; flex-direction: column; gap: 3px; } +.dash-cmd-list { display: flex; flex-direction: column; gap: 3px; max-height: 270px; overflow-y: auto; } .dash-cmd-row { display: flex; align-items: center; gap: 6px; padding: 3px 0; overflow: hidden;