feat(billing): enhance ProgressBar and UsageInfo for storage mode

- Add indeterminateFull prop to ProgressBar for full-width stripe in indeterminate state
- Introduce storageMode prop in UsageInfo to manage display logic based on storage usage
- Update rendering logic in UsageInfo to differentiate between storage and non-storage modes
- Modify VectorSpaceInfo to pass storageMode prop for consistent behavior
This commit is contained in:
CodingOnStar
2026-01-20 14:55:56 +08:00
parent 3b4b5b332c
commit a1482c5587
3 changed files with 65 additions and 42 deletions

View File

@ -4,19 +4,26 @@ type ProgressBarProps = {
percent: number
color: string
indeterminate?: boolean
indeterminateFull?: boolean // For Sandbox users: full width stripe
}
const ProgressBar = ({
percent = 0,
color = '#2970FF',
indeterminate = false,
indeterminateFull = false,
}: ProgressBarProps) => {
if (indeterminate) {
return (
<div
data-testid="billing-progress-bar-indeterminate"
className="h-1 overflow-hidden rounded-[6px] bg-components-progress-bar-bg"
/>
<div className="overflow-hidden rounded-[6px] bg-components-progress-bar-bg">
<div
data-testid="billing-progress-bar-indeterminate"
className={cn('h-1 rounded-[6px]', indeterminateFull ? 'w-full' : 'w-[30px]')}
style={{
background: 'repeating-linear-gradient(-55deg, #D0D5DD, #D0D5DD 2px, transparent 2px, transparent 5px)',
}}
/>
</div>
)
}

View File

@ -20,6 +20,7 @@ type Props = {
resetInDays?: number
hideIcon?: boolean
// Props for the 50MB threshold display logic
storageMode?: boolean
storageThreshold?: number
storageTooltip?: string
storageTotalDisplay?: string // e.g., "5GB" or "50MB" for formatted display
@ -40,6 +41,7 @@ const UsageInfo: FC<Props> = ({
resetHint,
resetInDays,
hideIcon = false,
storageMode = false,
storageThreshold = 50,
storageTooltip,
storageTotalDisplay,
@ -47,10 +49,10 @@ const UsageInfo: FC<Props> = ({
}) => {
const { t } = useTranslation()
// Special display logic for usage below threshold
const isBelowThreshold = usage < storageThreshold
// Special display logic for usage below threshold (only in storage mode)
const isBelowThreshold = storageMode && usage < storageThreshold
// Sandbox at full capacity (usage >= threshold and it's sandbox plan)
const isSandboxFull = isSandboxPlan && usage >= storageThreshold
const isSandboxFull = storageMode && isSandboxPlan && usage >= storageThreshold
const percent = usage / total * 100
const getProgressColor = () => {
@ -88,49 +90,61 @@ const UsageInfo: FC<Props> = ({
// Render usage display
const renderUsageDisplay = () => {
// Sandbox user at full capacity
if (isSandboxFull) {
return (
<div className="flex items-center gap-1">
<span>
{storageThreshold}
</span>
<span className="system-md-regular text-text-quaternary">/</span>
<span>
{storageThreshold}
{' '}
{unit}
</span>
</div>
)
}
// Usage below threshold - show "< 50 MB" or "< 50 / 5GB"
if (isBelowThreshold) {
// Storage mode: special display logic
if (storageMode) {
// Sandbox user at full capacity
if (isSandboxFull) {
return (
<div className="flex items-center gap-1">
<span>
{storageThreshold}
</span>
<span className="system-md-regular text-text-quaternary">/</span>
<span>
{storageThreshold}
{' '}
{unit}
</span>
</div>
)
}
// Usage below threshold - show "< 50 MB" or "< 50 / 5GB"
if (isBelowThreshold) {
const totalText = storageTotalDisplay || totalDisplay
return (
<div className="flex items-center gap-1">
<span>
&lt;
{' '}
{storageThreshold}
</span>
{!isSandboxPlan && (
<>
<span className="system-md-regular text-text-quaternary">/</span>
<span>{totalText}</span>
</>
)}
{isSandboxPlan && <span>{unit}</span>}
</div>
)
}
// Pro/Team users with usage >= threshold - show actual usage
const totalText = storageTotalDisplay || totalDisplay
return (
<div className="flex items-center gap-1">
<span>
&lt;
{' '}
{storageThreshold}
</span>
{!isSandboxPlan && (
<>
<span className="system-md-regular text-text-quaternary">/</span>
<span>{totalText}</span>
</>
)}
{isSandboxPlan && <span>{unit}</span>}
<span>{usage}</span>
<span className="system-md-regular text-text-quaternary">/</span>
<span>{totalText}</span>
</div>
)
}
// Pro/Team users with usage >= threshold - show actual usage
const totalText = storageTotalDisplay || totalDisplay
// Default display (storageMode = false)
return (
<div className="flex items-center gap-1">
<span>{usage}</span>
<span className="system-md-regular text-text-quaternary">/</span>
<span>{totalText}</span>
<span>{totalDisplay}</span>
</div>
)
}
@ -142,10 +156,11 @@ const UsageInfo: FC<Props> = ({
percent={isBelowThreshold ? 0 : percent}
color={isSandboxFull ? 'bg-components-progress-error-progress' : color}
indeterminate={isBelowThreshold}
indeterminateFull={isBelowThreshold && isSandboxPlan}
/>
)
if (storageTooltip) {
if (storageMode && storageTooltip) {
return (
<Tooltip
popupContent={(
@ -167,7 +182,7 @@ const UsageInfo: FC<Props> = ({
const renderUsageWithTooltip = () => {
const usageDisplay = renderUsageDisplay()
if (storageTooltip) {
if (storageMode && storageTooltip) {
return (
<Tooltip
popupContent={(

View File

@ -54,6 +54,7 @@ const VectorSpaceInfo: FC<Props> = ({
total={totalInMB}
unit="MB"
unitPosition="inline"
storageMode
storageThreshold={STORAGE_THRESHOLD_MB}
storageTooltip={t('usagePage.storageThresholdTooltip', { ns: 'billing' }) as string}
storageTotalDisplay={`${totalInMB}MB`}