diff --git a/apps/web/src/components/usage/UsageLimitsPooled.tsx b/apps/web/src/components/usage/UsageLimitsPooled.tsx index d99ce30b475c..e8543ff9dd31 100644 --- a/apps/web/src/components/usage/UsageLimitsPooled.tsx +++ b/apps/web/src/components/usage/UsageLimitsPooled.tsx @@ -121,6 +121,37 @@ function AccountName({ ); } +/** + * " · ", so two accounts on one provider are told apart by + * the name their owner gave them. An account with no name of its own would + * render the provider label twice, so it keeps the provider label alone. + */ +function PoolRowName({ + account, + providerLabel, + className, +}: { + readonly account: LimitAccount; + readonly providerLabel: string; + readonly className?: string; +}) { + // An unnamed instance carries the provider's own name, which would print twice. + const named = account.displayName + ? account.displayName.toLowerCase() !== providerLabel.toLowerCase() + : account.email !== undefined; + return ( + + {providerLabel} + {named ? ( + <> + · + + + ) : null} + + ); +} + function Row({ label, children }: { readonly label: string; readonly children: ReactNode }) { return (
@@ -224,6 +255,7 @@ function SegmentPopover({ */ function PoolSegment({ account, + providerLabel, window, reset, color, @@ -232,6 +264,7 @@ function PoolSegment({ showAccountName, }: { readonly account: LimitAccount; + readonly providerLabel: string; readonly window: LimitPoolMember["window"]; readonly reset: LimitPoolWindow["resets"][number] | undefined; readonly color: string; @@ -246,68 +279,79 @@ function PoolSegment({ const credits = account.limits.resetCredits?.availableCount ?? 0; return ( - - } - > - {/* Translucent so the label reads over the fill for any provider colour and theme. */} -
- {/* The spent share is hatched, not blank: it is what the countdown restores. */} - {remaining < 100 && reset ? ( +
+ + } + > + {/* Translucent so the label reads over the fill for any provider colour and theme. */}
- ) : null} - - {index} - -
- {showAccountName ? ( - ) : null} - {remaining}% - {/* Countdown and badge get their own plate: fill and hatching run under them otherwise. */} - - {resetsIn?.replace("resets in ", "↻ ") ?? ""} - {credits ? ( - <> - {resetsIn ? ( - - · - - ) : null} - - - {credits} - - - ) : null} + + {index} -
- - +
+ {showAccountName ? ( + + ) : null} + + {remaining}% + + {/* Countdown and badge get their own plate: fill and hatching run under them otherwise. */} + + {resetsIn?.replace("resets in ", "↻ ") ?? ""} + {credits ? ( + <> + {resetsIn ? ( + + · + + ) : null} + + + {credits} + + + ) : null} + +
+ + +
{account.redeem ? ( } className="min-w-0 @2xl/pool:hidden" > @@ -369,7 +414,11 @@ function LegendRow({ Segment {index} - + {remaining}% {resetsIn?.replace("resets in ", "↻ ") ?? ""} @@ -451,35 +500,37 @@ function RedeemableSegmentPopup({ */ function PoolBar({ pool, + providerLabel, color, now, }: { readonly pool: LimitPoolWindow; + readonly providerLabel: string; readonly color: string; readonly now: number; }) { const restores = new Map(pool.resets.map((reset) => [reset.member.account.key, reset])); return ( -
-
- {pool.columns.map((member, position) => - member.window ? ( - 1} - /> - ) : null, - )} -
+
+ {pool.columns.map((member, position) => + member.window ? ( + 1} + /> + ) : ( + // The account reports nothing in this window, but keeps its place: + // a row holds the same account across every card of this provider. +
+ ), + )}
); } @@ -490,12 +541,14 @@ function PoolBar({ */ function PoolWindowCard({ pool, + providerLabel, color, now, label, description, }: { readonly pool: LimitPoolWindow; + readonly providerLabel: string; readonly color: string; readonly now: number; readonly label?: string | undefined; @@ -520,7 +573,7 @@ function PoolWindowCard({ ) : null}
- + {description ? (

{description}

) : null} @@ -550,6 +603,7 @@ function PoolSection({ pool, now }: { readonly pool: LimitPool; readonly now: nu