Skip to content

Commit 40e68a9

Browse files
committed
feat(accounts): show error tooltip on status badge hover
Hover the unauthorized/error status badge to reveal the full error message in a tooltip styled like the usage log status code popover.
1 parent cb4ab16 commit 40e68a9

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

frontend/src/components/StatusBadge.tsx

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Badge } from '@/components/ui/badge'
2+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
23
import { useTranslation } from 'react-i18next'
34

45
interface StatusBadgeProps {
56
status?: string | null
67
detail?: string | null
8+
errorMessage?: string | null
79
}
810

911
const statusConfig: Record<string, { variant: 'default' | 'secondary' | 'destructive' | 'outline'; dotColor: string }> = {
@@ -18,13 +20,18 @@ const statusConfig: Record<string, { variant: 'default' | 'secondary' | 'destruc
1820
paused: { variant: 'outline', dotColor: 'bg-blue-500' },
1921
}
2022

21-
export default function StatusBadge({ status, detail }: StatusBadgeProps) {
23+
export default function StatusBadge({ status, detail, errorMessage }: StatusBadgeProps) {
2224
const { t } = useTranslation()
2325
const key = status ?? 'unknown'
2426
const config = statusConfig[key] ?? { variant: 'outline' as const, dotColor: 'bg-gray-400' }
27+
const trimmedError = errorMessage?.trim() ?? ''
28+
const showErrorTooltip = key === 'unauthorized' || key === 'error'
2529

26-
return (
27-
<Badge variant={config.variant} className="gap-1.5 text-[13px]">
30+
const badge = (
31+
<Badge
32+
variant={config.variant}
33+
className={`gap-1.5 text-[13px] ${showErrorTooltip ? 'cursor-help ring-1 ring-inset ring-current/10' : ''}`}
34+
>
2835
<span className={`size-1.5 rounded-full ${config.dotColor}`} />
2936
{t(`status.${key}`, { defaultValue: t('status.unknown', { defaultValue: key }) })}
3037
{detail && (
@@ -35,4 +42,36 @@ export default function StatusBadge({ status, detail }: StatusBadgeProps) {
3542
)}
3643
</Badge>
3744
)
45+
46+
if (!showErrorTooltip) {
47+
return badge
48+
}
49+
50+
const message = trimmedError || t('usage.statusErrorEmpty')
51+
52+
return (
53+
<TooltipProvider>
54+
<Tooltip>
55+
<TooltipTrigger asChild>
56+
<span
57+
tabIndex={0}
58+
aria-label={message}
59+
className="inline-flex focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
60+
>
61+
{badge}
62+
</span>
63+
</TooltipTrigger>
64+
<TooltipContent
65+
side="right"
66+
sideOffset={8}
67+
className="max-w-[360px] rounded-lg border border-slate-700 bg-slate-950 px-3 py-2.5 text-xs text-slate-50 shadow-xl"
68+
>
69+
<div className="space-y-1.5">
70+
<div className="font-semibold text-slate-300">{t('usage.statusErrorDetails')}</div>
71+
<div className="whitespace-pre-wrap break-words leading-relaxed text-slate-50">{message}</div>
72+
</div>
73+
</TooltipContent>
74+
</Tooltip>
75+
</TooltipProvider>
76+
)
3877
}

frontend/src/pages/Accounts.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3074,6 +3074,7 @@ export default function Accounts() {
30743074
getAccountRateLimitWindow(account) ??
30753075
undefined
30763076
}
3077+
errorMessage={account.error_message}
30773078
/>
30783079
<AccountStatusCountdown account={account} />
30793080
</div>
@@ -6124,6 +6125,7 @@ function AccountMobileCard({
61246125
<StatusBadge
61256126
status={account.status}
61266127
detail={getAccountRateLimitWindow(account) ?? undefined}
6128+
errorMessage={account.error_message}
61276129
/>
61286130
</div>
61296131
</div>

0 commit comments

Comments
 (0)