diff --git a/web/src/features/groups/credentials/SubscriptionAccountCard.vue b/web/src/features/groups/credentials/SubscriptionAccountCard.vue index d9e83e5e..d2848256 100644 --- a/web/src/features/groups/credentials/SubscriptionAccountCard.vue +++ b/web/src/features/groups/credentials/SubscriptionAccountCard.vue @@ -5,6 +5,7 @@ import { CircleOff, Download, Ellipsis, + Gauge, KeyRound, LoaderCircle, RefreshCw, @@ -102,6 +103,14 @@ watch( const observation = computed(() => props.item.observation) const supportsQuotaObservation = computed(() => props.capabilities.quota_observation) +const needsInitialQuotaSync = computed( + () => + supportsQuotaObservation.value && + (observation.value === undefined || + (observation.value.state === 'unavailable' && + observation.value.observed_at_ms === null && + observation.value.last_attempt_at_ms === null)), +) const supportsResetCredit = computed(() => props.capabilities.credential_actions.includes('reset_credit'), ) @@ -890,6 +899,26 @@ function runMenuAction( +
+ + + {{ t('group.credentials.subscription.initialSyncTitle') }} + {{ t('group.credentials.subscription.initialSyncDescription') }} + + + +

{{ t('group.credentials.subscription.noQuota') }}

@@ -1589,6 +1618,43 @@ function runMenuAction( outline: 2px solid var(--color-focus); outline-offset: 2px; } +.subscription-account__initial-sync { + display: flex; + min-height: 54px; + align-items: center; + gap: var(--space-2); + border-radius: 6px; + background: color-mix(in srgb, var(--color-action-soft) 72%, var(--color-surface)); + box-shadow: inset 3px 0 0 color-mix(in srgb, var(--color-action) 58%, transparent); + padding: 8px 10px 8px 13px; +} +.subscription-account__initial-sync-icon { + display: grid; + width: 30px; + height: 30px; + flex: none; + place-items: center; + border-radius: 50%; + background: var(--color-surface); + color: var(--color-action); + box-shadow: 0 1px 2px color-mix(in srgb, var(--color-action) 12%, transparent); +} +.subscription-account__initial-sync-copy { + display: grid; + min-width: 0; + flex: 1 1 auto; + gap: 2px; + color: var(--color-text-muted); + font-size: var(--text-sm); + line-height: 1.35; +} +.subscription-account__initial-sync-copy strong { + color: var(--color-text); + font-weight: 650; +} +.subscription-account__initial-sync-action { + flex: none; +} .subscription-account__faint, .subscription-account__hint { margin: 0; diff --git a/web/src/i18n/locales/en-US/group.ts b/web/src/i18n/locales/en-US/group.ts index 61d7d201..b8a583ba 100644 --- a/web/src/i18n/locales/en-US/group.ts +++ b/web/src/i18n/locales/en-US/group.ts @@ -503,6 +503,10 @@ export default { 'Quota was reset, but quota information could not be refreshed. Try again manually.', tokenExpiresAt: 'Credential expires', lastTokenRefresh: 'Last credential refresh', + initialSyncTitle: 'Quota information not loaded', + initialSyncDescription: + 'Refresh once after importing to load the current quota and its progress.', + initialSyncAction: 'Refresh quota', noQuota: 'The upstream has not supplied any displayable quota window', quotaPendingRefresh: 'Refresh pending', quotaResetPrefix: 'Resets', diff --git a/web/src/i18n/locales/ja-JP/group.ts b/web/src/i18n/locales/ja-JP/group.ts index 0b638ee0..7418b4df 100644 --- a/web/src/i18n/locales/ja-JP/group.ts +++ b/web/src/i18n/locales/ja-JP/group.ts @@ -507,6 +507,10 @@ export default { '利用枠をリセットしましたが、利用枠情報を更新できませんでした。手動で再試行してください。', tokenExpiresAt: '認証期限', lastTokenRefresh: '認証情報の最終更新', + initialSyncTitle: '利用枠情報が未取得です', + initialSyncDescription: + '初回インポート後に一度更新すると、現在の利用枠と進捗を取得できます。', + initialSyncAction: '利用枠を更新', noQuota: '上流から表示可能な利用枠が提供されていません', quotaPendingRefresh: '更新待ち', quotaResetPrefix: '', diff --git a/web/src/i18n/locales/zh-CN/group.ts b/web/src/i18n/locales/zh-CN/group.ts index 86108ef0..613cb6c9 100644 --- a/web/src/i18n/locales/zh-CN/group.ts +++ b/web/src/i18n/locales/zh-CN/group.ts @@ -486,6 +486,9 @@ export default { consumeResetCreditPending: '额度已重置,但额度信息刷新失败,请手动重试', tokenExpiresAt: '凭据到期', lastTokenRefresh: '上次凭据刷新', + initialSyncTitle: '额度信息待获取', + initialSyncDescription: '首次导入后需要刷新一次,以获取当前额度和进度。', + initialSyncAction: '刷新额度', noQuota: '上游尚未提供可展示的额度窗口', quotaPendingRefresh: '待刷新', quotaResetPrefix: '',