mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 03:43:11 +08:00
feat(desktop): order the token usage page usage, activity, then models
The per-model table moves below the activity heatmap and insights under its own "Usage by model" heading.
This commit is contained in:
@@ -1197,6 +1197,7 @@ Row 9, all 8 cells: continuing from straight down, turning left through lower-le
|
||||
'settings.activity.messages': 'Messages',
|
||||
'settings.activity.tools': 'Tools',
|
||||
'settings.activity.activityInsights': 'Activity insights',
|
||||
'settings.activity.modelUsage': 'Usage by model',
|
||||
'settings.activity.activeRate': 'Active rate',
|
||||
'settings.activity.mostUsedModel': 'Most used model',
|
||||
'settings.activity.exploredSkills': 'Skills explored',
|
||||
|
||||
@@ -1198,6 +1198,7 @@ export const jp: Record<TranslationKey, string> = {
|
||||
'settings.activity.messages': 'メッセージ',
|
||||
'settings.activity.tools': 'ツール',
|
||||
'settings.activity.activityInsights': 'アクティビティ分析',
|
||||
'settings.activity.modelUsage': 'モデル別の使用量',
|
||||
'settings.activity.activeRate': 'アクティブ率',
|
||||
'settings.activity.mostUsedModel': '最も使ったモデル',
|
||||
'settings.activity.exploredSkills': '使用したスキル',
|
||||
|
||||
@@ -1200,6 +1200,7 @@ export const kr: Record<TranslationKey, string> = {
|
||||
'settings.activity.messages': '메시지',
|
||||
'settings.activity.tools': '도구',
|
||||
'settings.activity.activityInsights': '활동 인사이트',
|
||||
'settings.activity.modelUsage': '모델별 사용량',
|
||||
'settings.activity.activeRate': '활성 비율',
|
||||
'settings.activity.mostUsedModel': '가장 많이 쓴 모델',
|
||||
'settings.activity.exploredSkills': '사용한 스킬',
|
||||
|
||||
@@ -1197,6 +1197,7 @@ export const zh: Record<TranslationKey, string> = {
|
||||
'settings.activity.messages': '訊息',
|
||||
'settings.activity.tools': '工具',
|
||||
'settings.activity.activityInsights': '活動洞察',
|
||||
'settings.activity.modelUsage': '模型用量',
|
||||
'settings.activity.activeRate': '活躍率',
|
||||
'settings.activity.mostUsedModel': '最常用模型',
|
||||
'settings.activity.exploredSkills': '已使用的技能',
|
||||
|
||||
@@ -1196,6 +1196,7 @@ export const zh: Record<TranslationKey, string> = {
|
||||
'settings.activity.messages': '消息',
|
||||
'settings.activity.tools': '工具',
|
||||
'settings.activity.activityInsights': '活动洞察',
|
||||
'settings.activity.modelUsage': '模型用量',
|
||||
'settings.activity.activeRate': '活跃率',
|
||||
'settings.activity.mostUsedModel': '最常用模型',
|
||||
'settings.activity.exploredSkills': '已使用的技能',
|
||||
|
||||
@@ -412,6 +412,22 @@ describe('ActivitySettings', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('orders the page usage, then activity, then the per-model breakdown', async () => {
|
||||
render(<ActivitySettings />)
|
||||
|
||||
await flushActivityLoad()
|
||||
|
||||
const usage = screen.getByRole('list', { name: 'Token usage by day' })
|
||||
const activity = screen.getByRole('heading', { name: 'Token Activity' })
|
||||
const insights = screen.getByRole('heading', { name: 'Activity insights' })
|
||||
const models = screen.getByRole('heading', { name: 'Usage by model' })
|
||||
const follows = (a: Node, b: Node) => Boolean(a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING)
|
||||
expect(follows(usage, activity)).toBe(true)
|
||||
expect(follows(activity, insights)).toBe(true)
|
||||
expect(follows(insights, models)).toBe(true)
|
||||
expect(follows(models, screen.getByRole('table'))).toBe(true)
|
||||
})
|
||||
|
||||
it('supports localized heatmap mode switches and persisted display name edits', async () => {
|
||||
useSettingsStore.setState({ locale: 'zh' })
|
||||
render(<ActivitySettings />)
|
||||
|
||||
@@ -1001,34 +1001,6 @@ export function ActivitySettings() {
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{!isLoading && !error && hasUsage && modelRows.length > 0 && (
|
||||
<Card surface="lowest" padding="none" role="table" className="mt-3 overflow-hidden">
|
||||
<div
|
||||
role="row"
|
||||
className="grid grid-cols-[minmax(0,1.6fr)_minmax(0,0.8fr)_minmax(0,0.8fr)_minmax(0,0.8fr)] gap-3 bg-[var(--color-surface-container)] px-4 py-2.5 text-xs font-semibold text-[var(--color-text-tertiary)]"
|
||||
>
|
||||
<span role="columnheader" className="min-w-0 truncate">{t('settings.agents.model')}</span>
|
||||
<span role="columnheader" className="min-w-0 truncate text-right">{t('settings.activity.freshTokens')}</span>
|
||||
<span role="columnheader" className="min-w-0 truncate text-right">{t('settings.activity.cachedTokens')}</span>
|
||||
<span role="columnheader" className="min-w-0 truncate text-right">{t('settings.activity.estimatedCost')}</span>
|
||||
</div>
|
||||
{modelRows.map((row) => (
|
||||
<div
|
||||
key={row.model}
|
||||
role="row"
|
||||
className="grid grid-cols-[minmax(0,1.6fr)_minmax(0,0.8fr)_minmax(0,0.8fr)_minmax(0,0.8fr)] items-center gap-3 border-t border-[var(--color-border)] px-4 py-2.5 text-[13px] tabular-nums text-[var(--color-text-primary)]"
|
||||
>
|
||||
<span role="cell" className="min-w-0 truncate font-mono text-xs" title={row.model}>{row.model}</span>
|
||||
<span role="cell" className="min-w-0 truncate text-right">{formatTokens(row.fresh)}</span>
|
||||
<span role="cell" className="min-w-0 truncate text-right">{formatTokens(row.cached)}</span>
|
||||
<span role="cell" className="min-w-0 truncate text-right">
|
||||
{row.unpriced ? <span className="text-[var(--color-text-tertiary)]">—</span> : formatCostUSD(row.costUSD, locale)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Modal
|
||||
open={isEditingProfile}
|
||||
onClose={cancelProfileEdit}
|
||||
@@ -1265,6 +1237,36 @@ export function ActivitySettings() {
|
||||
</Card>
|
||||
</SettingsSection>
|
||||
|
||||
{modelRows.length > 0 && (
|
||||
<SettingsSection title={t('settings.activity.modelUsage')}>
|
||||
<Card surface="lowest" padding="none" role="table" className="overflow-hidden">
|
||||
<div
|
||||
role="row"
|
||||
className="grid grid-cols-[minmax(0,1.6fr)_minmax(0,0.8fr)_minmax(0,0.8fr)_minmax(0,0.8fr)] gap-3 bg-[var(--color-surface-container)] px-4 py-2.5 text-xs font-semibold text-[var(--color-text-tertiary)]"
|
||||
>
|
||||
<span role="columnheader" className="min-w-0 truncate">{t('settings.agents.model')}</span>
|
||||
<span role="columnheader" className="min-w-0 truncate text-right">{t('settings.activity.freshTokens')}</span>
|
||||
<span role="columnheader" className="min-w-0 truncate text-right">{t('settings.activity.cachedTokens')}</span>
|
||||
<span role="columnheader" className="min-w-0 truncate text-right">{t('settings.activity.estimatedCost')}</span>
|
||||
</div>
|
||||
{modelRows.map((row) => (
|
||||
<div
|
||||
key={row.model}
|
||||
role="row"
|
||||
className="grid grid-cols-[minmax(0,1.6fr)_minmax(0,0.8fr)_minmax(0,0.8fr)_minmax(0,0.8fr)] items-center gap-3 border-t border-[var(--color-border)] px-4 py-2.5 text-[13px] tabular-nums text-[var(--color-text-primary)]"
|
||||
>
|
||||
<span role="cell" className="min-w-0 truncate font-mono text-xs" title={row.model}>{row.model}</span>
|
||||
<span role="cell" className="min-w-0 truncate text-right">{formatTokens(row.fresh)}</span>
|
||||
<span role="cell" className="min-w-0 truncate text-right">{formatTokens(row.cached)}</span>
|
||||
<span role="cell" className="min-w-0 truncate text-right">
|
||||
{row.unpriced ? <span className="text-[var(--color-text-tertiary)]">—</span> : formatCostUSD(row.costUSD, locale)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</Card>
|
||||
</SettingsSection>
|
||||
)}
|
||||
|
||||
{topPluginItems.length > 0 && (
|
||||
<SettingsSection title={t('settings.activity.mostUsedPluginsAndSkills')}>
|
||||
<Card surface="lowest" padding="none" className="overflow-hidden">
|
||||
|
||||
Reference in New Issue
Block a user