From f445ceead6a374366ce1050459a61fdd544f2525 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Thu, 18 Jun 2026 21:17:25 +0000 Subject: [PATCH 1/7] feat(ui): legible Usage charts - distinct prompt/completion hues + chart a11y Prompt and completion were the same color (primary at 0.35 opacity), so the stacked token charts read as one blurry blob. Completion now uses a distinct data-viz hue (--color-data-3) at full opacity across the time chart, the per-model distribution bars, and the tooltip. The source-mix chart is no longer aria-hidden: it exposes role="img" with a label. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto --- core/http/react-ui/src/pages/Usage.jsx | 10 +++++----- core/http/react-ui/src/pages/Usage/SourceTimeChart.jsx | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/http/react-ui/src/pages/Usage.jsx b/core/http/react-ui/src/pages/Usage.jsx index 7e869c8731e5..50f499ada6cc 100644 --- a/core/http/react-ui/src/pages/Usage.jsx +++ b/core/http/react-ui/src/pages/Usage.jsx @@ -413,7 +413,7 @@ function UsageTimeChart({ data, predictedData, period }) { Tokens over time
Prompt - Completion + Completion {predictedData && predictedData.length > 0 && ( {/* Completion tokens (top) */} - + ) })} @@ -571,7 +571,7 @@ function UsageTimeChart({ data, predictedData, period }) { {formatBucket(tooltip.data.bucket, period)}
Prompt: {tooltip.predicted ? '~' : ''}{tooltip.data.prompt_tokens.toLocaleString()}
-
Completion: {tooltip.predicted ? '~' : ''}{tooltip.data.completion_tokens.toLocaleString()}
+
Completion: {tooltip.predicted ? '~' : ''}{tooltip.data.completion_tokens.toLocaleString()}
{tooltip.predicted ? '~' : ''}{tooltip.data.request_count} requests
@@ -596,7 +596,7 @@ function ModelDistChart({ rows }) { Token distribution by model
Prompt - Completion + Completion
@@ -613,7 +613,7 @@ function ModelDistChart({ rows }) {
-
+
{series.map((row, i) => { let y = height From b983e39e962875072d35d61f9df17ad16f9a8400 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Thu, 18 Jun 2026 21:22:35 +0000 Subject: [PATCH 2/7] feat(ui): sortable Users table The admin Users table is now sortable by name, email, provider, role, status, and created date - clickable headers with an aria-sort state, a direction caret, and keyboard activation (Enter/Space). Permissions and Actions stay non-sortable. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto --- core/http/react-ui/src/pages/Users.jsx | 41 +++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/core/http/react-ui/src/pages/Users.jsx b/core/http/react-ui/src/pages/Users.jsx index 79ce3a990bf4..14846e190ec9 100644 --- a/core/http/react-ui/src/pages/Users.jsx +++ b/core/http/react-ui/src/pages/Users.jsx @@ -797,6 +797,33 @@ export default function Users() { return (u.name || '').toLowerCase().includes(q) || (u.email || '').toLowerCase().includes(q) }) + const [sort, setSort] = useState({ key: null, dir: 'asc' }) + const USER_SORT = { + name: (a, b) => (a.name || '').localeCompare(b.name || ''), + email: (a, b) => (a.email || '').localeCompare(b.email || ''), + provider: (a, b) => (a.provider || '').localeCompare(b.provider || ''), + role: (a, b) => (a.role || '').localeCompare(b.role || ''), + status: (a, b) => (a.status || '').localeCompare(b.status || ''), + created: (a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0), + } + const sortedUsers = sort.key + ? [...filtered].sort((a, b) => sort.dir === 'asc' ? USER_SORT[sort.key](a, b) : USER_SORT[sort.key](b, a)) + : filtered + const toggleSort = (key) => setSort(s => s.key === key ? { key, dir: s.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: 'asc' }) + const sortableTh = (key, label, className) => ( + toggleSort(key)} + onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleSort(key) } }} + style={{ cursor: 'pointer', userSelect: 'none' }} + > + {label}{sort.key === key &&