From e6060ac874a94bd94ece723f4ce9b37f1469a97a Mon Sep 17 00:00:00 2001 From: watermelon <76525576+watermelon1024@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:22:48 +0800 Subject: [PATCH] feat: Update quota results as they resolve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update quota loading to commit each file’s result as soon as it completes instead of waiting for the full batch. This keeps the store in sync during concurrent refreshes and avoids missing intermediate updates when requests resolve incrementally. The test was adjusted to cover the new progressive update behavior. --- .../components/quota/QuotaSection.test.tsx | 14 +++++ .../src/components/quota/useQuotaLoader.ts | 60 ++++++++++++------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/apps/web/src/components/quota/QuotaSection.test.tsx b/apps/web/src/components/quota/QuotaSection.test.tsx index f825d1427..6dc2b6c62 100644 --- a/apps/web/src/components/quota/QuotaSection.test.tsx +++ b/apps/web/src/components/quota/QuotaSection.test.tsx @@ -469,6 +469,20 @@ describe('QuotaSection account display mode', () => { expect(mocks.fetchQuota).toHaveBeenCalledTimes(4); expect(maxActiveRequests).toBe(4); + resolvers.shift()?.(); + await act(async () => { + await flushMicrotasks(); + }); + + expect(mocks.quotaStoreState.codexQuota).toMatchObject({ + [getTestAuthFileKey(files[0])]: { + status: 'success', + rateLimitResetCreditsAvailableCount: 0, + authFileKey: getTestAuthFileKey(files[0]), + }, + }); + expect(mocks.fetchQuota).toHaveBeenCalledTimes(5); + while (mocks.fetchQuota.mock.calls.length < files.length) { resolvers.shift()?.(); await act(async () => { diff --git a/apps/web/src/components/quota/useQuotaLoader.ts b/apps/web/src/components/quota/useQuotaLoader.ts index 3ff8231f6..98d8ee698 100644 --- a/apps/web/src/components/quota/useQuotaLoader.ts +++ b/apps/web/src/components/quota/useQuotaLoader.ts @@ -90,27 +90,9 @@ export function useQuotaLoader(config: QuotaConfig return nextState; }); - const results = await runWithConcurrencyLimit( - targets, - DEFAULT_QUOTA_REFRESH_CONCURRENCY, - async (file): Promise> => { - const storeKey = getQuotaStoreKey(config, file); - try { - const data = await config.fetchQuota(file, t); - return { storeKey, file, status: 'success', data }; - } catch (err: unknown) { - const message = err instanceof Error ? err.message : t('common.unknown_error'); - const errorStatus = getStatusFromError(err); - return { storeKey, file, status: 'error', error: message, errorStatus }; - } - } - ); - - if (requestId !== requestIdRef.current) return; - - setQuota((prev) => { - const nextState = { ...prev }; - results.forEach((result) => { + const commitQuotaResult = (result: LoadQuotaResult) => { + setQuota((prev) => { + const nextState = { ...prev }; if (result.status === 'success') { nextState[result.storeKey] = config.buildSuccessState( result.data as TData, @@ -125,9 +107,41 @@ export function useQuotaLoader(config: QuotaConfig previousStateByStoreKey.get(result.storeKey) ); } + return nextState; }); - return nextState; - }); + }; + + await runWithConcurrencyLimit( + targets, + DEFAULT_QUOTA_REFRESH_CONCURRENCY, + async (file): Promise> => { + const storeKey = getQuotaStoreKey(config, file); + try { + const data = await config.fetchQuota(file, t); + const result: LoadQuotaResult = { storeKey, file, status: 'success', data }; + if (requestId === requestIdRef.current) { + commitQuotaResult(result); + } + return result; + } catch (err: unknown) { + const message = err instanceof Error ? err.message : t('common.unknown_error'); + const errorStatus = getStatusFromError(err); + const result: LoadQuotaResult = { + storeKey, + file, + status: 'error', + error: message, + errorStatus, + }; + if (requestId === requestIdRef.current) { + commitQuotaResult(result); + } + return result; + } + } + ); + + if (requestId !== requestIdRef.current) return; } finally { if (requestId === requestIdRef.current) { setLoading(false);