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:
parent
b9b3d98d71
commit
1bebb24015
|
|
@ -40,7 +40,7 @@
|
|||
{
|
||||
"name": "orca-cli",
|
||||
"sourcePath": "skills/orca-cli",
|
||||
"releaseRevision": 33,
|
||||
"releaseRevision": 35,
|
||||
"packageDigest": "72f63dcaad3dea8bea54838835fe46c689c37b63cd96a9ef2f2537f0c2f6b8c8",
|
||||
"gitTreeSha": "97f6596bb43a56c6e81246f077c35144c9025343",
|
||||
"files": [
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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": [
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3289,7 +3289,9 @@
|
|||
"noUsageData": "No usage data",
|
||||
"detailed": "Detailed",
|
||||
"compact": "Compact",
|
||||
"footerDetailAria": "Usage footer detail"
|
||||
"footerDetailAria": "Usage footer detail",
|
||||
"detailedTooltip": "バー・ラベル・パーセントを含む完全な使用状況",
|
||||
"compactTooltip": "凝縮された使用状況: 最も狭いウィンドウのみ"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3289,7 +3289,9 @@
|
|||
"noUsageData": "No usage data",
|
||||
"detailed": "Detailed",
|
||||
"compact": "Compact",
|
||||
"footerDetailAria": "Usage footer detail"
|
||||
"footerDetailAria": "Usage footer detail",
|
||||
"detailedTooltip": "막대, 레이블, 백분율을 포함한 전체 사용량",
|
||||
"compactTooltip": "압축된 사용: 가장 좁은 창만 사용"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3289,7 +3289,9 @@
|
|||
"noUsageData": "No usage data",
|
||||
"detailed": "Detailed",
|
||||
"compact": "Compact",
|
||||
"footerDetailAria": "Usage footer detail"
|
||||
"footerDetailAria": "Usage footer detail",
|
||||
"detailedTooltip": "完整使用情况,包含条形图、标签和百分比",
|
||||
"compactTooltip": "精简使用情况:仅显示最吃紧的窗口"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue