fix(usage): only auto-poll Copilot/ChatGPT quota for current provider

CopilotQuotaFooter and CodexOauthQuotaFooter called their hooks with a
hardcoded `enabled: true` plus an unconditional 5-minute refetch and
refetchOnWindowFocus, so non-current reverse-proxy cards kept polling
in violation of the project's "only the active provider auto-queries
on cooldown" rule. With multiple Copilot or ChatGPT accounts bound to
different cards, every card kept hitting its own usage endpoint.

Adopt the same pattern as useUsageQuery: keep `enabled` independent of
isCurrent so first-fetch and manual refresh still work, but gate
refetchInterval / refetchIntervalInBackground / refetchOnWindowFocus on
a new `autoQuery` option, and thread `isCurrent` from ProviderCard
through the footers into the hooks.
This commit is contained in:
Jason
2026-04-08 22:37:16 +08:00
parent 62fc1d9151
commit df5cb6d771
5 changed files with 43 additions and 10 deletions
+4 -1
View File
@@ -6,6 +6,8 @@ import { SubscriptionQuotaView } from "@/components/SubscriptionQuotaFooter";
interface CodexOauthQuotaFooterProps {
meta?: ProviderMeta;
inline?: boolean;
/** 是否为当前激活的供应商 */
isCurrent?: boolean;
}
/**
@@ -17,12 +19,13 @@ interface CodexOauthQuotaFooterProps {
const CodexOauthQuotaFooter: React.FC<CodexOauthQuotaFooterProps> = ({
meta,
inline = false,
isCurrent = false,
}) => {
const {
data: quota,
isFetching: loading,
refetch,
} = useCodexOauthQuota(meta, true);
} = useCodexOauthQuota(meta, { enabled: true, autoQuery: isCurrent });
return (
<SubscriptionQuotaView
+4 -1
View File
@@ -13,6 +13,8 @@ import {
interface CopilotQuotaFooterProps {
meta?: ProviderMeta;
inline?: boolean;
/** 是否为当前激活的供应商 */
isCurrent?: boolean;
}
/** 格式化相对时间 */
@@ -33,6 +35,7 @@ function formatRelativeTime(
const CopilotQuotaFooter: React.FC<CopilotQuotaFooterProps> = ({
meta,
inline = false,
isCurrent = false,
}) => {
const { t } = useTranslation();
const accountId = resolveManagedAccountId(
@@ -44,7 +47,7 @@ const CopilotQuotaFooter: React.FC<CopilotQuotaFooterProps> = ({
data: quota,
isFetching: loading,
refetch,
} = useCopilotQuota(accountId, true);
} = useCopilotQuota(accountId, { enabled: true, autoQuery: isCurrent });
const [now, setNow] = React.useState(Date.now());
React.useEffect(() => {
+10 -2
View File
@@ -357,9 +357,17 @@ export function ProviderCard({
<div className="ml-auto">
<div className="flex items-center gap-1">
{isCopilot ? (
<CopilotQuotaFooter meta={provider.meta} inline={true} />
<CopilotQuotaFooter
meta={provider.meta}
inline={true}
isCurrent={isCurrent}
/>
) : isCodexOauth ? (
<CodexOauthQuotaFooter meta={provider.meta} inline={true} />
<CodexOauthQuotaFooter
meta={provider.meta}
inline={true}
isCurrent={isCurrent}
/>
) : isOfficial ? (
<SubscriptionQuotaFooter appId={appId} inline={true} />
) : hasMultiplePlans ? (
+14 -3
View File
@@ -13,7 +13,17 @@ export interface CopilotQuota {
queriedAt: number | null;
}
export function useCopilotQuota(accountId: string | null, enabled: boolean) {
export interface UseCopilotQuotaOptions {
enabled?: boolean;
/** 是否启用自动轮询(5 分钟)与窗口 focus 重取 */
autoQuery?: boolean;
}
export function useCopilotQuota(
accountId: string | null,
options: UseCopilotQuotaOptions = {},
) {
const { enabled = true, autoQuery = false } = options;
return useQuery<CopilotQuota>({
queryKey: ["copilot", "quota", accountId ?? "default"],
queryFn: async (): Promise<CopilotQuota> => {
@@ -44,8 +54,9 @@ export function useCopilotQuota(accountId: string | null, enabled: boolean) {
};
},
enabled,
refetchInterval: REFETCH_INTERVAL,
refetchOnWindowFocus: true,
refetchInterval: autoQuery ? REFETCH_INTERVAL : false,
refetchIntervalInBackground: autoQuery,
refetchOnWindowFocus: autoQuery,
staleTime: REFETCH_INTERVAL,
retry: 1,
});
+11 -3
View File
@@ -19,6 +19,12 @@ export function useSubscriptionQuota(appId: AppId, enabled: boolean) {
});
}
export interface UseCodexOauthQuotaOptions {
enabled?: boolean;
/** 是否启用自动轮询(5 分钟)与窗口 focus 重取 */
autoQuery?: boolean;
}
/**
* Codex OAuth (ChatGPT Plus/Pro 反代) 订阅额度查询 hook
*
@@ -30,15 +36,17 @@ export function useSubscriptionQuota(appId: AppId, enabled: boolean) {
*/
export function useCodexOauthQuota(
meta: ProviderMeta | undefined,
enabled: boolean,
options: UseCodexOauthQuotaOptions = {},
) {
const { enabled = true, autoQuery = false } = options;
const accountId = resolveManagedAccountId(meta, PROVIDER_TYPES.CODEX_OAUTH);
return useQuery({
queryKey: ["codex_oauth", "quota", accountId ?? "default"],
queryFn: () => subscriptionApi.getCodexOauthQuota(accountId),
enabled,
refetchInterval: REFETCH_INTERVAL,
refetchOnWindowFocus: true,
refetchInterval: autoQuery ? REFETCH_INTERVAL : false,
refetchIntervalInBackground: autoQuery,
refetchOnWindowFocus: autoQuery,
staleTime: REFETCH_INTERVAL,
retry: 1,
});