From 6ff748d2aa9cb3f64fddb820a553607c9800a74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E5=8F=8A?= <522caiji@gmail.com> Date: Thu, 10 Sep 2026 14:54:35 +0800 Subject: [PATCH] fix: honor Qoder resource package quota --- CHANGELOG.md | 4 +++ frontend/src/api/types.ts | 8 +++++ .../src/components/account/AccountCard.tsx | 1 + .../src/components/account/QuotaMeter.tsx | 11 ++++-- frontend/src/i18n/messages.ts | 2 ++ frontend/src/lib/account.ts | 2 +- frontend/src/pages/OverviewPage.tsx | 2 +- internal/accounts/manager.go | 26 ++++++++++++-- internal/accounts/manager_test.go | 27 ++++++++++++++ internal/accounts/pool.go | 36 +++++++++++-------- internal/accounts/pool_test.go | 15 ++++++++ internal/accounts/store.go | 2 +- internal/accounts/store_test.go | 13 +++++++ internal/providers/interfaces.go | 5 +-- internal/providers/workbuddy/client.go | 2 +- ...t-B294OS2-.js => TrafficChart-BN8k9Ecy.js} | 12 +++---- .../webui/static/assets/index-BAjBDEmY.js | 28 --------------- .../webui/static/assets/index-DfvsD18H.js | 28 +++++++++++++++ internal/webui/static/index.html | 2 +- 19 files changed, 166 insertions(+), 60 deletions(-) rename internal/webui/static/assets/{TrafficChart-B294OS2-.js => TrafficChart-BN8k9Ecy.js} (61%) delete mode 100644 internal/webui/static/assets/index-BAjBDEmY.js create mode 100644 internal/webui/static/assets/index-DfvsD18H.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 80571b5..0199925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,12 @@ Write each change in both `### English` and `### 中文` under `## Unreleased`. ### English +- Keep Qoder accounts routable when their base quota is exhausted but an available add-on or organization resource package still has credits, and show resource-package balance in the console + ### 中文 +- Qoder 主额度用尽但可用附加包或组织资源包仍有余额时继续参与路由,并在控制台展示资源包余额 + ## 0.4.3 - 2026-09-10 ### English diff --git a/frontend/src/api/types.ts b/frontend/src/api/types.ts index 3a59156..0ad4f08 100644 --- a/frontend/src/api/types.ts +++ b/frontend/src/api/types.ts @@ -8,7 +8,15 @@ export type AccountQuota = { has_add_on?: boolean add_on_used?: number add_on_total?: number + add_on_remaining?: number add_on_unit?: string + add_on_available?: boolean + has_resource_package?: boolean + resource_package_used?: number + resource_package_total?: number + resource_package_remaining?: number + resource_package_unit?: string + resource_package_available?: boolean fetched_at?: string } diff --git a/frontend/src/components/account/AccountCard.tsx b/frontend/src/components/account/AccountCard.tsx index eb96bf8..6da334e 100644 --- a/frontend/src/components/account/AccountCard.tsx +++ b/frontend/src/components/account/AccountCard.tsx @@ -292,6 +292,7 @@ export function AccountCard({ usedLabel={t('quotaUsed')} remainingLabel={t('quotaRemaining')} addOnLabel={t('quotaAddOn')} + resourcePackageLabel={t('quotaResourcePackage')} exceededLabel={t('quotaExceeded')} /> ) : {t('statsUnknown')}} diff --git a/frontend/src/components/account/QuotaMeter.tsx b/frontend/src/components/account/QuotaMeter.tsx index 7861cc4..91eb662 100644 --- a/frontend/src/components/account/QuotaMeter.tsx +++ b/frontend/src/components/account/QuotaMeter.tsx @@ -8,19 +8,23 @@ type Props = { usedLabel: string remainingLabel: string addOnLabel: string + resourcePackageLabel: string exceededLabel: string } -export function QuotaMeter({ quota, label, usedLabel, remainingLabel, addOnLabel, exceededLabel }: Props) { +export function QuotaMeter({ quota, label, usedLabel, remainingLabel, addOnLabel, resourcePackageLabel, exceededLabel }: Props) { const ratio = quotaUsedRatio(quota) const tone = quotaTone(quota) const color = tone === 'danger' ? 'danger' : tone === 'warn' ? 'warning' : 'success' const unit = quota.unit || 'credits' const used = `${formatQuotaAmount(quota.used)} / ${formatQuotaAmount(quota.total)} ${unit}` const remaining = `${formatQuotaAmount(quota.remaining)} ${unit}` - const addOn = quota.has_add_on + const addOn = quota.has_add_on && quota.add_on_available !== false ? `${addOnLabel} ${formatQuotaAmount(quota.add_on_used)} / ${formatQuotaAmount(quota.add_on_total)} ${quota.add_on_unit || 'credits'}` : '' + const resourcePackage = quota.has_resource_package && quota.resource_package_available !== false + ? `${resourcePackageLabel} ${remainingLabel} ${formatQuotaAmount(quota.resource_package_remaining)} ${quota.resource_package_unit || 'credits'}` + : '' return (