import type { EnvironmentId, UsageLimitsReport } from "@t3tools/contracts";import { limitsNotice } from "@t3tools/shared/usageLimits";import { GaugeIcon } from "lucide-react"; import { getDriverOption } from "../settings/providerDriverMeta";import { RedactedSensitiveText } from "../settings/RedactedSensitiveText";import { LimitWindows, ResetCredits } from "../usage/UsageLimits";import { ComposerBanner } from "./ComposerBanner";import type { ComposerBannerStackItem } from "./ComposerBannerStack"; /** Driver name, then the instance when there could be more than one of that driver. */function accountLabel(account: UsageLimitsReport["accounts"][number]): string { if (!account.instanceId) return account.label; const driver = getDriverOption(account.driver)?.label ?? String(account.driver); const instance = account.displayName?.trim() || (String(account.instanceId) !== String(account.driver) ? account.instanceId : ""); // The default instance is often named after its driver; saying it twice adds nothing. return instance && instance.toLowerCase() !== driver.toLowerCase() ? `${driver} · ${instance}` : driver;} function AccountSummary({ account }: { readonly account: UsageLimitsReport["accounts"][number] }) { const label = accountLabel(account); return ( <> {label.includes("@") ? ( <RedactedSensitiveText key={label} value={label} ariaLabel="Toggle account label visibility" revealTooltip="Click to reveal account" hideTooltip="Click to hide account" className="max-w-full truncate align-bottom font-sans text-xs leading-normal" /> ) : ( label )} {account.plan ? ` · ${account.plan}` : null} </> );} /** The /usage-limits result as a composer notice: it stacks under warnings and dismisses like one. */export function usageLimitsBannerItem( id: string, report: UsageLimitsReport, environmentId: EnvironmentId, onDismiss: () => void,): ComposerBannerStackItem { const [first] = report.accounts; const single = report.accounts.length === 1 && first ? first : null; const summary = single ? ( <AccountSummary account={single} /> ) : ( `${report.accounts.length} accounts` ); return { id, variant: "info", priority: "notice", icon: <GaugeIcon />, title: "Usage limits", description: summary, dismissLabel: "Dismiss usage limits", onDismiss, children: <UsageLimitsBannerBody report={report} environmentId={environmentId} />, };} function UsageLimitsBannerBody({ report, environmentId,}: { readonly report: UsageLimitsReport; readonly environmentId: EnvironmentId;}) { const now = Date.parse(report.createdAt); return ( <ComposerBanner.Scroll> <ComposerBanner.Body className="flex flex-col gap-2 pt-1 pb-1.5 pe-2"> {report.accounts.map((account) => { const resetCreditInput = account.resetCreditInput ?? (account.instanceId ? { instanceId: account.instanceId } : undefined); const notice = limitsNotice(account.limits); return ( <div key={account.id} className="flex min-w-0 flex-col gap-1"> {report.accounts.length > 1 ? ( <span className="truncate text-xs text-muted-foreground"> <AccountSummary account={account} /> </span> ) : null} {notice ? ( <span className="text-xs text-muted-foreground">{notice}</span> ) : ( <LimitWindows compact driver={account.driver} windows={account.limits.windows} now={now} /> )} {resetCreditInput && account.limits.resetCredits ? ( <ResetCredits environmentId={environmentId} input={resetCreditInput} credits={account.limits.resetCredits} now={now} /> ) : null} </div> ); })} {report.notices.map((notice) => ( <span key={notice} className="text-xs text-muted-foreground"> {notice} </span> ))} </ComposerBanner.Body> </ComposerBanner.Scroll> );}
import type { EnvironmentId, UsageLimitsReport } from "@t3tools/contracts";
import { limitsNotice } from "@t3tools/shared/usageLimits";
import { GaugeIcon } from "lucide-react";
import { getDriverOption } from "../settings/providerDriverMeta";
import { RedactedSensitiveText } from "../settings/RedactedSensitiveText";
import { LimitWindows, ResetCredits } from "../usage/UsageLimits";
import { ComposerBanner } from "./ComposerBanner";
import type { ComposerBannerStackItem } from "./ComposerBannerStack";
/** Driver name, then the instance when there could be more than one of that driver. */
function accountLabel(account: UsageLimitsReport["accounts"][number]): string {
if (!account.instanceId) return account.label;
const driver = getDriverOption(account.driver)?.label ?? String(account.driver);
const instance =
account.displayName?.trim() ||
(String(account.instanceId) !== String(account.driver) ? account.instanceId : "");
// The default instance is often named after its driver; saying it twice adds nothing.
return instance && instance.toLowerCase() !== driver.toLowerCase()
? `${driver} · ${instance}`
: driver;
}
function AccountSummary({ account }: { readonly account: UsageLimitsReport["accounts"][number] }) {
const label = accountLabel(account);
return (
<>
{label.includes("@") ? (
<RedactedSensitiveText
key={label}
value={label}
ariaLabel="Toggle account label visibility"
revealTooltip="Click to reveal account"
hideTooltip="Click to hide account"
className="max-w-full truncate align-bottom font-sans text-xs leading-normal"
/>
) : (
label
)}
{account.plan ? ` · ${account.plan}` : null}
</>
);
}
/** The /usage-limits result as a composer notice: it stacks under warnings and dismisses like one. */
export function usageLimitsBannerItem(
id: string,
report: UsageLimitsReport,
environmentId: EnvironmentId,
onDismiss: () => void,
): ComposerBannerStackItem {
const [first] = report.accounts;
const single = report.accounts.length === 1 && first ? first : null;
const summary = single ? (
<AccountSummary account={single} />
) : (
`${report.accounts.length} accounts`
);
return {
id,
variant: "info",
priority: "notice",
icon: <GaugeIcon />,
title: "Usage limits",
description: summary,
dismissLabel: "Dismiss usage limits",
onDismiss,
children: <UsageLimitsBannerBody report={report} environmentId={environmentId} />,
};
}
function UsageLimitsBannerBody({
report,
environmentId,
}: {
readonly report: UsageLimitsReport;
readonly environmentId: EnvironmentId;
}) {
const now = Date.parse(report.createdAt);
return (
<ComposerBanner.Scroll>
<ComposerBanner.Body className="flex flex-col gap-2 pt-1 pb-1.5 pe-2">
{report.accounts.map((account) => {
const resetCreditInput =
account.resetCreditInput ??
(account.instanceId ? { instanceId: account.instanceId } : undefined);
const notice = limitsNotice(account.limits);
return (
<div key={account.id} className="flex min-w-0 flex-col gap-1">
{report.accounts.length > 1 ? (
<span className="truncate text-xs text-muted-foreground">
<AccountSummary account={account} />
</span>
) : null}
{notice ? (
<span className="text-xs text-muted-foreground">{notice}</span>
) : (
<LimitWindows
compact
driver={account.driver}
windows={account.limits.windows}
now={now}
/>
)}
{resetCreditInput && account.limits.resetCredits ? (
<ResetCredits
environmentId={environmentId}
input={resetCreditInput}
credits={account.limits.resetCredits}
now={now}
/>
) : null}
</div>
);
})}
{report.notices.map((notice) => (
<span key={notice} className="text-xs text-muted-foreground">
{notice}
</span>
))}
</ComposerBanner.Body>
</ComposerBanner.Scroll>
);
}