mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
chore(usage): add Realtime docs, improve timeframes, upsell
This commit is contained in:
1 parent
b7dabb368d
commit
2fc053d323
2 files changed
+199
-154
No files matched your search
@@ -243,6 +243,12 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [
|
||||
description:
|
||||
"Count of messages going through Realtime.\nUsage example: If you do a database change and 5 clients listen to that change via Realtime, that's 5 messages. If you broadcast a message and 4 clients listen to that, that's 5 messages (1 message sent, 4 received).\nBilling is based on the total amount of messages throughout your billing period.",
|
||||
chartDescription: 'The data refreshes every 24 hours.',
|
||||
links: [
|
||||
{
|
||||
name: 'Realtime Rate Limits',
|
||||
url: 'https://supabase.com/docs/guides/realtime/rate-limits',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
anchor: 'realtimePeakConnection',
|
||||
@@ -254,6 +260,12 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [
|
||||
description:
|
||||
'Total number of successful connections. Connections attempts are not counted towards usage.\nBilling is based on the maximum amount of concurrent peak connections throughout your billing period.',
|
||||
chartDescription: 'The data refreshes every 24 hours.',
|
||||
links: [
|
||||
{
|
||||
name: 'Realtime Rate Limits',
|
||||
url: 'https://supabase.com/docs/guides/realtime/rate-limits',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -68,166 +68,199 @@ const UsageSection = ({
|
||||
return (
|
||||
<div id={attribute.anchor} key={attribute.key}>
|
||||
<SectionContent section={attribute}>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<p className="text-sm">{attribute.name} usage</p>
|
||||
{currentBillingCycleSelected &&
|
||||
usageBasedBilling === false &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD && (
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger asChild>
|
||||
{!usageBasedBilling && usageRatio >= 1 ? (
|
||||
<div className="flex items-center space-x-2 min-w-[115px] cursor-help">
|
||||
<IconAlertTriangle
|
||||
size={14}
|
||||
strokeWidth={2}
|
||||
className={exceededLimitStyle}
|
||||
/>
|
||||
<p className={`text-sm ${exceededLimitStyle}`}>Exceeded limit</p>
|
||||
</div>
|
||||
) : (
|
||||
!usageBasedBilling &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD && (
|
||||
<div className="flex items-center space-x-2 min-w-[115px] cursor-help">
|
||||
<IconAlertTriangle
|
||||
size={14}
|
||||
strokeWidth={2}
|
||||
className="text-amber-900"
|
||||
/>
|
||||
<p className="text-sm text-amber-900">Approaching limit</p>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="bottom">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-scale-100 py-1 px-2 leading-none shadow',
|
||||
'border border-scale-200',
|
||||
].join(' ')}
|
||||
>
|
||||
<p className="text-xs text-scale-1200">
|
||||
Exceeding your plans included usage will lead to restrictions to
|
||||
your project.
|
||||
</p>
|
||||
<p className="text-xs text-scale-1200">
|
||||
Upgrade to a usage-based plan or disable the spend cap to avoid
|
||||
restrictions.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
)}
|
||||
</div>
|
||||
{usageMeta?.available_in_plan ? (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<p className="text-sm">{attribute.name} usage</p>
|
||||
{currentBillingCycleSelected &&
|
||||
usageBasedBilling === false &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD && (
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger asChild>
|
||||
{!usageBasedBilling && usageRatio >= 1 ? (
|
||||
<div className="flex items-center space-x-2 min-w-[115px] cursor-help">
|
||||
<IconAlertTriangle
|
||||
size={14}
|
||||
strokeWidth={2}
|
||||
className={exceededLimitStyle}
|
||||
/>
|
||||
<p className={`text-sm ${exceededLimitStyle}`}>
|
||||
Exceeded limit
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
!usageBasedBilling &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD && (
|
||||
<div className="flex items-center space-x-2 min-w-[115px] cursor-help">
|
||||
<IconAlertTriangle
|
||||
size={14}
|
||||
strokeWidth={2}
|
||||
className="text-amber-900"
|
||||
/>
|
||||
<p className="text-sm text-amber-900">Approaching limit</p>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="bottom">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-scale-100 py-1 px-2 leading-none shadow',
|
||||
'border border-scale-200',
|
||||
].join(' ')}
|
||||
>
|
||||
<p className="text-xs text-scale-1200">
|
||||
Exceeding your plans included usage will lead to restrictions
|
||||
to your project.
|
||||
</p>
|
||||
<p className="text-xs text-scale-1200">
|
||||
Upgrade to a usage-based plan or disable the spend cap to
|
||||
avoid restrictions.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{currentBillingCycleSelected &&
|
||||
!usageBasedBilling &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD && (
|
||||
<Link href={upgradeUrl}>
|
||||
<a className="pb-1">
|
||||
<Button type="default" size="tiny">
|
||||
{subscription?.plan?.id === 'free'
|
||||
? 'Upgrade plan'
|
||||
: 'Change spend cap'}
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
{currentBillingCycleSelected && usageMeta?.limit > 0 && (
|
||||
<SparkBar
|
||||
type="horizontal"
|
||||
barClass={clsx(
|
||||
usageRatio >= 1
|
||||
? usageBasedBilling
|
||||
? 'bg-amber-900'
|
||||
: 'bg-red-900'
|
||||
: usageBasedBilling === false && usageRatio >= USAGE_APPROACHING_THRESHOLD
|
||||
? 'bg-amber-900'
|
||||
: 'bg-scale-1100'
|
||||
)}
|
||||
bgClass="bg-gray-300 dark:bg-gray-600"
|
||||
value={usageMeta?.usage ?? 0}
|
||||
max={usageMeta?.limit || 1}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<div className="flex items-center justify-between border-b py-1">
|
||||
<p className="text-xs text-scale-1000">
|
||||
Included in {subscription?.plan?.name.toLowerCase()} plan
|
||||
</p>
|
||||
<p className="text-xs">
|
||||
{attribute.unit === 'bytes'
|
||||
? formatBytes(usageMeta?.limit ?? 0)
|
||||
: (usageMeta?.limit ?? 0).toLocaleString()}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<p className="text-xs text-scale-1000">
|
||||
{attribute.chartPrefix || 'Used '}in period
|
||||
</p>
|
||||
<p className="text-xs">
|
||||
{attribute.unit === 'bytes'
|
||||
? formatBytes(usageMeta?.usage ?? 0)
|
||||
: (usageMeta?.usage ?? 0).toLocaleString()}
|
||||
</p>
|
||||
</div>
|
||||
{currentBillingCycleSelected && usageMeta?.limit > 0 && (
|
||||
<div className="flex items-center justify-between border-t py-1">
|
||||
<p className="text-xs text-scale-1000">Overage in period</p>
|
||||
<p className="text-xs">
|
||||
{usageExcess < 0
|
||||
? attribute.unit === 'bytes'
|
||||
? formatBytes(0)
|
||||
: 0
|
||||
: attribute.unit === 'bytes'
|
||||
? formatBytes(usageExcess)
|
||||
: usageExcess.toLocaleString()}
|
||||
</p>
|
||||
{currentBillingCycleSelected &&
|
||||
!usageBasedBilling &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD && (
|
||||
<Link href={upgradeUrl}>
|
||||
<a className="pb-1">
|
||||
<Button type="default" size="tiny">
|
||||
{subscription?.plan?.id === 'free'
|
||||
? 'Upgrade plan'
|
||||
: 'Change spend cap'}
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
{currentBillingCycleSelected && usageMeta?.limit > 0 && (
|
||||
<SparkBar
|
||||
type="horizontal"
|
||||
barClass={clsx(
|
||||
usageRatio >= 1
|
||||
? usageBasedBilling
|
||||
? 'bg-amber-900'
|
||||
: 'bg-red-900'
|
||||
: usageBasedBilling === false &&
|
||||
usageRatio >= USAGE_APPROACHING_THRESHOLD
|
||||
? 'bg-amber-900'
|
||||
: 'bg-scale-1100'
|
||||
)}
|
||||
bgClass="bg-gray-300 dark:bg-gray-600"
|
||||
value={usageMeta?.usage ?? 0}
|
||||
max={usageMeta?.limit || 1}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<div className="flex items-center justify-between border-b py-1">
|
||||
<p className="text-xs text-scale-1000">
|
||||
Included in {subscription?.plan?.name.toLowerCase()} plan
|
||||
</p>
|
||||
{usageMeta?.limit === -1 ? (
|
||||
<p className="text-xs">None</p>
|
||||
) : usageMeta?.limit === 0 ? (
|
||||
<p className="text-xs">Unlimited</p>
|
||||
) : (
|
||||
<p className="text-xs">
|
||||
{attribute.unit === 'bytes'
|
||||
? formatBytes(usageMeta?.limit ?? 0)
|
||||
: (usageMeta?.limit ?? 0).toLocaleString()}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{currentBillingCycleSelected && (
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<p className="text-xs text-scale-1000">
|
||||
{attribute.chartPrefix || 'Used '}in period
|
||||
</p>
|
||||
<p className="text-xs">
|
||||
{attribute.unit === 'bytes'
|
||||
? formatBytes(usageMeta?.usage ?? 0)
|
||||
: (usageMeta?.usage ?? 0).toLocaleString()}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{currentBillingCycleSelected && usageMeta?.limit > 0 && (
|
||||
<div className="flex items-center justify-between border-t py-1">
|
||||
<p className="text-xs text-scale-1000">Overage in period</p>
|
||||
<p className="text-xs">
|
||||
{(usageMeta?.limit ?? 0) === -1 || usageExcess < 0
|
||||
? 0
|
||||
: attribute.unit === 'bytes'
|
||||
? formatBytes(usageExcess)
|
||||
: usageExcess.toLocaleString()}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{attribute.additionalInfo?.(subscription, usage)}
|
||||
|
||||
<div className="space-y-1">
|
||||
<p>
|
||||
{attribute.chartPrefix || ''}
|
||||
{attribute.name} per day
|
||||
</p>
|
||||
{attribute.chartDescription.split('\n').map((paragraph, idx) => (
|
||||
<p key={`para-${idx}`} className="text-sm text-scale-1000">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
{chartMeta[attribute.key].isLoading ? (
|
||||
<div className="space-y-2">
|
||||
<ShimmeringLoader />
|
||||
<ShimmeringLoader className="w-3/4" />
|
||||
<ShimmeringLoader className="w-1/2" />
|
||||
</div>
|
||||
) : chartData.length > 0 && notAllValuesZero ? (
|
||||
<UsageBarChart
|
||||
name={`${attribute.chartPrefix || ''}${attribute.name}`}
|
||||
unit={attribute.unit}
|
||||
attribute={attribute.attribute}
|
||||
data={chartData}
|
||||
yLeftMargin={chartMeta[attribute.key].margin}
|
||||
yFormatter={(value) => ChartYFormatterCompactNumber(value, attribute.unit)}
|
||||
/>
|
||||
) : (
|
||||
<Panel>
|
||||
<Panel.Content>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<IconBarChart2 className="text-scale-1100 mb-2" />
|
||||
<p className="text-sm">No data in period</p>
|
||||
<p className="text-sm text-scale-1000">May take up to 24 hours to show</p>
|
||||
</div>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{attribute.additionalInfo?.(subscription, usage)}
|
||||
|
||||
<div className="space-y-1">
|
||||
<p>
|
||||
{attribute.chartPrefix || ''}
|
||||
{attribute.name} per day
|
||||
</p>
|
||||
{attribute.chartDescription.split('\n').map((paragraph, idx) => (
|
||||
<p key={`para-${idx}`} className="text-sm text-scale-1000">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
{chartMeta[attribute.key].isLoading ? (
|
||||
<div className="space-y-2">
|
||||
<ShimmeringLoader />
|
||||
<ShimmeringLoader className="w-3/4" />
|
||||
<ShimmeringLoader className="w-1/2" />
|
||||
</div>
|
||||
) : chartData.length > 0 && notAllValuesZero ? (
|
||||
<UsageBarChart
|
||||
name={`${attribute.chartPrefix || ''}${attribute.name}`}
|
||||
unit={attribute.unit}
|
||||
attribute={attribute.attribute}
|
||||
data={chartData}
|
||||
yLeftMargin={chartMeta[attribute.key].margin}
|
||||
yFormatter={(value) => ChartYFormatterCompactNumber(value, attribute.unit)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Panel>
|
||||
<Panel.Content>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<IconBarChart2 className="text-scale-1100 mb-2" />
|
||||
<p className="text-sm">No data in period</p>
|
||||
<p className="text-sm text-scale-1000">May take up to 24 hours to show</p>
|
||||
<div className="flex w-full items-center flex-col justify-center space-y-2 md:flex-row md:justify-between">
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm">Not included in plan</p>
|
||||
<div>
|
||||
<p className="text-sm text-scale-1100">
|
||||
You need to be on a higher plan in order to use this feature.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Link href={`/project/${projectRef}/settings/billing/subscription`}>
|
||||
<a>
|
||||
<Button type="primary">Upgrade plan</Button>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
|
||||
Reference in new issue
Block a user