authorgravatar for dominic@sdko.orgDominic Roy <dominic@sdko.org> 2026-09-12 19:30:05-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-12 20:30:05-03:00
logfcbe45796aea99e9e2a9ce19dd9409fbd7e720e4
tree70b50b7a7032f64b3c1e78556b972204b077fd00
parentaf2baccd100604f9885d6af97a5fa99622dd1c4f
signature Signed by PGP key B5690EEEBB952194

fix(usage): make unavailable account limits more visible (#10601)


2 files changed, 36 insertions(+), 16 deletions(-)

apps/mobile/src/features/usage/UsageLimitsPooled.tsx+27-11
...@@ -212,12 +212,7 @@ export function UsageLimitsSection({...@@ -212,12 +212,7 @@ export function UsageLimitsSection({
212 const colors = useProviderColors();212 const colors = useProviderColors();
213 return (213 return (
214 <View className="gap-6">214 <View className="gap-6">
215 {failedLabels.length ? (215 {pools.length === 0 && notices.length === 0 && failedLabels.length === 0 ? (
216 <Text className="text-sm text-foreground-muted">
217 {failedLabels.join(", ")} could not refresh limits. Showing the last known values.
218 </Text>
219 ) : null}
220 {pools.length === 0 ? (
221 <Text className="py-12 text-center text-base text-foreground-muted">216 <Text className="py-12 text-center text-base text-foreground-muted">
222 {selected.size === 0217 {selected.size === 0
223 ? "Select an environment to see limits."218 ? "Select an environment to see limits."
...@@ -243,11 +238,32 @@ export function UsageLimitsSection({...@@ -243,11 +238,32 @@ export function UsageLimitsSection({
243 ))}238 ))}
244 </View>239 </View>
245 ))}240 ))}
246 {notices.map((notice) => (241 {notices.length > 0 || failedLabels.length > 0 ? (
247 <Text key={notice} className="text-sm text-foreground-muted">242 <View
248 {notice}243 accessible
249 </Text>244 accessibilityRole="alert"
250 ))}245 accessibilityLiveRegion="polite"
246 className="flex-row items-start gap-2 rounded-xl border border-warning-border bg-warning px-3.5 py-3"
247 >
248 <SymbolView
249 name="exclamationmark.triangle"
250 size={16}
251 tintColorClassName="accent-warning-foreground"
252 />
253 <View className="min-w-0 flex-1 gap-0.5">
254 {notices.map((notice) => (
255 <Text key={notice} className="text-sm font-t3-medium text-warning-foreground">
256 {notice}
257 </Text>
258 ))}
259 {failedLabels.length > 0 ? (
260 <Text className="text-sm font-t3-medium text-warning-foreground">
261 {failedLabels.join(", ")} could not refresh limits. Showing the last known values.
262 </Text>
263 ) : null}
264 </View>
265 </View>
266 ) : null}
251 </View>267 </View>
252 );268 );
253}269}
apps/web/src/components/usage/UsageLimitsPooled.tsx+9-5
...@@ -10,7 +10,7 @@ import {...@@ -10,7 +10,7 @@ import {
10 type LimitPoolWindow,10 type LimitPoolWindow,
11 remainingPercent,11 remainingPercent,
12} from "@t3tools/shared/usageLimits";12} from "@t3tools/shared/usageLimits";
13import { TicketIcon } from "lucide-react";13import { AlertTriangleIcon, TicketIcon } from "lucide-react";
14import { type ReactNode, useState } from "react";14import { type ReactNode, useState } from "react";
1515
16import { usePrimarySettings } from "../../hooks/useSettings";16import { usePrimarySettings } from "../../hooks/useSettings";
...@@ -20,6 +20,7 @@ import { ProviderInstanceIcon } from "../chat/ProviderInstanceIcon";...@@ -20,6 +20,7 @@ import { ProviderInstanceIcon } from "../chat/ProviderInstanceIcon";
20import { getDriverOption } from "../settings/providerDriverMeta";20import { getDriverOption } from "../settings/providerDriverMeta";
21import { RedactedSensitiveText } from "../settings/RedactedSensitiveText";21import { RedactedSensitiveText } from "../settings/RedactedSensitiveText";
22import { Button } from "../ui/button";22import { Button } from "../ui/button";
23import { Alert, AlertTitle } from "../ui/alert";
23import { Popover, PopoverPopup, PopoverTrigger } from "../ui/popover";24import { Popover, PopoverPopup, PopoverTrigger } from "../ui/popover";
24import {25import {
25 PaceIcon,26 PaceIcon,
...@@ -545,7 +546,7 @@ export function UsageLimitsPooled({...@@ -545,7 +546,7 @@ export function UsageLimitsPooled({
545 const notices = collectLimitNotices(presentations);546 const notices = collectLimitNotices(presentations);
546 return (547 return (
547 <div className="flex flex-col gap-8">548 <div className="flex flex-col gap-8">
548 {pools.length === 0 ? (549 {pools.length === 0 && notices.length === 0 ? (
549 <p className="text-sm text-muted-foreground">550 <p className="text-sm text-muted-foreground">
550 No provider on the selected environments reports subscription limits.551 No provider on the selected environments reports subscription limits.
551 </p>552 </p>
...@@ -562,10 +563,13 @@ export function UsageLimitsPooled({...@@ -562,10 +563,13 @@ export function UsageLimitsPooled({
562function LimitNotices({ notices }: { readonly notices: readonly string[] }) {563function LimitNotices({ notices }: { readonly notices: readonly string[] }) {
563 if (notices.length === 0) return null;564 if (notices.length === 0) return null;
564 return (565 return (
565 <ul className="flex flex-col gap-1 text-xs text-muted-foreground">566 <Alert variant="warning" controlAlignment="first-line">
567 <AlertTriangleIcon />
566 {notices.map((notice) => (568 {notices.map((notice) => (
567 <li key={notice}>{notice}</li>569 <AlertTitle key={notice} className="break-words">
570 {notice}
571 </AlertTitle>
568 ))}572 ))}
569 </ul>573 </Alert>
570 );574 );
571}575}