mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-03 11:01:22 +08:00
feat(usage): add official subscription quota template with unified tier rendering
Changes: - Add official_subscription template type for Claude/Codex/Gemini - Replace implicit 'category=official auto-query' with explicit opt-in template - Default disabled; users enable via usage script modal with configurable interval - Unify tier→label mapping across subscription and script paths via labeled_tier_parts() - Fix tray rendering: week aliases (seven_day/opus/sonnet) now use highest utilization - Add depth guard: official_subscription checks enabled flag in query_provider_usage_inner - Add cache invalidation symmetry: invalidate_subscription() for disabled providers - i18n: add templateOfficialSubscription + hint in zh/en/ja/zh-TW Backend (Rust): - provider.rs: add TEMPLATE_TYPE_OFFICIAL_SUBSCRIPTION branch, flatten SubscriptionQuota→UsageData - tray.rs: extract labeled_tier_parts() shared by both summary functions, use max_by for multi-alias groups - usage_cache.rs: add invalidate_subscription() method - Test coverage: add week-alias highest-utilization tests for both paths Frontend (TypeScript): - UsageScriptModal: add official_subscription to templates, auto-detect for official providers - ProviderCard: gate useUsageQuery with !isOfficialSubscriptionUsage, pass autoQueryInterval to footer - SubscriptionQuotaFooter: accept autoQueryInterval prop, default 0 (disabled) - constants.ts: add TEMPLATE_TYPES.OFFICIAL_SUBSCRIPTION Fixes tier rendering regression where: - Claude/Codex: seven_day was missed (only weekly_limit matched) → lost 7-day window in tray - Gemini: gemini_pro/flash/flash_lite fell through to fallback → leaked machine names - Multi-window (opus+sonnet): find() took first, not worst → underestimated utilization and emoji color All tests pass (cargo test + cargo clippy clean).
This commit is contained in:
@@ -14,7 +14,7 @@ import UsageFooter from "@/components/UsageFooter";
|
||||
import SubscriptionQuotaFooter from "@/components/SubscriptionQuotaFooter";
|
||||
import CopilotQuotaFooter from "@/components/CopilotQuotaFooter";
|
||||
import CodexOauthQuotaFooter from "@/components/CodexOauthQuotaFooter";
|
||||
import { PROVIDER_TYPES } from "@/config/constants";
|
||||
import { PROVIDER_TYPES, TEMPLATE_TYPES } from "@/config/constants";
|
||||
import { isHermesReadOnlyProvider } from "@/config/hermesProviderPresets";
|
||||
import { ProviderHealthBadge } from "@/components/providers/ProviderHealthBadge";
|
||||
import { FailoverPriorityBadge } from "@/components/providers/FailoverPriorityBadge";
|
||||
@@ -192,6 +192,13 @@ export function ProviderCard({
|
||||
|
||||
const usageEnabled = provider.meta?.usage_script?.enabled ?? false;
|
||||
const isOfficial = isOfficialProvider(provider, appId);
|
||||
const supportsOfficialSubscription =
|
||||
isOfficial && ["claude", "codex", "gemini"].includes(appId);
|
||||
const isOfficialSubscriptionUsage =
|
||||
provider.meta?.usage_script?.templateType ===
|
||||
TEMPLATE_TYPES.OFFICIAL_SUBSCRIPTION;
|
||||
const officialSubscriptionEnabled =
|
||||
supportsOfficialSubscription && usageEnabled && isOfficialSubscriptionUsage;
|
||||
const isOfficialBlockedByProxy =
|
||||
isProxyTakeover && (provider.category === "official" || isOfficial);
|
||||
const isCopilot =
|
||||
@@ -231,7 +238,7 @@ export function ProviderCard({
|
||||
: 0;
|
||||
|
||||
const { data: usage } = useUsageQuery(provider.id, appId, {
|
||||
enabled: usageEnabled,
|
||||
enabled: usageEnabled && !isOfficial && !isOfficialSubscriptionUsage,
|
||||
autoQueryInterval,
|
||||
});
|
||||
|
||||
@@ -469,11 +476,16 @@ export function ProviderCard({
|
||||
isCurrent={isCurrent}
|
||||
/>
|
||||
) : isOfficial ? (
|
||||
<SubscriptionQuotaFooter
|
||||
appId={appId}
|
||||
inline={true}
|
||||
isCurrent={isCurrent}
|
||||
/>
|
||||
officialSubscriptionEnabled ? (
|
||||
<SubscriptionQuotaFooter
|
||||
appId={appId}
|
||||
inline={true}
|
||||
isCurrent={isCurrent}
|
||||
autoQueryInterval={
|
||||
provider.meta?.usage_script?.autoQueryInterval ?? 0
|
||||
}
|
||||
/>
|
||||
) : null
|
||||
) : hasMultiplePlans ? (
|
||||
<div className="flex items-center gap-2 text-xs text-gray-600 dark:text-gray-400">
|
||||
<span className="font-medium">
|
||||
@@ -540,7 +552,9 @@ export function ProviderCard({
|
||||
: undefined
|
||||
}
|
||||
onConfigureUsage={
|
||||
isOfficial || isCopilot || isCodexOauth
|
||||
(isOfficial && !supportsOfficialSubscription) ||
|
||||
isCopilot ||
|
||||
isCodexOauth
|
||||
? undefined
|
||||
: () => onConfigureUsage(provider)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user