diff --git a/src/components/usage/ApiDetailsCard.tsx b/src/components/usage/ApiDetailsCard.tsx index 1a41f9a..6e93436 100644 --- a/src/components/usage/ApiDetailsCard.tsx +++ b/src/components/usage/ApiDetailsCard.tsx @@ -74,6 +74,7 @@ export function ApiDetailsCard({ apiStats, loading, hasPrices }: ApiDetailsCardP + {isExpanded && ( +
+ {Object.entries(api.models).map(([model, stats]) => ( +
+ {model} + + + {stats.requests.toLocaleString()} + + ({stats.successCount.toLocaleString()}{' '} + {stats.failureCount.toLocaleString()}) + + + + {formatCompactNumber(stats.tokens)} +
+ ))} +
+ )} + + ); + })} ) : ( diff --git a/src/components/usage/ModelStatsCard.tsx b/src/components/usage/ModelStatsCard.tsx index d40c74e..f35d070 100644 --- a/src/components/usage/ModelStatsCard.tsx +++ b/src/components/usage/ModelStatsCard.tsx @@ -55,6 +55,8 @@ export function ModelStatsCard({ modelStats, loading, hasPrices }: ModelStatsCar const arrow = (key: SortKey) => sortKey === key ? (sortDir === 'asc' ? ' ▲' : ' ▼') : ''; + const ariaSort = (key: SortKey): 'none' | 'ascending' | 'descending' => + sortKey === key ? (sortDir === 'asc' ? 'ascending' : 'descending') : 'none'; return ( @@ -65,21 +67,51 @@ export function ModelStatsCard({ modelStats, loading, hasPrices }: ModelStatsCar - - - - {hasPrices && ( - )} diff --git a/src/pages/UsagePage.module.scss b/src/pages/UsagePage.module.scss index f97f696..854c943 100644 --- a/src/pages/UsagePage.module.scss +++ b/src/pages/UsagePage.module.scss @@ -451,6 +451,11 @@ background: var(--bg-tertiary); color: var(--text-primary); } + + &:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: 1px; + } } .apiSortBtnActive { @@ -474,16 +479,27 @@ } .apiHeader { + width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 10px; + border: 0; + background: transparent; + color: inherit; + font: inherit; + text-align: left; cursor: pointer; transition: background-color 0.15s ease; &:hover { background-color: var(--bg-tertiary); } + + &:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: -2px; + } } .apiInfo { @@ -588,7 +604,6 @@ } th.sortableHeader { - cursor: pointer; user-select: none; transition: color 0.15s ease; @@ -606,6 +621,25 @@ } } +.sortHeaderButton { + display: inline-flex; + align-items: center; + width: 100%; + border: 0; + padding: 0; + background: transparent; + color: inherit; + font: inherit; + text-align: left; + cursor: pointer; + + &:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: 2px; + border-radius: $radius-sm; + } +} + .modelCell { font-weight: 500; max-width: 240px;
handleSort('model')}> - {t('usage_stats.model_name')}{arrow('model')} + + handleSort('requests')}> - {t('usage_stats.requests_count')}{arrow('requests')} + + handleSort('tokens')}> - {t('usage_stats.tokens_count')}{arrow('tokens')} + + handleSort('successRate')}> - {t('usage_stats.success_rate')}{arrow('successRate')} + + handleSort('cost')}> - {t('usage_stats.total_cost')}{arrow('cost')} + +