feat(quota): enhance quota reset functionality with UI updates and styling improvements

This commit is contained in:
LTbinglingfeng
2026-06-12 17:38:47 +08:00
Unverified
parent f3959a0b19
commit c7051aeb68
6 changed files with 41 additions and 47 deletions
+5 -3
View File
@@ -56,7 +56,6 @@ export function QuotaProgressBar({
export interface QuotaRenderHelpers {
styles: typeof styles;
QuotaProgressBar: (props: QuotaProgressBarProps) => ReactElement;
resetQuotaAction?: ReactNode;
}
interface QuotaCardProps<TState extends QuotaStatusState> {
@@ -149,14 +148,16 @@ export function QuotaCard<TState extends QuotaStatusState>({
})}
</div>
) : quota ? (
renderQuotaItems(quota, t, { styles, QuotaProgressBar, resetQuotaAction })
renderQuotaItems(quota, t, { styles, QuotaProgressBar })
) : (
<div className={styles.quotaMessage}>{t(idleMessageKey)}</div>
)}
</div>
{onRefresh && quotaStatus !== 'idle' && (
{(resetQuotaAction || (onRefresh && quotaStatus !== 'idle')) && (
<div className={styles.quotaCardActions}>
{resetQuotaAction}
{onRefresh && quotaStatus !== 'idle' && (
<Button
type="button"
variant="secondary"
@@ -170,6 +171,7 @@ export function QuotaCard<TState extends QuotaStatusState>({
{!quotaLoading && <IconRefreshCw size={14} />}
{t('auth_files.quota_refresh_single')}
</Button>
)}
</div>
)}
</div>
+3 -1
View File
@@ -360,7 +360,9 @@ export function QuotaSection<TState extends QuotaStatusState, TData>({
const isResettingQuota = resettingQuotaName === item.name;
const canUseQuotaAction =
!disabled && !item.disabled && itemQuota?.status !== 'loading';
const resetQuotaAction = config.resetQuota ? (
const showResetQuotaAction =
itemQuota !== undefined && Boolean(config.canResetQuota?.(itemQuota));
const resetQuotaAction = config.resetQuota && showResetQuotaAction ? (
<Button
type="button"
variant="secondary"
+2 -14
View File
@@ -130,6 +130,7 @@ export interface QuotaConfig<TState, TData> {
filterFn: (file: AuthFileItem) => boolean;
fetchQuota: (file: AuthFileItem, t: TFunction) => Promise<TData>;
resetQuota?: (file: AuthFileItem, t: TFunction) => Promise<TData>;
canResetQuota?: (quota: TState) => boolean;
storeSelector: (state: QuotaStore) => Record<string, TState>;
storeSetter: keyof QuotaStore;
buildLoadingState: () => TState;
@@ -857,10 +858,6 @@ const renderCodexItems = (
const planLabel = getPlanLabel(planType);
const isPremiumPlan = PREMIUM_CODEX_PLAN_TYPES.has(normalizePlanType(planType) ?? '');
const expiryLabel = subscriptionActiveUntil ? formatDateTimeValue(subscriptionActiveUntil) : '';
const resetQuotaAction =
rateLimitResetCreditsAvailableCount !== null && rateLimitResetCreditsAvailableCount > 0
? helpers.resetQuotaAction
: null;
const nodes: ReactNode[] = [];
if (planLabel || expiryLabel || rateLimitResetCreditsAvailableCount !== null) {
@@ -922,16 +919,6 @@ const renderCodexItems = (
nodes.push(h('div', { key: 'plan', className: styleMap.codexPlan }, ...planNodes));
}
if (resetQuotaAction) {
nodes.push(
h(
'div',
{ key: 'reset-credits-action', className: styleMap.quotaInlineActions },
resetQuotaAction
)
);
}
if (windows.length === 0) {
nodes.push(
h('div', { key: 'empty', className: styleMap.quotaMessage }, t('codex_quota.empty_windows'))
@@ -1354,6 +1341,7 @@ export const CODEX_CONFIG: QuotaConfig<
filterFn: (file) => isCodexFile(file) && !isDisabledAuthFile(file),
fetchQuota: fetchCodexQuota,
resetQuota: resetCodexQuota,
canResetQuota: (quota) => (quota.rateLimitResetCreditsAvailableCount ?? 0) > 0,
storeSelector: (state) => state.codexQuota,
storeSetter: 'setCodexQuota',
buildLoadingState: () => ({ status: 'loading', windows: [] }),
@@ -155,20 +155,22 @@ export function AuthFileQuotaSection(props: AuthFileQuotaSectionProps) {
const config = getQuotaConfig(quotaType) as unknown as {
i18nPrefix: string;
resetQuota?: (file: AuthFileItem, t: TFunction) => Promise<unknown>;
canResetQuota?: (quota: unknown) => boolean;
renderQuotaItems: (quota: unknown, t: TFunction, helpers: unknown) => unknown;
};
const quotaStatus = quota?.status ?? 'idle';
const canRefreshQuota = !disableControls && !file.disabled && !resettingQuota;
const canResetQuota = canRefreshQuota && quotaStatus !== 'loading';
const resetQuotaAction = config.resetQuota ? (
const canUseResetQuota = canRefreshQuota && quotaStatus !== 'loading';
const showResetQuotaAction = quota !== undefined && Boolean(config.canResetQuota?.(quota));
const resetQuotaAction = config.resetQuota && showResetQuotaAction ? (
<Button
type="button"
variant="secondary"
size="sm"
className={styles.quotaResetCreditButton}
onClick={() => resetQuotaForFile()}
disabled={!canResetQuota}
disabled={!canUseResetQuota}
loading={resettingQuota}
title={t('codex_quota.reset_button')}
aria-label={t('codex_quota.reset_button')}
@@ -206,11 +208,13 @@ export function AuthFileQuotaSection(props: AuthFileQuotaSectionProps) {
(config.renderQuotaItems(quota, t, {
styles,
QuotaProgressBar,
resetQuotaAction,
}) as ReactNode)
) : (
<div className={styles.quotaMessage}>{t(`${config.i18nPrefix}.idle`)}</div>
)}
{quotaStatus !== 'idle' && resetQuotaAction && (
<div className={styles.quotaCardActions}>{resetQuotaAction}</div>
)}
</div>
);
}
+8 -6
View File
@@ -640,12 +640,6 @@
}
}
.quotaInlineActions {
display: flex;
justify-content: flex-start;
padding-top: $spacing-xs;
}
.quotaResetCreditButton:global(.btn.btn-sm) {
border-radius: 999px;
padding-inline: 12px;
@@ -658,6 +652,14 @@
}
}
.quotaCardActions {
display: flex;
justify-content: flex-end;
gap: $spacing-xs;
flex-wrap: wrap;
padding-top: $spacing-xs;
}
.quotaError {
font-size: 12px;
color: var(--danger-color);
+2 -6
View File
@@ -392,15 +392,11 @@
}
}
.quotaInlineActions {
display: flex;
justify-content: flex-start;
padding-top: $spacing-xs;
}
.quotaCardActions {
display: flex;
justify-content: flex-end;
gap: $spacing-xs;
flex-wrap: wrap;
padding-top: $spacing-xs;
}