feat(status-bar): replace usage footer toggle with Compact/Detailed segmented control

Swap the bottom-of-popover on/off switch for a SettingsSegmentedControl at
the top of the Usage popover (view-switcher pattern), so both modes are
named and discoverable on first open. Reuses the repo's canonical
Compact/Detailed vocabulary from the Workspace card-layout control.
This commit is contained in:
Brennan Benson
2026-07-20 17:33:57 -07:00
parent 982c1eb5b3
commit b910f48da0
7 changed files with 122 additions and 47 deletions
@@ -1,5 +1,9 @@
// @vitest-environment happy-dom
import { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { renderToStaticMarkup } from 'react-dom/server'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { ProviderRateLimits } from '../../../../shared/rate-limit-types'
const mocks = vi.hoisted(() => ({
@@ -17,21 +21,6 @@ vi.mock('@/hooks/useResetCountdownClock', () => ({
useResetCountdownClock: mocks.useResetCountdownClock
}))
vi.mock('@/components/ui/dropdown-menu', () => ({
DropdownMenuCheckboxItem: ({
children,
checked,
onCheckedChange: _onCheckedChange,
onSelect: _onSelect,
...props
}: React.PropsWithChildren<{
checked?: boolean
onCheckedChange?: (checked: boolean) => void
onSelect?: () => void
}>) => (
<div data-checked={checked} {...props}>
{children}
</div>
),
DropdownMenuItem: ({
children,
onSelect: _onSelect,
@@ -137,7 +126,81 @@ describe('UsageRow', () => {
expect(mocks.useResetCountdownClock).toHaveBeenCalledOnce()
expect(mocks.useResetCountdownClock).toHaveBeenCalledWith([sessionReset, weeklyReset])
expect(markup).toContain('Resets in 2m')
expect(markup).toContain('Verbose footer')
expect(markup).toContain('data-checked="true"')
})
})
describe('UsageRosterPanel density picker', () => {
let container: HTMLDivElement
let root: Root
beforeEach(() => {
mocks.useResetCountdownClock.mockClear()
container = document.createElement('div')
document.body.appendChild(container)
root = createRoot(container)
})
afterEach(() => {
act(() => {
root.unmount()
})
container.remove()
})
function renderPanel(
statusBarUsageMode: 'verbose' | 'compact',
onStatusBarUsageModeChange: (mode: 'verbose' | 'compact') => void
): void {
act(() => {
root.render(
<UsageRosterPanel
providers={[]}
display="used"
statusBarUsageMode={statusBarUsageMode}
onStatusBarUsageModeChange={onStatusBarUsageModeChange}
isRefreshing={false}
onRefresh={() => {}}
onOpenProvider={() => {}}
onSignIn={() => {}}
canSignIn={() => true}
onManageAccounts={() => {}}
onUsageDetails={() => {}}
/>
)
})
}
function segmentButton(label: string): HTMLButtonElement {
const button = [...container.querySelectorAll('button')].find(
(node) => node.textContent === label
)
if (!button) {
throw new Error(`missing "${label}" segment`)
}
return button as HTMLButtonElement
}
it('offers named Detailed/Compact segments and marks the active one', () => {
renderPanel('compact', () => {})
expect(container.textContent).toContain('Detailed')
expect(container.textContent).toContain('Compact')
expect(segmentButton('Compact').getAttribute('aria-checked')).toBe('true')
expect(segmentButton('Detailed').getAttribute('aria-checked')).toBe('false')
})
it('switches mode when a segment is chosen', () => {
const onStatusBarUsageModeChange = vi.fn()
renderPanel('compact', onStatusBarUsageModeChange)
act(() => {
segmentButton('Detailed').click()
})
expect(onStatusBarUsageModeChange).toHaveBeenLastCalledWith('verbose')
act(() => {
segmentButton('Compact').click()
})
expect(onStatusBarUsageModeChange).toHaveBeenLastCalledWith('compact')
})
})
@@ -1,6 +1,7 @@
import React from 'react'
import { ChevronRight, RefreshCw } from 'lucide-react'
import { DropdownMenuCheckboxItem, DropdownMenuItem } from '@/components/ui/dropdown-menu'
import { DropdownMenuItem } from '@/components/ui/dropdown-menu'
import { SettingsSegmentedControl } from '@/components/settings/SettingsFormControls'
import { useResetCountdownClock } from '@/hooks/useResetCountdownClock'
import { translate } from '@/i18n/i18n'
import { formatRateLimitWindowChipLabel, formatWindowLabel } from '@/lib/window-label-formatter'
@@ -220,6 +221,30 @@ export function UsageRosterPanel({
</DropdownMenuItem>
</div>
</div>
{/* Density picker lives at the top of the popover it controls (view-switcher
pattern) so both modes are named and discoverable on first open. */}
<div className="px-3.5 pb-2.5">
<SettingsSegmentedControl<StatusBarUsageMode>
value={statusBarUsageMode}
onChange={onStatusBarUsageModeChange}
ariaLabel={translate(
'auto.components.status.bar.UsageRosterPanel.footerDetailAria',
'Usage footer detail'
)}
size="sm"
equalWidth
options={[
{
value: 'verbose',
label: translate('auto.components.status.bar.UsageRosterPanel.detailed', 'Detailed')
},
{
value: 'compact',
label: translate('auto.components.status.bar.UsageRosterPanel.compact', 'Compact')
}
]}
/>
</div>
<div className="border-t border-border/70" />
{sorted.map((p) => {
const state = getUsageRosterRowState(p, usedSections(p).length > 0)
@@ -259,29 +284,6 @@ export function UsageRosterPanel({
)
})}
<div className="border-t border-border/70" />
<DropdownMenuCheckboxItem
checked={statusBarUsageMode === 'verbose'}
onCheckedChange={(checked) => {
onStatusBarUsageModeChange(checked ? 'verbose' : 'compact')
}}
onSelect={(event) => event.preventDefault()}
className="w-full cursor-pointer justify-between rounded-none px-3.5 py-2.5 text-[13px] text-foreground [&>span:first-child]:hidden"
>
{translate('auto.components.status.bar.UsageRosterPanel.verboseFooter', 'Verbose footer')}
{/* Why: one menu control avoids nesting the SettingsSwitch button inside an interactive item. */}
<span
aria-hidden
className={`relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent transition-colors ${
statusBarUsageMode === 'verbose' ? 'bg-foreground' : 'bg-muted-foreground/30'
}`}
>
<span
className={`block size-3.5 rounded-full bg-background shadow-sm transition-transform ${
statusBarUsageMode === 'verbose' ? 'translate-x-4' : 'translate-x-0.5'
}`}
/>
</span>
</DropdownMenuCheckboxItem>
<DropdownMenuItem
onSelect={onUsageDetails}
className="w-full cursor-pointer justify-between rounded-none px-3.5 py-2.5 text-[13px] text-foreground"
+3 -1
View File
@@ -3309,7 +3309,9 @@
"loadingUsage": "Loading usage…",
"usageUnavailable": "Usage unavailable",
"noUsageData": "No usage data",
"verboseFooter": "Verbose footer"
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
}
}
},
+3 -1
View File
@@ -3286,7 +3286,9 @@
"loadingUsage": "Loading usage…",
"usageUnavailable": "Usage unavailable",
"noUsageData": "No usage data",
"verboseFooter": "Verbose footer"
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
}
}
},
+3 -1
View File
@@ -3286,7 +3286,9 @@
"loadingUsage": "Loading usage…",
"usageUnavailable": "Usage unavailable",
"noUsageData": "No usage data",
"verboseFooter": "Verbose footer"
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
}
}
},
+3 -1
View File
@@ -3286,7 +3286,9 @@
"loadingUsage": "Loading usage…",
"usageUnavailable": "Usage unavailable",
"noUsageData": "No usage data",
"verboseFooter": "Verbose footer"
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
}
}
},
+3 -1
View File
@@ -3286,7 +3286,9 @@
"loadingUsage": "Loading usage…",
"usageUnavailable": "Usage unavailable",
"noUsageData": "No usage data",
"verboseFooter": "Verbose footer"
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
}
}
},