diff --git a/packages/web-shell/client/components/messages/StatsMessage.module.css b/packages/web-shell/client/components/messages/StatsMessage.module.css index d32e5092fa..b515e37175 100644 --- a/packages/web-shell/client/components/messages/StatsMessage.module.css +++ b/packages/web-shell/client/components/messages/StatsMessage.module.css @@ -118,6 +118,14 @@ min-height: 20px; } +.modelUsageRow { + display: grid; + grid-template-columns: + minmax(14ch, 1.4fr) + repeat(3, minmax(9ch, 1fr)); + column-gap: 16px; +} + .tableNameCol { color: var(--foreground); font-weight: 700; @@ -142,6 +150,13 @@ white-space: nowrap; } +.tableValueCol { + min-width: 9ch; + color: var(--foreground); + text-align: right; + white-space: nowrap; +} + /* ---------- Semantic colors ---------- */ .success { diff --git a/packages/web-shell/client/components/messages/StatsMessage.tsx b/packages/web-shell/client/components/messages/StatsMessage.tsx index d08cc9b295..fbc0132402 100644 --- a/packages/web-shell/client/components/messages/StatsMessage.tsx +++ b/packages/web-shell/client/components/messages/StatsMessage.tsx @@ -247,11 +247,13 @@ function StatsOverview({ status }: { status: DaemonSessionStatsStatus }) {
{/* Header */} -
+
{t('stats.modelUsage')} - {t('stats.reqs')} - {t('stats.inputTokens')} - + {t('stats.reqs')} + + {t('stats.inputTokens')} + + {t('stats.outputTokens')}
@@ -259,15 +261,18 @@ function StatsOverview({ status }: { status: DaemonSessionStatsStatus }) { {/* Rows */} {entries.map((e) => ( -
+
{e.label} - + {e.metrics.api.totalRequests} - + {e.metrics.tokens.prompt.toLocaleString()} - + {e.metrics.tokens.candidates.toLocaleString()}
@@ -366,7 +371,7 @@ function ModelStatsCard({ status }: { status: DaemonSessionStatsStatus }) { ))} /> m.tokens.prompt.toLocaleString())} variant="sub" /> @@ -382,6 +387,11 @@ function ModelStatsCard({ status }: { status: DaemonSessionStatsStatus }) { variant="sub" /> )} + m.tokens.candidates.toLocaleString())} + variant="sub" + /> {hasThoughts && ( )} - m.tokens.candidates.toLocaleString())} - variant="sub" - />
); } diff --git a/packages/web-shell/client/components/panels/TodoPanel.module.css b/packages/web-shell/client/components/panels/TodoPanel.module.css index 73a28ce119..5cf178eead 100644 --- a/packages/web-shell/client/components/panels/TodoPanel.module.css +++ b/packages/web-shell/client/components/panels/TodoPanel.module.css @@ -118,6 +118,15 @@ font-size: 13px; } +.loadingIcon { + width: 12px; + height: 12px; + border: 2px solid color-mix(in srgb, var(--agent-blue-500) 24%, transparent); + border-top-color: var(--agent-blue-500); + border-radius: 50%; + animation: todoPanelSpin 0.8s linear infinite; +} + .content { min-width: 0; overflow: hidden; @@ -131,13 +140,33 @@ color: var(--muted-foreground); } +.completed .content { + text-decoration: line-through; + text-decoration-color: color-mix( + in srgb, + var(--muted-foreground) 72%, + transparent + ); +} + .inProgress .icon, .inProgress .content { color: var(--foreground); - font-weight: 600; } .pending .icon, .pending .content { color: var(--muted-foreground); } + +@keyframes todoPanelSpin { + to { + transform: rotate(1turn); + } +} + +@media (prefers-reduced-motion: reduce) { + .loadingIcon { + animation: none; + } +} diff --git a/packages/web-shell/client/components/panels/TodoPanel.tsx b/packages/web-shell/client/components/panels/TodoPanel.tsx index dba61863c0..e46a4d7114 100644 --- a/packages/web-shell/client/components/panels/TodoPanel.tsx +++ b/packages/web-shell/client/components/panels/TodoPanel.tsx @@ -72,7 +72,11 @@ export const TodoPanel = memo(function TodoPanel({ className={`${styles.item} ${getStatusClass(todo.status)}`} >