@@ -160,9 +160,8 @@ export default function Accounts() {
160160
161161 const totalAccounts = accounts . length
162162 const normalAccounts = accounts . filter ( ( account ) => account . status === 'active' || account . status === 'ready' ) . length
163- const rateLimitedAccountRows = accounts . filter ( isRateLimitedAccount )
164- const rateLimitedWindowStats = getRateLimitedWindowStats ( rateLimitedAccountRows )
165- const rateLimitedAccounts = rateLimitedAccountRows . length
163+ const rateLimitedWindowStats = getRateLimitedWindowStats ( accounts )
164+ const rateLimitedAccounts = rateLimitedWindowStats . total
166165 const rateLimited5hAccounts = rateLimitedWindowStats . fiveHour
167166 const rateLimited7dAccounts = rateLimitedWindowStats . sevenDay
168167 const bannedAccounts = accounts . filter ( ( account ) => account . status === 'unauthorized' ) . length
@@ -1379,7 +1378,7 @@ export default function Accounts() {
13791378 < TableCell >
13801379 < div className = "space-y-1.5" >
13811380 < div className = "flex min-h-6 items-center gap-2 whitespace-nowrap" >
1382- < StatusBadge status = { account . status } />
1381+ < StatusBadge status = { account . status } detail = { getAccountRateLimitWindow ( account ) ?? undefined } />
13831382 < AccountStatusCountdown account = { account } />
13841383 </ div >
13851384 { account . status === 'error' && account . error_message && (
@@ -2373,59 +2372,74 @@ function isUsageWindowExhausted(value?: number | null): boolean {
23732372 return typeof value === 'number' && Number . isFinite ( value ) && value >= 100
23742373}
23752374
2375+ function isActiveUsageWindowExhausted ( value ?: number | null , resetAt ?: string ) : boolean {
2376+ return isUsageWindowExhausted ( value ) && ( ! resetAt || isFutureTime ( resetAt ) )
2377+ }
2378+
23762379function isPremiumUsagePlan ( planType ?: string ) : boolean {
23772380 return [ 'plus' , 'pro' , 'team' , 'teamplus' ] . includes ( normalizePlanType ( planType ) )
23782381}
23792382
2383+ type RateLimitWindow = '5h' | '7d'
2384+
23802385function isRateLimitedAccount ( account : AccountRow ) : boolean {
2386+ return getAccountRateLimitWindow ( account ) !== null
2387+ }
2388+
2389+ function getAccountRateLimitWindow ( account : AccountRow ) : RateLimitWindow | null {
23812390 const status = ( account . status || '' ) . toLowerCase ( )
23822391 const reason = ( account . cooldown_reason || '' ) . toLowerCase ( )
2383-
2384- return status === 'rate_limited' ||
2392+ const explicitlyRateLimited = status === 'rate_limited' ||
23852393 status === 'usage_exhausted' ||
23862394 status === 'rate_limited_5h' ||
23872395 status === 'rate_limited_7d' ||
2396+ reason === 'rate_limited' ||
23882397 reason === 'rate_limited_5h' ||
23892398 reason === 'rate_limited_7d'
2390- }
2391-
2392- function getAccountRateLimitWindow ( account : AccountRow ) : '5h' | '7d' {
2393- const status = ( account . status || '' ) . toLowerCase ( )
2394- const reason = ( account . cooldown_reason || '' ) . toLowerCase ( )
2399+ const has7dLimit = isActiveUsageWindowExhausted ( account . usage_percent_7d , account . reset_7d_at )
2400+ const has5hLimit = isPremiumUsagePlan ( account . plan_type ) &&
2401+ isActiveUsageWindowExhausted ( account . usage_percent_5h , account . reset_5h_at )
23952402
2403+ // Prefer the longer 7d window when both windows are exhausted so each account
2404+ // belongs to exactly one bucket and 5h + 7d stays equal to total limited.
23962405 if (
23972406 status === 'usage_exhausted' ||
23982407 status === 'rate_limited_7d' ||
23992408 reason === 'rate_limited_7d' ||
2400- ( isUsageWindowExhausted ( account . usage_percent_7d ) && ( ! account . reset_7d_at || isFutureTime ( account . reset_7d_at ) ) )
2409+ has7dLimit
24012410 ) {
24022411 return '7d'
24032412 }
24042413
24052414 if (
24062415 status === 'rate_limited_5h' ||
24072416 reason === 'rate_limited_5h' ||
2408- (
2409- isPremiumUsagePlan ( account . plan_type ) &&
2410- isUsageWindowExhausted ( account . usage_percent_5h ) &&
2411- ( ! account . reset_5h_at || isFutureTime ( account . reset_5h_at ) )
2412- )
2417+ has5hLimit
24132418 ) {
24142419 return '5h'
24152420 }
24162421
2417- return '5h'
2422+ return explicitlyRateLimited ? '5h' : null
24182423}
24192424
2420- function getRateLimitedWindowStats ( accounts : AccountRow [ ] ) : { fiveHour : number ; sevenDay : number } {
2421- return accounts . reduce ( ( stats , account ) => {
2422- if ( getAccountRateLimitWindow ( account ) === '7d' ) {
2425+ function getRateLimitedWindowStats ( accounts : AccountRow [ ] ) : { total : number ; fiveHour : number ; sevenDay : number } {
2426+ const stats = accounts . reduce ( ( stats , account ) => {
2427+ const window = getAccountRateLimitWindow ( account )
2428+ if ( ! window ) {
2429+ return stats
2430+ }
2431+ if ( window === '7d' ) {
24232432 stats . sevenDay += 1
24242433 } else {
24252434 stats . fiveHour += 1
24262435 }
24272436 return stats
24282437 } , { fiveHour : 0 , sevenDay : 0 } )
2438+
2439+ return {
2440+ ...stats ,
2441+ total : stats . fiveHour + stats . sevenDay ,
2442+ }
24292443}
24302444
24312445function isSubscriptionPlan ( planType ?: string ) : boolean {
@@ -2645,12 +2659,12 @@ function CompactStat({
26452659 { chipLabel ?? label }
26462660 </ div >
26472661 { details && details . length > 0 && (
2648- < div className = "flex flex-col items-end gap-0.5 text-[11px] font-semibold leading-4 text-muted-foreground" >
2662+ < div className = "flex w-[4.75rem] flex-col gap-0.5 text-[11px] font-semibold leading-4 text-muted-foreground" >
26492663 { details . map ( ( item ) => (
2650- < div key = { item . label } className = "tabular-nums" >
2651- < span > { item . label } </ span >
2652- < span className = "mx-0.5 " > :</ span >
2653- < span className = "text-foreground" > { item . value } </ span >
2664+ < div key = { item . label } className = "grid grid-cols-[2ch_auto_1fr] items-center gap-x-1 tabular-nums" >
2665+ < span className = "justify-self-start" > { item . label } </ span >
2666+ < span className = "justify-self-center " > :</ span >
2667+ < span className = "justify-self-end text-foreground" > { item . value } </ span >
26542668 </ div >
26552669 ) ) }
26562670 </ div >
0 commit comments