feat(status-bar): tooltips for Detailed vs Compact usage modes (#9693)

* feat(status-bar): add tooltips explaining Detailed vs Compact usage modes

The Detailed/Compact density picker in the usage popover named both modes
but didn't explain what they change. Add hover tooltips via a new optional
`tooltip` field on SettingsSegmentedControl's options (no behavior change
for existing segmented controls).

* reword usage tooltips + add zh/ko/ja/es translations

Detailed: drop 'in the status bar'. Compact: 'Condensed usage: only the
tightest window'. Translate both keys into all locales via the repo's
translate+repair policy.

* test(status-bar): wrap UsageRosterPanel renders in TooltipProvider

The new segment tooltips use Radix Tooltip, which requires an ancestor
TooltipProvider (present in the real app at App root). Wrap the test
renders to match, fixing 3 failures.

* i18n(usage-tooltips): fix zh/ja mistranslations of 'full usage'

The zh/ja 'Detailed' tooltips read as an imperative ('make full use of
bars/labels/percentages') instead of the intended noun ('full usage
shown with ...'). Correct to the usage-status noun, align ja Compact to
使用状況 (not 使用法/how-to), and drop a stray trailing period in es.

* chore(skills): regenerate skill bundle manifest for release-tag drift

New release tags cut since the manifest was last committed appended
orca-cli snapshots (releaseRevision 33→35). Append-only regen — released
history is preserved; only unblocks the verify:skill-bundle-manifest gate.

* i18n(usage-tooltips): polish zh Compact tooltip wording

The zh Compact tooltip read like an instruction ('only use the tightest
window'). Reword to a descriptive summary parallel to Detailed. Keep the
'tightest = highest-usage window' meaning (getTightestUsageSection picks
max usedPercent) rather than CodeRabbit's '最短/shortest', which would
misdescribe it as the shortest-duration window.
This commit is contained in:
Brennan Benson 2026-07-21 13:01:54 -07:00 committed by GitHub
parent b9b3d98d71
commit 1bebb24015
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 158 additions and 52 deletions

View File

@ -40,7 +40,7 @@
{
"name": "orca-cli",
"sourcePath": "skills/orca-cli",
"releaseRevision": 33,
"releaseRevision": 35,
"packageDigest": "72f63dcaad3dea8bea54838835fe46c689c37b63cd96a9ef2f2537f0c2f6b8c8",
"gitTreeSha": "97f6596bb43a56c6e81246f077c35144c9025343",
"files": [

View File

@ -509,6 +509,45 @@
"orca-per-workspace-env": 2,
"orchestration": 25
}
},
{
"appVersion": "1.4.148-rc.1",
"skills": {
"computer-use": 5,
"linear-tickets": 4,
"orca-cli": 33,
"orca-emulator": 4,
"orca-emulator-android": 2,
"orca-linear": 2,
"orca-per-workspace-env": 2,
"orchestration": 25
}
},
{
"appVersion": "1.4.148",
"skills": {
"computer-use": 5,
"linear-tickets": 4,
"orca-cli": 34,
"orca-emulator": 4,
"orca-emulator-android": 2,
"orca-linear": 2,
"orca-per-workspace-env": 2,
"orchestration": 25
}
},
{
"appVersion": "1.4.149-rc.0",
"skills": {
"computer-use": 5,
"linear-tickets": 4,
"orca-cli": 35,
"orca-emulator": 4,
"orca-emulator-android": 2,
"orca-linear": 2,
"orca-per-workspace-env": 2,
"orchestration": 25
}
}
]
}

View File

@ -529,6 +529,38 @@
"identitySha256": "90228630bc4daab4ccf67b691153976d1f28ec064d7069a4c170621ed2ea99b5"
}
]
},
{
"releaseRevision": 34,
"packageDigest": "51740ff13f379ac5743d3fd28a14b17168dcef40f7048c20182dce166098c45f",
"gitTreeSha": "ded93000a5f654e2b4f324501282459bd56afe19",
"files": [
{
"path": "SKILL.md",
"size": 21557,
"executable": false,
"classification": "text",
"exactSha256": "b4c36e19fc158fc8c286bdfdf05a537985cb2159a596c93862968c5417bf15be",
"textNormalizedSha256": "b4c36e19fc158fc8c286bdfdf05a537985cb2159a596c93862968c5417bf15be",
"identitySha256": "b4c36e19fc158fc8c286bdfdf05a537985cb2159a596c93862968c5417bf15be"
}
]
},
{
"releaseRevision": 35,
"packageDigest": "72f63dcaad3dea8bea54838835fe46c689c37b63cd96a9ef2f2537f0c2f6b8c8",
"gitTreeSha": "97f6596bb43a56c6e81246f077c35144c9025343",
"files": [
{
"path": "SKILL.md",
"size": 3835,
"executable": false,
"classification": "text",
"exactSha256": "90228630bc4daab4ccf67b691153976d1f28ec064d7069a4c170621ed2ea99b5",
"textNormalizedSha256": "90228630bc4daab4ccf67b691153976d1f28ec064d7069a4c170621ed2ea99b5",
"identitySha256": "90228630bc4daab4ccf67b691153976d1f28ec064d7069a4c170621ed2ea99b5"
}
]
}
],
"orchestration": [

View File

@ -7,6 +7,7 @@ import { ScrollArea } from '../ui/scroll-area'
import { Input } from '../ui/input'
import { Label } from '../ui/label'
import { Popover, PopoverAnchor, PopoverContent } from '../ui/popover'
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
import { Check, ChevronsUpDown, CircleX } from 'lucide-react'
import { normalizeColor, type TerminalThemeOption } from '@/lib/terminal-theme'
import { MAX_THEME_RESULTS } from './SettingsConstants'
@ -138,6 +139,8 @@ type SegmentedOption<T extends string | number> = {
label: React.ReactNode
disabled?: boolean
ariaLabel?: string
/** Optional hover label describing what the option does. */
tooltip?: React.ReactNode
}
type SettingsSegmentedControlProps<T extends string | number> = {
@ -169,7 +172,7 @@ export function SettingsSegmentedControl<T extends string | number>({
>
{options.map((opt) => {
const active = opt.value === value
return (
const button = (
<button
key={String(opt.value)}
type="button"
@ -196,6 +199,15 @@ export function SettingsSegmentedControl<T extends string | number>({
{opt.label}
</button>
)
if (opt.tooltip == null) {
return button
}
return (
<Tooltip key={String(opt.value)}>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent>{opt.tooltip}</TooltipContent>
</Tooltip>
)
})}
</div>
)

View File

@ -28,6 +28,7 @@ vi.mock('@/components/ui/dropdown-menu', () => ({
}: React.PropsWithChildren<{ onSelect?: () => void }>) => <div {...props}>{children}</div>
}))
import { TooltipProvider } from '@/components/ui/tooltip'
import { UsageRosterPanel, UsageRow } from './UsageRosterPanel'
const signedOutCodex: ProviderRateLimits = {
@ -90,37 +91,39 @@ describe('UsageRow', () => {
const sessionReset = mocks.now + 2 * 60_000
const weeklyReset = mocks.now + 7 * 24 * 60 * 60_000
const markup = renderToStaticMarkup(
<UsageRosterPanel
providers={[
{
...signedOutCodex,
session: {
usedPercent: 25,
windowMinutes: 300,
resetsAt: sessionReset,
resetDescription: null
},
weekly: {
usedPercent: 10,
windowMinutes: 10_080,
resetsAt: weeklyReset,
resetDescription: null
},
status: 'ok',
error: null
}
]}
display="used"
statusBarUsageMode="verbose"
onStatusBarUsageModeChange={() => {}}
isRefreshing={false}
onRefresh={() => {}}
onOpenProvider={() => {}}
onSignIn={() => {}}
canSignIn={() => true}
onManageAccounts={() => {}}
onUsageDetails={() => {}}
/>
<TooltipProvider>
<UsageRosterPanel
providers={[
{
...signedOutCodex,
session: {
usedPercent: 25,
windowMinutes: 300,
resetsAt: sessionReset,
resetDescription: null
},
weekly: {
usedPercent: 10,
windowMinutes: 10_080,
resetsAt: weeklyReset,
resetDescription: null
},
status: 'ok',
error: null
}
]}
display="used"
statusBarUsageMode="verbose"
onStatusBarUsageModeChange={() => {}}
isRefreshing={false}
onRefresh={() => {}}
onOpenProvider={() => {}}
onSignIn={() => {}}
canSignIn={() => true}
onManageAccounts={() => {}}
onUsageDetails={() => {}}
/>
</TooltipProvider>
)
expect(mocks.useResetCountdownClock).toHaveBeenCalledOnce()
@ -153,19 +156,21 @@ describe('UsageRosterPanel density picker', () => {
): void {
act(() => {
root.render(
<UsageRosterPanel
providers={[]}
display="used"
statusBarUsageMode={statusBarUsageMode}
onStatusBarUsageModeChange={onStatusBarUsageModeChange}
isRefreshing={false}
onRefresh={() => {}}
onOpenProvider={() => {}}
onSignIn={() => {}}
canSignIn={() => true}
onManageAccounts={() => {}}
onUsageDetails={() => {}}
/>
<TooltipProvider>
<UsageRosterPanel
providers={[]}
display="used"
statusBarUsageMode={statusBarUsageMode}
onStatusBarUsageModeChange={onStatusBarUsageModeChange}
isRefreshing={false}
onRefresh={() => {}}
onOpenProvider={() => {}}
onSignIn={() => {}}
canSignIn={() => true}
onManageAccounts={() => {}}
onUsageDetails={() => {}}
/>
</TooltipProvider>
)
})
}

View File

@ -236,11 +236,19 @@ export function UsageRosterPanel({
options={[
{
value: 'verbose',
label: translate('auto.components.status.bar.UsageRosterPanel.detailed', 'Detailed')
label: translate('auto.components.status.bar.UsageRosterPanel.detailed', 'Detailed'),
tooltip: translate(
'auto.components.status.bar.UsageRosterPanel.detailedTooltip',
'Full usage with bars, labels, and percentages'
)
},
{
value: 'compact',
label: translate('auto.components.status.bar.UsageRosterPanel.compact', 'Compact')
label: translate('auto.components.status.bar.UsageRosterPanel.compact', 'Compact'),
tooltip: translate(
'auto.components.status.bar.UsageRosterPanel.compactTooltip',
'Condensed usage: only the tightest window'
)
}
]}
/>

View File

@ -3312,6 +3312,8 @@
"noUsageData": "No usage data",
"detailed": "Detailed",
"compact": "Compact",
"detailedTooltip": "Full usage with bars, labels, and percentages",
"compactTooltip": "Condensed usage: only the tightest window",
"footerDetailAria": "Usage footer detail"
}
}

View File

@ -3289,7 +3289,9 @@
"noUsageData": "No usage data",
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
"footerDetailAria": "Usage footer detail",
"detailedTooltip": "Uso completo con barras, etiquetas y porcentajes",
"compactTooltip": "Uso condensado: sólo la ventana más estrecha"
}
}
},

View File

@ -3289,7 +3289,9 @@
"noUsageData": "No usage data",
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
"footerDetailAria": "Usage footer detail",
"detailedTooltip": "バー・ラベル・パーセントを含む完全な使用状況",
"compactTooltip": "凝縮された使用状況: 最も狭いウィンドウのみ"
}
}
},

View File

@ -3289,7 +3289,9 @@
"noUsageData": "No usage data",
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
"footerDetailAria": "Usage footer detail",
"detailedTooltip": "막대, 레이블, 백분율을 포함한 전체 사용량",
"compactTooltip": "압축된 사용: 가장 좁은 창만 사용"
}
}
},

View File

@ -3289,7 +3289,9 @@
"noUsageData": "No usage data",
"detailed": "Detailed",
"compact": "Compact",
"footerDetailAria": "Usage footer detail"
"footerDetailAria": "Usage footer detail",
"detailedTooltip": "完整使用情况,包含条形图、标签和百分比",
"compactTooltip": "精简使用情况:仅显示最吃紧的窗口"
}
}
},