fix(frontend): wrong usage, tooltips, ...

This commit is contained in:
Alois 2026-08-30 11:58:15 +02:00
commit 3db5ec25c2
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
2 changed files with 59 additions and 43 deletions

View file

@ -317,8 +317,13 @@ func (h *Handler) RequestCodexToken(c *gin.Context) {
FileName: fileName, FileName: fileName,
Storage: tokenStorage, Storage: tokenStorage,
Metadata: map[string]any{ Metadata: map[string]any{
"email": tokenStorage.Email, "email": tokenStorage.Email,
"account_id": tokenStorage.AccountID, "account_id": tokenStorage.AccountID,
"access_token": tokenStorage.AccessToken,
"refresh_token": tokenStorage.RefreshToken,
"id_token": tokenStorage.IDToken,
"expired": tokenStorage.Expire,
"last_refresh": tokenStorage.LastRefresh,
}, },
} }
if errGuard := guardOAuthSessionPendingForSave(state, "codex"); errGuard != nil { if errGuard := guardOAuthSessionPendingForSave(state, "codex"); errGuard != nil {

View file

@ -32,26 +32,23 @@ import {
Spinner, Spinner,
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider,
TooltipTrigger, TooltipTrigger,
useTheme, useTheme,
} from '@methanium/ui'; } from '@methanium/ui';
import { import {
AlertTriangle, AlertTriangle,
Check, Check,
CheckCircle2,
Clock3, Clock3,
ExternalLink, ExternalLink,
Eye, Eye,
EyeClosed,
EyeOff, EyeOff,
EyeOffIcon,
KeyRound, KeyRound,
LogOut, LogOut,
Moon, Moon,
Plus, Plus,
RefreshCw, RefreshCw,
ShieldAlert, ShieldAlert,
Star,
Sun, Sun,
Trash2, Trash2,
UserRound, UserRound,
@ -101,6 +98,21 @@ function titleFromKey(key: string) {
return key.replace(/[_-]+/g, ' ').replace(/\b\w/g, (letter) => letter.toUpperCase()); return key.replace(/[_-]+/g, ' ').replace(/\b\w/g, (letter) => letter.toUpperCase());
} }
function quotaWindowLabel(record: Record<string, unknown>, key: string) {
const rawSeconds =
record.limit_window_seconds ?? record.limitWindowSeconds ?? record.window_seconds;
if (typeof rawSeconds === 'number') {
if (rawSeconds === 5 * 60 * 60) return '5-hour limit';
if (rawSeconds === 7 * 24 * 60 * 60) return 'Weekly limit';
const days = rawSeconds / 86400;
if (Number.isInteger(days)) return `${days}-day limit`;
const hours = rawSeconds / 3600;
if (Number.isInteger(hours)) return `${hours}-hour limit`;
}
return titleFromKey(key);
}
function quotaWindows(data: unknown) { function quotaWindows(data: unknown) {
const windows: Array<{ const windows: Array<{
key: string; key: string;
@ -119,7 +131,7 @@ function quotaWindows(data: unknown) {
const rawResetAfter = record.reset_after_seconds ?? record.resetAfterSeconds; const rawResetAfter = record.reset_after_seconds ?? record.resetAfterSeconds;
windows.push({ windows.push({
key, key,
label: titleFromKey(path[path.length - 1] || 'Usage'), label: quotaWindowLabel(record, path[path.length - 1] || 'Usage'),
usedPercent: Math.max(0, Math.min(100, used)), usedPercent: Math.max(0, Math.min(100, used)),
resetAt: typeof rawResetAt === 'number' ? rawResetAt : undefined, resetAt: typeof rawResetAt === 'number' ? rawResetAt : undefined,
resetAfterSeconds: typeof rawResetAfter === 'number' ? rawResetAfter : undefined, resetAfterSeconds: typeof rawResetAfter === 'number' ? rawResetAfter : undefined,
@ -302,22 +314,17 @@ function AccountCard({
<CardTitle className="flex min-w-0 items-center gap-2"> <CardTitle className="flex min-w-0 items-center gap-2">
<UserRound className="size-4 shrink-0" /> <UserRound className="size-4 shrink-0" />
{emailHidden ? ( {emailHidden ? (
<Tooltip> <code className="truncate">
<TooltipTrigger className="truncate"> {Array.from({ length: (identity || account.name).length }).map((_, index) => (
<code> <span key={index}>*</span>
{Array.from({ length: (identity || account.name).length }).map((_, index) => ( ))}
<span key={index}>*</span> </code>
))}
</code>
</TooltipTrigger>
<TooltipContent className="truncate">{account.name}</TooltipContent>
</Tooltip>
) : ( ) : (
<Tooltip> <Tooltip>
<TooltipTrigger className="truncate"> <TooltipTrigger
<code>{identity || account.name}</code> render={<code className="truncate">{identity || account.name}</code>}
</TooltipTrigger> />
<TooltipContent className="truncate">{account.name}</TooltipContent> <TooltipContent>{account.name}</TooltipContent>
</Tooltip> </Tooltip>
)} )}
<button <button
@ -392,9 +399,11 @@ function AccountCard({
<div className="space-y-4"> <div className="space-y-4">
{windows.map((window) => ( {windows.map((window) => (
<div key={window.key}> <div key={window.key}>
<Progress value={window.usedPercent}> <Progress value={100 - window.usedPercent} max={100}>
<ProgressLabel>{window.label}</ProgressLabel> <ProgressLabel>{window.label}</ProgressLabel>
<ProgressValue>{() => `${Math.round(window.usedPercent)}% used`}</ProgressValue> <ProgressValue>
{() => `${Math.round(100 - window.usedPercent)}% used`}
</ProgressValue>
</Progress> </Progress>
{resetLabel(window) && ( {resetLabel(window) && (
<div className="mt-1 text-xs text-muted-foreground">{resetLabel(window)}</div> <div className="mt-1 text-xs text-muted-foreground">{resetLabel(window)}</div>
@ -709,25 +718,27 @@ export function App() {
}; };
return ( return (
<div className="min-h-screen bg-background text-foreground"> <TooltipProvider>
<Header loggedIn={Boolean(managementKey && accounts)} onLogout={logout} /> <div className="min-h-screen bg-background text-foreground">
{!managementKey ? ( <Header loggedIn={Boolean(managementKey && accounts)} onLogout={logout} />
<Login {!managementKey ? (
onLogin={async (key) => { <Login
const trimmed = key.trim(); onLogin={async (key) => {
const files = await listAuthFiles(trimmed); const trimmed = key.trim();
sessionStorage.setItem(managementKeyStorage, trimmed); const files = await listAuthFiles(trimmed);
setManagementKey(trimmed); sessionStorage.setItem(managementKeyStorage, trimmed);
setAccounts(files); setManagementKey(trimmed);
}} setAccounts(files);
/> }}
) : accounts === null ? ( />
<main className="flex min-h-[calc(100vh-3rem)] items-center justify-center"> ) : accounts === null ? (
<Spinner className="size-5" /> <main className="flex min-h-[calc(100vh-3rem)] items-center justify-center">
</main> <Spinner className="size-5" />
) : ( </main>
<Dashboard managementKey={managementKey} initialAccounts={accounts} /> ) : (
)} <Dashboard managementKey={managementKey} initialAccounts={accounts} />
</div> )}
</div>
</TooltipProvider>
); );
} }