Flip usage bars from percent-remaining to percent-used (#8167)
Aligns status bar, tooltip, popover mocks, and mobile usage bars with the Claude/Codex harness convention (consumption meters) so a fresh account reads empty/green and a depleted one reads full/red, instead of the inverted "left" framing that misread as "full = exhausted".
This commit is contained in:
parent
b93a7eece1
commit
b9ccc0d17f
|
|
@ -21,9 +21,9 @@ export {
|
|||
hasRenderableUsage
|
||||
} from './account-usage-state'
|
||||
|
||||
// Why: matches desktop StatusBar convention — bars show percent remaining
|
||||
// (so a fresh account renders full, a depleted one renders empty), not
|
||||
// percent used. Color thresholds invert accordingly.
|
||||
// Why: matches desktop StatusBar — bars show percent used (consumption), same
|
||||
// as Claude/Codex harness meters. Fresh account is empty/green; depleted is
|
||||
// full/red.
|
||||
export function UsageBar({
|
||||
label,
|
||||
usedPercent,
|
||||
|
|
@ -35,13 +35,15 @@ export function UsageBar({
|
|||
unavailable: boolean
|
||||
loading?: boolean
|
||||
}) {
|
||||
const remaining = usedPercent == null ? null : Math.max(0, Math.min(100, 100 - usedPercent))
|
||||
// Why: round then clamp so bar width, color, and label share one value (desktop parity).
|
||||
const used = usedPercent == null ? null : Math.max(0, Math.min(100, Math.round(usedPercent)))
|
||||
// Why: same consumption bands as desktop barColor (green <60, amber <80, red ≥80).
|
||||
const barColor =
|
||||
remaining == null
|
||||
used == null
|
||||
? colors.textMuted
|
||||
: remaining <= 10
|
||||
: used >= 80
|
||||
? colors.statusRed
|
||||
: remaining <= 30
|
||||
: used >= 60
|
||||
? colors.statusAmber
|
||||
: colors.statusGreen
|
||||
return (
|
||||
|
|
@ -52,7 +54,7 @@ export function UsageBar({
|
|||
style={[
|
||||
styles.usageFill,
|
||||
{
|
||||
width: `${remaining ?? 0}%`,
|
||||
width: `${used ?? 0}%`,
|
||||
backgroundColor: unavailable ? colors.textMuted : barColor
|
||||
}
|
||||
]}
|
||||
|
|
@ -61,9 +63,7 @@ export function UsageBar({
|
|||
{loading ? (
|
||||
<ActivityIndicator size="small" color={colors.textSecondary} style={styles.usageSpinner} />
|
||||
) : (
|
||||
<Text style={styles.usageValue}>
|
||||
{unavailable || remaining == null ? '—' : `${Math.round(remaining)}%`}
|
||||
</Text>
|
||||
<Text style={styles.usageValue}>{unavailable || used == null ? '—' : `${used}%`}</Text>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2433,7 +2433,7 @@
|
|||
}
|
||||
|
||||
/* Brief one-shot pulse when the Codex limits popover swaps accounts and the
|
||||
"100% left" label flashes from red to green. */
|
||||
"0% used" label flashes from red to green. */
|
||||
@keyframes feature-wall-meta-pulse {
|
||||
0% {
|
||||
color: rgb(220 38 38);
|
||||
|
|
|
|||
|
|
@ -77,10 +77,11 @@ function Popover(props: {
|
|||
pulseKey: number
|
||||
}): JSX.Element {
|
||||
const { expanded, targeted, swapped, pulseKey } = props
|
||||
const sessionPctText = swapped ? '100% left' : '4% left'
|
||||
// Why: bars show % used (consumption), matching the live status-bar meter.
|
||||
const sessionPctText = swapped ? '0% used' : '96% used'
|
||||
const sessionResetText = swapped ? 'Resets in 5h' : 'Resets in 47m'
|
||||
const sessionFillWidth = swapped ? '100%' : '4%'
|
||||
const weeklyFillWidth = '62%'
|
||||
const sessionFillWidth = swapped ? '0%' : '96%'
|
||||
const weeklyFillWidth = '38%'
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -144,7 +145,7 @@ function Popover(props: {
|
|||
<span>
|
||||
{translate(
|
||||
'auto.components.feature.wall.agents.orchestration.UsagePage.05ce4ecdd3',
|
||||
'62% left'
|
||||
'38% used'
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
|
|
@ -201,15 +202,15 @@ function Popover(props: {
|
|||
<SwitchAccount
|
||||
accountWidthClassName="w-24"
|
||||
tag="Team"
|
||||
fillPct={100}
|
||||
metaText="100%"
|
||||
fillPct={0}
|
||||
metaText="0%"
|
||||
highlighted={targeted}
|
||||
/>
|
||||
<SwitchAccount
|
||||
accountWidthClassName="w-32"
|
||||
tag={null}
|
||||
fillPct={78}
|
||||
metaText="78%"
|
||||
fillPct={22}
|
||||
metaText="22%"
|
||||
highlighted={false}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -295,11 +296,12 @@ function SwitchAccount(props: {
|
|||
|
||||
// The 340px-wide light pill at the bottom of the panel that the popover tip
|
||||
// points down to. Codex chip is the "active" one — it animates from a near-
|
||||
// empty red bar to a full green bar after the account swap.
|
||||
// full red bar (% used) to an empty green bar after the account swap.
|
||||
function BottomBar(props: { swapped: boolean }): JSX.Element {
|
||||
const codexFillWidth = props.swapped ? '100%' : '4%'
|
||||
// Why: match live status-bar consumption meters (% used), same as the popover.
|
||||
const codexFillWidth = props.swapped ? '0%' : '96%'
|
||||
const codexFillColor = props.swapped ? 'rgb(34 197 94)' : 'rgb(239 68 68)'
|
||||
const codexMeta = props.swapped ? '100% 5h · 96% wk' : '4% 47m'
|
||||
const codexMeta = props.swapped ? '0% used 5h · 4% used wk' : '96% used 47m'
|
||||
return (
|
||||
<div
|
||||
className="absolute bottom-[22px] left-1/2 flex -translate-x-1/2 items-center gap-3.5 rounded-lg border border-border bg-muted/60 px-3.5 py-1.5 text-[11px] shadow-[0_1px_2px_rgba(24,24,27,0.04)]"
|
||||
|
|
@ -308,12 +310,12 @@ function BottomBar(props: { swapped: boolean }): JSX.Element {
|
|||
<div className="inline-flex items-center gap-1.5 font-mono text-[10.5px] text-muted-foreground">
|
||||
<ClaudeIcon size={12} />
|
||||
<span className="block h-1 w-9 overflow-hidden rounded-full bg-foreground/[0.12]">
|
||||
<span className="block h-full rounded-full bg-emerald-500" style={{ width: '71%' }} />
|
||||
<span className="block h-full rounded-full bg-emerald-500" style={{ width: '29%' }} />
|
||||
</span>
|
||||
<span>
|
||||
{translate(
|
||||
'auto.components.feature.wall.agents.orchestration.UsagePage.64265cb295',
|
||||
'71% 5h'
|
||||
'29% used 5h'
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import {
|
|||
ProviderIcon,
|
||||
ProviderPanel,
|
||||
barColor,
|
||||
clampUsedPercent,
|
||||
formatResetCreditExpiry,
|
||||
getProviderUsageStatusLabel
|
||||
} from './tooltip'
|
||||
|
|
@ -932,15 +933,15 @@ function ClaudeSwitcherMenu({
|
|||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mini progress bar (shows remaining capacity, grey)
|
||||
// Mini progress bar (shows consumption / % used, grey)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function MiniBar({ leftPct }: { leftPct: number }): React.JSX.Element {
|
||||
function MiniBar({ usedPct }: { usedPct: number }): React.JSX.Element {
|
||||
return (
|
||||
<div className="w-[48px] h-[6px] rounded-full bg-muted overflow-hidden flex-shrink-0">
|
||||
<div
|
||||
className="h-full rounded-full transition-all duration-300 bg-muted-foreground/40"
|
||||
style={{ width: `${Math.min(100, Math.max(0, leftPct))}%` }}
|
||||
style={{ width: `${clampUsedPercent(usedPct)}%` }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -957,29 +958,32 @@ export function InlineUsageBars({
|
|||
limits: ProviderRateLimits
|
||||
isFetching: boolean
|
||||
}): React.JSX.Element {
|
||||
// Why: show % used (consumption), not remaining — matches harness meters (#7551).
|
||||
// Keep the "used" word in compact labels so bare "32% 5h" is not read as remaining.
|
||||
const usedSuffix = translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')
|
||||
const usageWindows = [
|
||||
limits.session
|
||||
? {
|
||||
key: 'session',
|
||||
left: Math.max(0, Math.round(100 - limits.session.usedPercent)),
|
||||
label: translate('auto.components.status.bar.StatusBar.d79c3362c4', '% 5h')
|
||||
used: clampUsedPercent(limits.session.usedPercent),
|
||||
label: translate('auto.components.status.bar.StatusBar.d79c3362c4', '5h')
|
||||
}
|
||||
: null,
|
||||
limits.weekly
|
||||
? {
|
||||
key: 'weekly',
|
||||
left: Math.max(0, Math.round(100 - limits.weekly.usedPercent)),
|
||||
label: translate('auto.components.status.bar.StatusBar.5c938d39ac', '% wk')
|
||||
used: clampUsedPercent(limits.weekly.usedPercent),
|
||||
label: translate('auto.components.status.bar.StatusBar.5c938d39ac', 'wk')
|
||||
}
|
||||
: null,
|
||||
limits.fableWeekly
|
||||
? {
|
||||
key: 'fableWeekly',
|
||||
left: Math.max(0, Math.round(100 - limits.fableWeekly.usedPercent)),
|
||||
label: translate('auto.components.status.bar.StatusBar.54e8d6bb2d', '% Fable')
|
||||
used: clampUsedPercent(limits.fableWeekly.usedPercent),
|
||||
label: translate('auto.components.status.bar.StatusBar.54e8d6bb2d', 'Fable')
|
||||
}
|
||||
: null
|
||||
].filter((window): window is { key: string; left: number; label: string } => window !== null)
|
||||
].filter((window): window is { key: string; used: number; label: string } => window !== null)
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -992,13 +996,13 @@ export function InlineUsageBars({
|
|||
<div key={window.key} className="flex min-w-0 items-center gap-1">
|
||||
<div className="h-[4px] min-w-0 flex-1 overflow-hidden rounded-full bg-muted">
|
||||
<div
|
||||
className={`h-full rounded-full ${barColor(window.left)}`}
|
||||
style={{ width: `${window.left}%` }}
|
||||
className={`h-full rounded-full ${barColor(window.used)}`}
|
||||
style={{ width: `${window.used}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className="shrink-0 text-[10px] tabular-nums text-muted-foreground">
|
||||
{window.left}
|
||||
{window.label}
|
||||
{window.used}
|
||||
{usedSuffix} {window.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -1071,14 +1075,16 @@ function InlineUsageSkeleton(): React.JSX.Element {
|
|||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Window label (shows percent remaining)
|
||||
// Window label (shows percent used / consumption)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function WindowLabel({ w, label }: { w: RateLimitWindow; label: string }): React.JSX.Element {
|
||||
const left = Math.max(0, Math.round(100 - w.usedPercent))
|
||||
const used = clampUsedPercent(w.usedPercent)
|
||||
// Why: "32% 5h" is ambiguous after the remaining→used flip; keep "used" explicit.
|
||||
return (
|
||||
<span className="tabular-nums">
|
||||
{left}% {label}
|
||||
{used}
|
||||
{translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')} {label}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
@ -1150,12 +1156,13 @@ function ProviderSegment({
|
|||
<span className="inline-flex items-center gap-1.5">
|
||||
<ProviderIcon provider={provider} />
|
||||
{visibleBuckets.map((bucket, i) => {
|
||||
const left = Math.max(0, Math.round(100 - bucket.usedPercent))
|
||||
const used = clampUsedPercent(bucket.usedPercent)
|
||||
return (
|
||||
<React.Fragment key={bucket.name}>
|
||||
{i > 0 && <span className="text-muted-foreground">·</span>}
|
||||
<span className="tabular-nums">
|
||||
{bucket.name} {left}%
|
||||
{bucket.name} {used}
|
||||
{translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')}
|
||||
</span>
|
||||
</React.Fragment>
|
||||
)
|
||||
|
|
@ -1195,7 +1202,7 @@ function ProviderSegment({
|
|||
return (
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<ProviderIcon provider={provider} />
|
||||
{p.session && !compact && <MiniBar leftPct={Math.max(0, 100 - p.session.usedPercent)} />}
|
||||
{p.session && !compact && <MiniBar usedPct={clampUsedPercent(p.session.usedPercent)} />}
|
||||
{visibleWindows.map((window, index) => (
|
||||
<React.Fragment key={window.key}>
|
||||
{index > 0 && <span className="text-muted-foreground">·</span>}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,9 @@ describe('InlineUsageBars', () => {
|
|||
<InlineUsageBars limits={claudeLimits()} isFetching={false} />
|
||||
)
|
||||
|
||||
expect(markup).toContain('68% 5h')
|
||||
expect(markup).toContain('84% wk')
|
||||
expect(markup).toContain('58% Fable')
|
||||
// Why: bars show % used with explicit "used" so compact labels are not ambiguous.
|
||||
expect(markup).toContain('32% used 5h')
|
||||
expect(markup).toContain('16% used wk')
|
||||
expect(markup).toContain('42% used Fable')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ vi.mock('./tooltip', () => ({
|
|||
ProviderPanel: function ProviderPanel(props: Record<string, unknown>) {
|
||||
return { type: 'ProviderPanel', props }
|
||||
},
|
||||
barColor: () => 'bg-green-500'
|
||||
barColor: () => 'bg-green-500',
|
||||
clampUsedPercent: (n: number) => Math.max(0, Math.min(100, Math.round(n)))
|
||||
}))
|
||||
|
||||
vi.mock('@/components/ui/dropdown-menu', () => ({
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ vi.mock('@/i18n/i18n', () => ({
|
|||
}))
|
||||
|
||||
import {
|
||||
barColor,
|
||||
clampUsedPercent,
|
||||
formatResetCreditExpiry,
|
||||
formatResetCountdown,
|
||||
getProviderUsageErrorMessage,
|
||||
|
|
@ -409,7 +411,7 @@ describe('ProviderPanel reset rendering', () => {
|
|||
expect(markup).toContain('Resets in 6d 17h')
|
||||
})
|
||||
|
||||
it('renders MiniMax session as `100 - usedPercent` left so the value matches the bar', () => {
|
||||
it('renders MiniMax session as usedPercent so the value matches the bar', () => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date(2026, 6, 4, 15, 0))
|
||||
const p = provider({
|
||||
|
|
@ -425,14 +427,13 @@ describe('ProviderPanel reset rendering', () => {
|
|||
|
||||
const markup = renderToStaticMarkup(ProviderPanel({ p }))
|
||||
|
||||
// Why: the bar reads "65% 5h"; the tooltip must read "65% left" from the
|
||||
// same source field so the two views stay consistent.
|
||||
expect(markup).toContain('65%')
|
||||
expect(markup).toContain('% left')
|
||||
expect(markup).not.toContain('100% left')
|
||||
// Why: bars show consumption (% used), matching harness meters (#7551).
|
||||
expect(markup).toContain('35%')
|
||||
expect(markup).toContain('% used')
|
||||
expect(markup).not.toContain('% left')
|
||||
})
|
||||
|
||||
it('clamps MiniMax session to 0% left when usedPercent reports 100', () => {
|
||||
it('clamps MiniMax session to 100% used when usedPercent reports 100', () => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date(2026, 6, 4, 15, 0))
|
||||
const p = provider({
|
||||
|
|
@ -448,7 +449,52 @@ describe('ProviderPanel reset rendering', () => {
|
|||
|
||||
const markup = renderToStaticMarkup(ProviderPanel({ p }))
|
||||
|
||||
expect(markup).toContain('0% left')
|
||||
expect(markup).toContain('100%')
|
||||
expect(markup).toContain('% used')
|
||||
})
|
||||
|
||||
it('clamps over-100 usedPercent to 100% used in the panel', () => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date(2026, 6, 4, 15, 0))
|
||||
const p = provider({
|
||||
provider: 'minimax',
|
||||
status: 'ok',
|
||||
session: {
|
||||
usedPercent: 140,
|
||||
windowMinutes: 300,
|
||||
resetsAt: Date.now() + 2 * 60 * 60_000,
|
||||
resetDescription: null
|
||||
}
|
||||
})
|
||||
|
||||
const markup = renderToStaticMarkup(ProviderPanel({ p }))
|
||||
|
||||
expect(markup).toContain('100%')
|
||||
expect(markup).toContain('width:100%')
|
||||
expect(markup).not.toContain('140%')
|
||||
})
|
||||
})
|
||||
|
||||
describe('clampUsedPercent', () => {
|
||||
it('rounds and clamps into 0–100', () => {
|
||||
expect(clampUsedPercent(-3)).toBe(0)
|
||||
expect(clampUsedPercent(32.4)).toBe(32)
|
||||
expect(clampUsedPercent(32.6)).toBe(33)
|
||||
expect(clampUsedPercent(100)).toBe(100)
|
||||
expect(clampUsedPercent(140)).toBe(100)
|
||||
})
|
||||
})
|
||||
|
||||
describe('barColor', () => {
|
||||
// Why: thresholds are on % used (consumption). Guard against flipping back
|
||||
// to remaining-based colors without noticing.
|
||||
it('maps used percent to green / yellow / red bands', () => {
|
||||
expect(barColor(0)).toBe('bg-green-500')
|
||||
expect(barColor(59)).toBe('bg-green-500')
|
||||
expect(barColor(60)).toBe('bg-yellow-500')
|
||||
expect(barColor(79)).toBe('bg-yellow-500')
|
||||
expect(barColor(80)).toBe('bg-red-500')
|
||||
expect(barColor(100)).toBe('bg-red-500')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -191,13 +191,19 @@ export function getWindowSections(
|
|||
// `text-background` for primary text and `text-background/50` for secondary
|
||||
// to stay readable inside the inverted tooltip container.
|
||||
|
||||
// Why: color-coded by remaining capacity so users can quickly gauge urgency.
|
||||
// Green = comfortable (>40% left), yellow = caution (20-40%), red = critical (<20%).
|
||||
export function barColor(leftPct: number): string {
|
||||
if (leftPct > 40) {
|
||||
// Why: single clamp for bar width + label so status bar and tooltip never diverge.
|
||||
export function clampUsedPercent(usedPercent: number): number {
|
||||
return Math.max(0, Math.min(100, Math.round(usedPercent)))
|
||||
}
|
||||
|
||||
// Why: color-coded by consumption so users can quickly gauge urgency.
|
||||
// Matches common harness usage meters (Claude/Codex): bars fill with % used.
|
||||
// Green = comfortable (<60% used), yellow = caution (60-80%), red = critical (≥80%).
|
||||
export function barColor(usedPct: number): string {
|
||||
if (usedPct < 60) {
|
||||
return 'bg-green-500'
|
||||
}
|
||||
if (leftPct > 20) {
|
||||
if (usedPct < 80) {
|
||||
return 'bg-yellow-500'
|
||||
}
|
||||
return 'bg-red-500'
|
||||
|
|
@ -282,7 +288,9 @@ export function ProviderPanel({
|
|||
if (!w) {
|
||||
return null
|
||||
}
|
||||
const leftPct = Math.max(0, Math.round(100 - w.usedPercent))
|
||||
// Why: show % used (consumption), not remaining — matches Claude/Codex
|
||||
// harness meters and avoids the "full green bar = exhausted" misread (#7551).
|
||||
const usedPct = clampUsedPercent(w.usedPercent)
|
||||
const resetLabel = w.resetsAt ? formatResetCountdown(w.resetsAt - Date.now()) : null
|
||||
|
||||
return (
|
||||
|
|
@ -290,14 +298,14 @@ export function ProviderPanel({
|
|||
<div className={`font-medium ${textClass}`}>{label}</div>
|
||||
<div className={`h-[6px] w-full overflow-hidden rounded-full ${emptyBarClass}`}>
|
||||
<div
|
||||
className={`h-full rounded-full ${barColor(leftPct)} transition-all duration-300`}
|
||||
style={{ width: `${Math.min(100, Math.max(0, leftPct))}%` }}
|
||||
className={`h-full rounded-full ${barColor(usedPct)} transition-all duration-300`}
|
||||
style={{ width: `${usedPct}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className={`flex justify-between ${mutedClass}`}>
|
||||
<span>
|
||||
{leftPct}
|
||||
{translate('auto.components.status.bar.tooltip.cedb7b99e3', '% left')}
|
||||
{usedPct}
|
||||
{translate('auto.components.status.bar.tooltip.cedb7b99e3', '% used')}
|
||||
</span>
|
||||
{resetLabel && <span>{resetLabel}</span>}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2999,9 +2999,9 @@
|
|||
"2483c60695": "···",
|
||||
"c35af53b73": "Sign in",
|
||||
"f19a63e7cd": "Sign in to see usage",
|
||||
"5c938d39ac": "% wk",
|
||||
"54e8d6bb2d": "% Fable",
|
||||
"d79c3362c4": "% 5h",
|
||||
"5c938d39ac": "wk",
|
||||
"54e8d6bb2d": "Fable",
|
||||
"d79c3362c4": "5h",
|
||||
"a79c64f87e": "Fable",
|
||||
"8295903d17": "Restart live Claude terminals before continuing old conversations after switching.",
|
||||
"c98ea88392": "No other accounts",
|
||||
|
|
@ -3169,7 +3169,7 @@
|
|||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cedb7b99e3": "% left",
|
||||
"cedb7b99e3": "% used",
|
||||
"6d6df77f41": "No data available",
|
||||
"7f7f208060": "Monthly",
|
||||
"252c096536": "Weekly",
|
||||
|
|
@ -10996,11 +10996,11 @@
|
|||
"945865332e": "Signing in"
|
||||
},
|
||||
"UsagePage": {
|
||||
"64265cb295": "71% 5h",
|
||||
"64265cb295": "29% used 5h",
|
||||
"be5a165875": "Switch to",
|
||||
"277a9c65a9": "Codex Account",
|
||||
"4dce5ca3aa": "Resets in 4d 3h",
|
||||
"05ce4ecdd3": "62% left",
|
||||
"05ce4ecdd3": "38% used",
|
||||
"0470aaed99": "Weekly",
|
||||
"f421abf962": "Session",
|
||||
"5e45fb1238": "Updated 1m ago",
|
||||
|
|
|
|||
|
|
@ -2999,9 +2999,9 @@
|
|||
"2483c60695": "···",
|
||||
"c35af53b73": "Iniciar sesión",
|
||||
"f19a63e7cd": "Inicia sesión para ver el uso",
|
||||
"5c938d39ac": "% semana",
|
||||
"54e8d6bb2d": "% Fable",
|
||||
"d79c3362c4": "% 5h",
|
||||
"5c938d39ac": "semana",
|
||||
"54e8d6bb2d": "Fable",
|
||||
"d79c3362c4": "5h",
|
||||
"a79c64f87e": "Fable",
|
||||
"8295903d17": "Reinicia los terminales Claude activos antes de continuar conversaciones antiguas después de cambiar.",
|
||||
"c98ea88392": "Ninguna otra cuenta",
|
||||
|
|
@ -3169,7 +3169,7 @@
|
|||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cedb7b99e3": "% restante",
|
||||
"cedb7b99e3": "% usado",
|
||||
"6d6df77f41": "No hay datos disponibles",
|
||||
"7f7f208060": "Mensual",
|
||||
"252c096536": "Semanal",
|
||||
|
|
@ -10996,11 +10996,11 @@
|
|||
"945865332e": "Iniciando sesión"
|
||||
},
|
||||
"UsagePage": {
|
||||
"64265cb295": "71% 5h",
|
||||
"64265cb295": "29% usado 5h",
|
||||
"be5a165875": "Cambiar a",
|
||||
"277a9c65a9": "Cuenta de Codex",
|
||||
"4dce5ca3aa": "Se restablece en 4d 3h",
|
||||
"05ce4ecdd3": "62% restante",
|
||||
"05ce4ecdd3": "38% usado",
|
||||
"0470aaed99": "Semanal",
|
||||
"f421abf962": "Sesión",
|
||||
"5e45fb1238": "Actualizado hace 1 min",
|
||||
|
|
|
|||
|
|
@ -2999,9 +2999,9 @@
|
|||
"2483c60695": "・・・",
|
||||
"c35af53b73": "サインイン",
|
||||
"f19a63e7cd": "サインインして使用状況を確認する",
|
||||
"5c938d39ac": "%週",
|
||||
"54e8d6bb2d": "% Fable",
|
||||
"d79c3362c4": "% 5時間",
|
||||
"5c938d39ac": "週",
|
||||
"54e8d6bb2d": "Fable",
|
||||
"d79c3362c4": "5時間",
|
||||
"a79c64f87e": "Fable",
|
||||
"8295903d17": "切り替え後に古い会話を続ける前に、ライブ Claude terminals を再起動します。",
|
||||
"c98ea88392": "他のアカウントはありません",
|
||||
|
|
@ -3169,7 +3169,7 @@
|
|||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cedb7b99e3": "% 左",
|
||||
"cedb7b99e3": "% 使用",
|
||||
"6d6df77f41": "利用可能なデータがありません",
|
||||
"7f7f208060": "毎月",
|
||||
"252c096536": "毎週",
|
||||
|
|
@ -10996,11 +10996,11 @@
|
|||
"945865332e": "サインインする"
|
||||
},
|
||||
"UsagePage": {
|
||||
"64265cb295": "71% 5時間",
|
||||
"64265cb295": "29% 使用 5時間",
|
||||
"be5a165875": "に切り替えます",
|
||||
"277a9c65a9": "Codex アカウント",
|
||||
"4dce5ca3aa": "4d 3h でリセット",
|
||||
"05ce4ecdd3": "62%残っています",
|
||||
"05ce4ecdd3": "38%使用",
|
||||
"0470aaed99": "毎週",
|
||||
"f421abf962": "セッション",
|
||||
"5e45fb1238": "1分前に更新されました",
|
||||
|
|
|
|||
|
|
@ -2999,9 +2999,9 @@
|
|||
"2483c60695": "···",
|
||||
"c35af53b73": "로그인",
|
||||
"f19a63e7cd": "사용량을 보려면 로그인하세요.",
|
||||
"5c938d39ac": "%주간",
|
||||
"54e8d6bb2d": "% Fable",
|
||||
"d79c3362c4": "% 5h",
|
||||
"5c938d39ac": "주간",
|
||||
"54e8d6bb2d": "Fable",
|
||||
"d79c3362c4": "5h",
|
||||
"a79c64f87e": "Fable",
|
||||
"8295903d17": "전환 후 이전 대화를 계속하기 전에 라이브 Claude terminals을 다시 시작하십시오.",
|
||||
"c98ea88392": "다른 계정 없음",
|
||||
|
|
@ -3169,7 +3169,7 @@
|
|||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cedb7b99e3": "% 남음",
|
||||
"cedb7b99e3": "% 사용",
|
||||
"6d6df77f41": "데이터가 없습니다",
|
||||
"7f7f208060": "월간",
|
||||
"252c096536": "주간",
|
||||
|
|
@ -10996,11 +10996,11 @@
|
|||
"945865332e": "로그인 중"
|
||||
},
|
||||
"UsagePage": {
|
||||
"64265cb295": "71% 5시간",
|
||||
"64265cb295": "29% 사용 5시간",
|
||||
"be5a165875": "다음으로 전환",
|
||||
"277a9c65a9": "Codex 계정",
|
||||
"4dce5ca3aa": "4일 3시간 후에 재설정됩니다.",
|
||||
"05ce4ecdd3": "62% 남음",
|
||||
"05ce4ecdd3": "38% 사용",
|
||||
"0470aaed99": "주간",
|
||||
"f421abf962": "세션",
|
||||
"5e45fb1238": "1분 전에 업데이트됨",
|
||||
|
|
|
|||
|
|
@ -2999,9 +2999,9 @@
|
|||
"2483c60695": "···",
|
||||
"c35af53b73": "登录",
|
||||
"f19a63e7cd": "登录查看使用情况",
|
||||
"5c938d39ac": "% 周",
|
||||
"54e8d6bb2d": "% Fable",
|
||||
"d79c3362c4": "% 5小时",
|
||||
"5c938d39ac": "周",
|
||||
"54e8d6bb2d": "Fable",
|
||||
"d79c3362c4": "5小时",
|
||||
"a79c64f87e": "Fable",
|
||||
"8295903d17": "切换后继续旧对话之前,请重新启动实时 Claude 终端。",
|
||||
"c98ea88392": "没有其他账户",
|
||||
|
|
@ -3169,7 +3169,7 @@
|
|||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cedb7b99e3": "剩余 %",
|
||||
"cedb7b99e3": "% 已用",
|
||||
"6d6df77f41": "无可用数据",
|
||||
"7f7f208060": "每月",
|
||||
"252c096536": "每周",
|
||||
|
|
@ -10996,11 +10996,11 @@
|
|||
"945865332e": "登录"
|
||||
},
|
||||
"UsagePage": {
|
||||
"64265cb295": "71% 5小时",
|
||||
"64265cb295": "29% 已用 5小时",
|
||||
"be5a165875": "切换到",
|
||||
"277a9c65a9": "Codex 账户",
|
||||
"4dce5ca3aa": "4d 3h后重置",
|
||||
"05ce4ecdd3": "还剩 62%",
|
||||
"05ce4ecdd3": "已用 38%",
|
||||
"0470aaed99": "每周",
|
||||
"f421abf962": "会话",
|
||||
"5e45fb1238": "更新于 1 分钟前",
|
||||
|
|
|
|||
Loading…
Reference in New Issue