feat(quota-ui): normalize Gemini vertex quota groups and streamline auth card refresh UX

This commit is contained in:
LTbinglingfeng
2026-02-06 22:28:01 +08:00
parent cade2647d6
commit c892d939c7
4 changed files with 36 additions and 88 deletions

View File

@@ -417,9 +417,6 @@
"proxy_url_placeholder": "socks5://username:password@proxy_ip:port/",
"prefix_proxy_invalid_json": "This credential is not a JSON object and cannot be edited.",
"prefix_proxy_saved_success": "Updated \"{{name}}\" successfully",
"card_tools_title": "Tools",
"quota_refresh_single": "Refresh quota",
"quota_refresh_hint": "Refresh quota for this credential only",
"quota_refresh_success": "Quota refreshed for \"{{name}}\"",
"quota_refresh_failed": "Failed to refresh quota for \"{{name}}\": {{message}}"
},
@@ -427,7 +424,7 @@
"title": "Antigravity Quota",
"empty_title": "No Antigravity Auth Files",
"empty_desc": "Upload an Antigravity credential to view remaining quota.",
"idle": "Not loaded. Click Refresh Button.",
"idle": "Click here to refresh quota",
"loading": "Loading quota...",
"load_failed": "Failed to load quota: {{message}}",
"missing_auth_index": "Auth file missing auth_index",
@@ -439,7 +436,7 @@
"title": "Codex Quota",
"empty_title": "No Codex Auth Files",
"empty_desc": "Upload a Codex credential to view quota.",
"idle": "Not loaded. Click Refresh Button.",
"idle": "Click here to refresh quota",
"loading": "Loading quota...",
"load_failed": "Failed to load quota: {{message}}",
"missing_auth_index": "Auth file missing auth_index",
@@ -461,7 +458,7 @@
"title": "Gemini CLI Quota",
"empty_title": "No Gemini CLI Auth Files",
"empty_desc": "Upload a Gemini CLI credential to view remaining quota.",
"idle": "Not loaded. Click Refresh Button.",
"idle": "Click here to refresh quota",
"loading": "Loading quota...",
"load_failed": "Failed to load quota: {{message}}",
"missing_auth_index": "Auth file missing auth_index",

View File

@@ -417,9 +417,6 @@
"proxy_url_placeholder": "socks5://username:password@proxy_ip:port/",
"prefix_proxy_invalid_json": "该凭证文件不是 JSON 对象,无法编辑。",
"prefix_proxy_saved_success": "已更新 \"{{name}}\"",
"card_tools_title": "配置面板",
"quota_refresh_single": "刷新额度",
"quota_refresh_hint": "仅刷新当前凭证的额度数据",
"quota_refresh_success": "已刷新 \"{{name}}\" 的额度",
"quota_refresh_failed": "刷新 \"{{name}}\" 的额度失败:{{message}}"
},
@@ -427,7 +424,7 @@
"title": "Antigravity 额度",
"empty_title": "暂无 Antigravity 认证",
"empty_desc": "上传 Antigravity 认证文件后即可查看额度。",
"idle": "尚未加载额度,请点击刷新按钮。",
"idle": "点击此处刷新额度",
"loading": "正在加载额度...",
"load_failed": "额度获取失败:{{message}}",
"missing_auth_index": "认证文件缺少 auth_index",
@@ -439,7 +436,7 @@
"title": "Codex 额度",
"empty_title": "暂无 Codex 认证",
"empty_desc": "上传 Codex 认证文件后即可查看额度。",
"idle": "尚未加载额度,请点击刷新按钮。",
"idle": "点击此处刷新额度",
"loading": "正在加载额度...",
"load_failed": "额度获取失败:{{message}}",
"missing_auth_index": "认证文件缺少 auth_index",
@@ -461,7 +458,7 @@
"title": "Gemini CLI 额度",
"empty_title": "暂无 Gemini CLI 认证",
"empty_desc": "上传 Gemini CLI 认证文件后即可查看额度。",
"idle": "尚未加载额度,请点击刷新按钮。",
"idle": "点击此处刷新额度",
"loading": "正在加载额度...",
"load_failed": "额度获取失败:{{message}}",
"missing_auth_index": "认证文件缺少 auth_index",

View File

@@ -185,10 +185,10 @@
}
.fileGridQuotaManaged {
grid-template-columns: repeat(auto-fill, minmax(520px, 1fr));
grid-template-columns: repeat(3, minmax(0, 1fr));
@include tablet {
grid-template-columns: 1fr;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@include mobile {
@@ -414,6 +414,24 @@
padding: $spacing-sm 0;
}
.quotaMessageAction {
width: 100%;
border: none;
background: none;
cursor: pointer;
text-decoration: underline;
&:hover:not(:disabled) {
color: var(--text-primary);
}
&:disabled {
cursor: not-allowed;
opacity: 0.6;
text-decoration: none;
}
}
.quotaError {
font-size: 12px;
color: var(--danger-color);
@@ -487,17 +505,6 @@
gap: $spacing-md;
}
.fileCardLayoutQuota {
display: grid;
grid-template-columns: 1fr 156px;
gap: $spacing-md;
align-items: stretch;
@include mobile {
grid-template-columns: 1fr;
}
}
.fileCardMain {
display: flex;
flex-direction: column;
@@ -506,41 +513,6 @@
min-width: 0;
}
.fileCardSidebar {
display: flex;
flex-direction: column;
gap: $spacing-sm;
padding-left: $spacing-md;
border-left: 1px dashed var(--border-color);
@include mobile {
border-left: none;
border-top: 1px dashed var(--border-color);
padding-left: 0;
padding-top: $spacing-md;
}
}
.fileCardSidebarHeader {
display: flex;
align-items: center;
justify-content: space-between;
gap: $spacing-xs;
}
.fileCardSidebarTitle {
font-size: 12px;
font-weight: 600;
color: var(--text-secondary);
white-space: nowrap;
}
.fileCardSidebarHint {
font-size: 12px;
color: var(--text-tertiary);
line-height: 1.4;
}
.cardHeader {
display: flex;
align-items: center;

View File

@@ -17,7 +17,6 @@ import {
IconChevronUp,
IconDownload,
IconInfo,
IconRefreshCw,
IconTrash2,
} from '@/components/ui/icons';
import type { TFunction } from 'i18next';
@@ -1547,6 +1546,7 @@ export function AuthFilesPage() {
| { status?: string; error?: string; errorStatus?: number }
| undefined;
const quotaStatus = quota?.status ?? 'idle';
const canRefreshQuota = !disableControls && !item.disabled;
const quotaErrorMessage = resolveQuotaErrorMessage(
t,
quota?.errorStatus,
@@ -1558,7 +1558,14 @@ export function AuthFilesPage() {
{quotaStatus === 'loading' ? (
<div className={styles.quotaMessage}>{t(`${config.i18nPrefix}.loading`)}</div>
) : quotaStatus === 'idle' ? (
<div className={styles.quotaMessage}>{t(`${config.i18nPrefix}.idle`)}</div>
<button
type="button"
className={`${styles.quotaMessage} ${styles.quotaMessageAction}`}
onClick={() => void refreshQuotaForFile(item, quotaType)}
disabled={!canRefreshQuota}
>
{t(`${config.i18nPrefix}.idle`)}
</button>
) : quotaStatus === 'error' ? (
<div className={styles.quotaError}>
{t(`${config.i18nPrefix}.load_failed`, {
@@ -1586,8 +1593,6 @@ export function AuthFilesPage() {
quotaFilterType && resolveQuotaType(item) === quotaFilterType ? quotaFilterType : null;
const showQuotaLayout = Boolean(quotaType) && !isRuntimeOnly;
const quotaState = quotaType ? getQuotaState(quotaType, item.name) : undefined;
const quotaRefreshing = quotaState?.status === 'loading';
const providerCardClass =
quotaType === 'antigravity'
@@ -1604,7 +1609,7 @@ export function AuthFilesPage() {
className={`${styles.fileCard} ${providerCardClass} ${item.disabled ? styles.fileCardDisabled : ''}`}
>
<div
className={`${styles.fileCardLayout} ${showQuotaLayout ? styles.fileCardLayoutQuota : ''}`}
className={styles.fileCardLayout}
>
<div className={styles.fileCardMain}>
<div className={styles.cardHeader}>
@@ -1722,29 +1727,6 @@ export function AuthFilesPage() {
)}
</div>
</div>
{showQuotaLayout && quotaType && (
<div className={styles.fileCardSidebar}>
<div className={styles.fileCardSidebarHeader}>
<span className={styles.fileCardSidebarTitle}>
{t('auth_files.card_tools_title')}
</span>
<Button
variant="secondary"
size="sm"
className={styles.iconButton}
onClick={() => void refreshQuotaForFile(item, quotaType)}
disabled={disableControls || item.disabled}
loading={quotaRefreshing}
title={t('auth_files.quota_refresh_single')}
aria-label={t('auth_files.quota_refresh_single')}
>
{!quotaRefreshing && <IconRefreshCw className={styles.actionIcon} size={16} />}
</Button>
</div>
<div className={styles.fileCardSidebarHint}>{t('auth_files.quota_refresh_hint')}</div>
</div>
)}
</div>
</div>
);