diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt index ee2983ba130..25cb1920e0b 100644 --- a/apps/docs/public/humans.txt +++ b/apps/docs/public/humans.txt @@ -34,6 +34,7 @@ Guilherme Souza Haydn Maley Hieu Pham Inian P +Jenny Kibiri Jess Shears Joel Lee John Pena diff --git a/apps/docs/spec/cli_v1_commands.yaml b/apps/docs/spec/cli_v1_commands.yaml index 27da229776d..c682e88a220 100644 --- a/apps/docs/spec/cli_v1_commands.yaml +++ b/apps/docs/spec/cli_v1_commands.yaml @@ -1,7 +1,7 @@ clispec: '001' info: id: cli - version: 1.187.3 + version: 1.187.10 title: Supabase CLI language: sh source: https://github.com/supabase/cli diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.constants.ts b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.constants.ts index 26eb514fece..ba64d28edf3 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.constants.ts +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.constants.ts @@ -6,9 +6,10 @@ export interface Metric { key: string name: string units: string - anchor: string + anchor?: string category: string - unitName: string + unitName?: string + tip?: string } export const BILLING_BREAKDOWN_METRICS: Metric[] = [ @@ -58,7 +59,6 @@ export const BILLING_BREAKDOWN_METRICS: Metric[] = [ units: 'absolute', anchor: 'storageImageTransformations', category: 'Storage', - unitName: 'image', }, { key: PricingMetric.REALTIME_PEAK_CONNECTIONS, @@ -66,7 +66,6 @@ export const BILLING_BREAKDOWN_METRICS: Metric[] = [ units: 'absolute', anchor: 'realtimePeakConnections', category: 'Realtime', - unitName: 'connection', }, { key: PricingMetric.REALTIME_MESSAGE_COUNT, @@ -74,7 +73,6 @@ export const BILLING_BREAKDOWN_METRICS: Metric[] = [ units: 'absolute', anchor: 'realtimeMessageCount', category: 'Realtime', - unitName: 'message', }, { key: PricingMetric.FUNCTION_INVOCATIONS, @@ -82,6 +80,13 @@ export const BILLING_BREAKDOWN_METRICS: Metric[] = [ units: 'absolute', anchor: 'funcInvocations', category: 'Edge Functions', - unitName: 'invocation', + }, + { + key: PricingMetric.DISK_SIZE_GB_HOURS, + name: 'Disk Size', + units: 'absolute', + unitName: 'GB-Hrs', + category: 'Database', + tip: 'Each project gets provisioned with 8 GB of disk. When you get close to the disk size limit, we autoscale your disk by 1.5x. The first 8 GB of disk is free for every single project.', }, ] diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx index 4292616e26f..b22f205965e 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingBreakdown.tsx @@ -52,7 +52,7 @@ const BillingBreakdown = () => { {!canReadSubscriptions ? ( - + ) : ( <> {isLoadingSubscription && ( diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingMetric.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingMetric.tsx index 5943872e241..c95e5190d34 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingMetric.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingMetric.tsx @@ -36,21 +36,30 @@ const BillingMetric = ({ } else if ( (usageMeta.cost && usageMeta.cost > 0) || !relativeToSubscription || - usageMeta.unlimited + usageMeta.unlimited || + usageMeta.pricing_free_units === 0 ) { - return metric.units === 'bytes' + return metric.units === 'bytes' || metric.units === 'gigabytes' ? `${usageMeta.usage.toLocaleString() ?? 0} GB` - : usageMeta.usage.toLocaleString() + : usageMeta.usage.toLocaleString() + (metric.unitName ? ` ${metric.unitName}` : '') } else { - return metric.units === 'bytes' + return metric.units === 'bytes' || metric.units === 'gigabytes' ? `${usageMeta.usage.toLocaleString() ?? 0} / ${usageMeta.pricing_free_units ?? 0} GB` - : `${usageMeta.usage.toLocaleString()} / ${usageMeta.pricing_free_units?.toLocaleString()}` + : `${usageMeta.usage.toLocaleString()} / ${usageMeta.pricing_free_units?.toLocaleString()}` + + (metric.unitName ? ` ${metric.unitName}` : '') } }, [usageMeta, relativeToSubscription, metric]) + const sortedProjectAllocations = useMemo(() => { + if (!usageMeta || !usageMeta.project_allocations) return [] + + return usageMeta.project_allocations.sort((a, b) => b.usage - a.usage) + }, [usageMeta]) + if (!usageMeta) return null - const usageRatio = usageMeta.usage / (usageMeta.pricing_free_units ?? 0) + const usageRatio = + usageMeta.usage === 0 ? 0 : usageMeta.usage / (usageMeta.pricing_free_units ?? 0) const isUsageBillingEnabled = subscription?.usage_billing_enabled === true @@ -61,24 +70,32 @@ const BillingMetric = ({ const unit = billingMetricUnit(usageMeta.metric as PricingMetric) const percentageLabel = - usageRatio < 0.01 ? '<1%' : `${(+(usageRatio * 100).toFixed(0)).toLocaleString()}%` + usageMeta.usage === 0 || usageMeta.pricing_free_units === 0 + ? '' + : usageRatio < 0.01 + ? '(<1%)' + : `(${(+(usageRatio * 100).toFixed(0)).toLocaleString()}%)` return (
- -
-

- {metric.name} -

- -
- + {metric.anchor ? ( + +
+

+ {metric.name} +

+ +
+ + ) : ( +

{metric.name}

+ )} {usageLabel}  - {usageMeta.cost && usageMeta.cost > 0 ? ( + {relativeToSubscription && usageMeta.cost && usageMeta.cost > 0 ? ( ({formatCurrency(usageMeta.cost)}) ) : usageMeta.available_in_plan && !usageMeta.unlimited && relativeToSubscription ? ( - ({percentageLabel}) + {percentageLabel} ) : null}
@@ -130,39 +147,10 @@ const BillingMetric = ({

{usageMeta.unit_price_desc}

- {usageMeta.project_allocations && usageMeta.project_allocations.length > 0 && ( - - - - - - - - - {usageMeta.project_allocations.map((allocation) => ( - - - - - ))} - - - - - - - - -
ProjectUsage
{allocation.name} - {formatUsage(usageMeta.metric as PricingMetric, allocation.usage)} -
- Total{unit && ({unit})} - - {formatUsage( - usageMeta.metric as PricingMetric, - usageMeta.usage_original - )}{' '} -
+ {metric.tip && ( +
+

{metric.tip}

+
)} {subscription.usage_billing_enabled === false && @@ -176,6 +164,40 @@ const BillingMetric = ({

)} + + {sortedProjectAllocations && sortedProjectAllocations.length > 0 && ( + + + + + + + + + {sortedProjectAllocations.map((allocation) => ( + + + + + ))} + + + + + + + + +
ProjectUsage
{allocation.name} + {formatUsage(usageMeta.metric as PricingMetric, allocation)} +
+ Total{unit && ({unit})} + + {formatUsage(usageMeta.metric as PricingMetric, { + usage: usageMeta.usage_original, + })}{' '} +
+ )}
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/ComputeMetric.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/ComputeMetric.tsx index 925015cc208..a319efb3056 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/ComputeMetric.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/ComputeMetric.tsx @@ -20,15 +20,21 @@ const ComputeMetric = ({ slug, metric, usage, relativeToSubscription }: ComputeM const usageMeta = usage.usages.find((x) => x.metric === metric.key) const usageLabel = useMemo(() => { - if (usageMeta?.cost && usageMeta.cost > 0) { - return `${usageMeta?.usage?.toLocaleString() ?? 0} hours` - } else { + if (usageMeta?.pricing_free_units) { return `${usageMeta?.usage?.toLocaleString() ?? 0} / ${ usageMeta?.pricing_free_units ?? 0 } hours` + } else { + return `${usageMeta?.usage?.toLocaleString() ?? 0} hours` } }, [usageMeta]) + const sortedProjectAllocations = useMemo(() => { + if (!usageMeta || !usageMeta.project_allocations) return [] + + return usageMeta.project_allocations.sort((a, b) => b.usage - a.usage) + }, [usageMeta]) + return (
@@ -57,40 +63,7 @@ const ComputeMetric = ({ slug, metric, usage, relativeToSubscription }: ComputeM

{usageMeta?.unit_price_desc}

- {usageMeta?.project_allocations && usageMeta.project_allocations.length > 0 && ( - - - - - - - - - {usageMeta.project_allocations.map((allocation) => ( - - - - - ))} - - - - - - - - -
ProjectUsage
{allocation.name} - {formatUsage(usageMeta.metric as PricingMetric, allocation.usage)} -
Total (Hours) - {formatUsage( - usageMeta.metric as PricingMetric, - usageMeta.usage_original - )} -
- )} - -
+

Every project is a dedicated server and database. For every hour your project is active, it incurs compute costs based on the compute size of your project. @@ -104,6 +77,38 @@ const ComputeMetric = ({ slug, metric, usage, relativeToSubscription }: ComputeM

+ + {usageMeta && sortedProjectAllocations.length > 0 && ( + + + + + + + + + {sortedProjectAllocations.map((allocation) => ( + + + + + ))} + + + + + + + + +
ProjectUsage
{allocation.name} + {formatUsage(usageMeta.metric as PricingMetric, allocation)} +
Total (Hours) + {formatUsage(usageMeta.metric as PricingMetric, { + usage: usageMeta.usage_original, + })} +
+ )}
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx index 9a9a2fe5cdf..d3fe1d030e1 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx @@ -193,7 +193,7 @@ const UpcomingInvoice = ({ slug }: UpcomingInvoiceProps) => { {fee.usage_original - ? `${formatUsage(fee.usage_metric!, fee.usage_original)}` + ? `${formatUsage(fee.usage_metric!, { usage: fee.usage_original })}` : fee.quantity ? fee.quantity : null} @@ -223,7 +223,7 @@ const UpcomingInvoice = ({ slug }: UpcomingInvoiceProps) => { {breakdown.project_name} - {formatUsage(fee.usage_metric!, breakdown.usage)} + {formatUsage(fee.usage_metric!, breakdown)} diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts b/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts index 431fe037dd0..62677c4ba83 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts +++ b/apps/studio/components/interfaces/Organization/BillingSettings/helpers.ts @@ -6,11 +6,32 @@ const pricingMetricBytes = [ PricingMetric.STORAGE_SIZE, ] -export const formatUsage = (pricingMetric: PricingMetric, usage: number) => { +export const formatUsage = ( + pricingMetric: PricingMetric, + allocation: { usage: number; hours?: number } +) => { + if (allocation.hours) { + return ( + allocation.usage.toLocaleString() + + ' (' + + Math.round(allocation.usage / allocation.hours).toLocaleString() + + 'x' + + allocation.hours.toLocaleString() + + ' hours)' + ) + } + if (pricingMetricBytes.includes(pricingMetric)) { - return +(usage / 1e9).toFixed(2).toLocaleString() + const formattedUsage = +(allocation.usage / 1e9).toFixed(2).toLocaleString() + + // To avoid very low usage displaying as "0", we will show "<0.01" instead + if (allocation.usage > 0 && formattedUsage === 0) { + return '<0.01' + } else { + return formattedUsage + } } else { - return usage.toLocaleString() + return allocation.usage.toLocaleString() } } diff --git a/apps/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx b/apps/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx index cba30fb97df..1a3b423f313 100644 --- a/apps/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx +++ b/apps/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx @@ -36,7 +36,7 @@ const SidePanelGitHubRepoLinker = ({ projectRef }: SidePanelGitHubRepoLinkerProp const sidePanelStateSnapshot = useSidePanelsStateSnapshot() const { data: gitHubAuthorization, isLoading: isLoadingGitHubAuthorization } = - useGitHubAuthorizationQuery() + useGitHubAuthorizationQuery({ enabled: sidePanelStateSnapshot.githubConnectionsOpen }) // [Alaister]: temp override with until the typegen is fixed const { data: githubReposData, isLoading: isLoadingGitHubRepos } = useGitHubRepositoriesQuery< diff --git a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthApps.tsx b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthApps.tsx index 8744880f1a8..512de2049f4 100644 --- a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthApps.tsx +++ b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthApps.tsx @@ -61,7 +61,7 @@ const OAuthApps = () => { if (!canReadOAuthApps) { return ( - + ) } diff --git a/apps/studio/components/interfaces/Organization/Usage/TotalUsage.tsx b/apps/studio/components/interfaces/Organization/Usage/TotalUsage.tsx index f56de7d4206..f664536c08a 100644 --- a/apps/studio/components/interfaces/Organization/Usage/TotalUsage.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/TotalUsage.tsx @@ -58,9 +58,13 @@ const TotalUsage = ({ ) const sortedBillingMetrics = useMemo(() => { - if (!usage) return BILLING_BREAKDOWN_METRICS + if (!usage) return [] - return BILLING_BREAKDOWN_METRICS.slice().sort((a, b) => { + const breakdownMetrics = BILLING_BREAKDOWN_METRICS.filter((metric) => + usage.usages.some((usage) => !usage.available_in_plan || usage.metric === metric.key) + ) + + return breakdownMetrics.slice().sort((a, b) => { const usageMetaA = usage.usages.find((x) => x.metric === a.key) const usageRatioA = typeof usageMetaA !== 'number' @@ -92,8 +96,8 @@ const TotalUsage = ({ section={{ name: 'Usage Summary', description: isUsageBillingEnabled - ? 'Your plan includes a limited amount of usage. If the usage on your organization exceeds these quotas, your subscription will be charged for the overages. It may take up to 24 hours for usage stats to update.' - : 'Your plan includes a limited amount of usage. If the usage on your organization exceeds these quotas, you may experience restrictions, as you are currently not billed for overages. It may take up to 24 hours for usage stats to update.', + ? `Your plan includes a limited amount of usage. If the usage on your organization exceeds these quotas, your subscription will be charged for the overages. It may take up to ${subscription?.usage_based_billing_project_addons ? '1 hour' : '24 hours'} for usage stats to update.` + : `Your plan includes a limited amount of usage. If the usage on your organization exceeds these quotas, you may experience restrictions, as you are currently not billed for overages. It may take up to ${subscription?.usage_based_billing_project_addons ? '1 hour' : '24 hours'} for usage stats to update.`, links: [ { name: 'How billing works', @@ -184,7 +188,8 @@ const TotalUsage = ({
diff --git a/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx b/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx index 60317e059eb..fbf88f42ebb 100644 --- a/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/Usage.constants.tsx @@ -47,7 +47,7 @@ export interface CategoryAttribute { key: string // Property from organization usage attributes: Attribute[] // For querying against stats-daily / infra-monitoring name: string - unit: 'bytes' | 'absolute' | 'percentage' | 'hours' + unit: 'bytes' | 'absolute' | 'percentage' | 'hours' | 'gigabytes' links?: { name: string url: string @@ -56,7 +56,7 @@ export interface CategoryAttribute { chartPrefix?: 'Max' | 'Average' | 'Cumulative' chartSuffix?: string chartDescription: string - additionalInfo?: (subscription?: OrgSubscription, usage?: OrgUsageResponse) => JSX.Element | null + additionalInfo?: (usage?: OrgUsageResponse) => JSX.Element | null } export type CategoryMetaKey = 'bandwidth' | 'sizeCount' | 'activity' | 'compute' @@ -68,7 +68,9 @@ export interface CategoryMeta { attributes: CategoryAttribute[] } -export const USAGE_CATEGORIES: CategoryMeta[] = [ +export const USAGE_CATEGORIES: (subscription?: OrgSubscription) => CategoryMeta[] = ( + subscription +) => [ { key: 'bandwidth', name: 'Bandwidth', @@ -106,15 +108,25 @@ export const USAGE_CATEGORIES: CategoryMeta[] = [ chartPrefix: 'Average', unit: 'bytes', description: - 'Database size refers to the monthly average storage usage, as reported by Postgres. Paid Plans use auto-scaling disks.\nBilling is based on the average daily database size used in GB throughout the billing period. Billing is independent of the provisioned disk size.', + subscription?.usage_based_billing_project_addons === true + ? 'Database size refers to the monthly average database space usage, as reported by Postgres. Paid Plans use auto-scaling disks and are billed based on provisioned disk size, rather than database space used.' + : 'Database size refers to the monthly average database space usage, as reported by Postgres. Paid Plans use auto-scaling disks.\nBilling is based on the average daily database size used in GB throughout the billing period. Billing is independent of the provisioned disk size.', links: [ { name: 'Documentation', url: 'https://supabase.com/docs/guides/platform/database-size', }, + ...(subscription?.usage_based_billing_project_addons === true + ? [ + { + name: 'Disk Management', + url: 'https://supabase.com/docs/guides/platform/database-size#disk-management', + }, + ] + : []), ], chartDescription: 'The data refreshes every 24 hours.', - additionalInfo: (subscription?: OrgSubscription, usage?: OrgUsageResponse) => { + additionalInfo: (usage?: OrgUsageResponse) => { const usageMeta = usage?.usages.find((x) => x.metric === PricingMetric.DATABASE_SIZE) const usageRatio = typeof usageMeta !== 'number' diff --git a/apps/studio/components/interfaces/Organization/Usage/Usage.utils.ts b/apps/studio/components/interfaces/Organization/Usage/Usage.utils.ts index 4e68b9e278a..62dcce33ae1 100644 --- a/apps/studio/components/interfaces/Organization/Usage/Usage.utils.ts +++ b/apps/studio/components/interfaces/Organization/Usage/Usage.utils.ts @@ -38,6 +38,8 @@ export const ChartYFormatterCompactNumber = (number: number | string, unit: stri const formattedBytes = formatBytesCompact(number).replace(/\s/g, '') return formattedBytes === '0bytes' ? '0' : formattedBytes + } else if (unit === 'gigabytes') { + return compactNumberFormatter.format(number) + 'GB' } else { return compactNumberFormatter.format(number) } @@ -53,6 +55,8 @@ export const ChartTooltipValueFormatter = (number: number | string, unit: string const formattedBytes = formatBytesPrecision(number).replace(/\s/g, '') return formattedBytes === '0bytes' ? '0' : formattedBytes + } else if (unit === 'gigabytes') { + return compactNumberFormatter.format(number) + 'GB' } else { return compactNumberFormatter.format(number) } diff --git a/apps/studio/components/interfaces/Organization/Usage/UsageBarChart.tsx b/apps/studio/components/interfaces/Organization/Usage/UsageBarChart.tsx index 003943ddfa5..937f36c09af 100644 --- a/apps/studio/components/interfaces/Organization/Usage/UsageBarChart.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/UsageBarChart.tsx @@ -21,7 +21,7 @@ export interface UsageBarChartProps { data: DataPoint[] name: string // Used within the tooltip attributes: Attribute[] - unit: 'bytes' | 'absolute' | 'percentage' | 'hours' + unit: 'bytes' | 'absolute' | 'percentage' | 'hours' | 'gigabytes' yLimit?: number yMin?: number yLeftMargin?: number diff --git a/apps/studio/components/interfaces/Organization/Usage/UsageChartTooltips.tsx b/apps/studio/components/interfaces/Organization/Usage/UsageChartTooltips.tsx index da6f20200c6..685c7afb46e 100644 --- a/apps/studio/components/interfaces/Organization/Usage/UsageChartTooltips.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/UsageChartTooltips.tsx @@ -4,7 +4,7 @@ import { Attribute, COLOR_MAP } from './Usage.constants' export interface SingleAttributeTooltipContentProps { name: string - unit: 'bytes' | 'percentage' | 'absolute' | 'hours' + unit: 'bytes' | 'percentage' | 'absolute' | 'hours' | 'gigabytes' value: any isAfterToday: boolean tooltipFormatter?: (value: any) => any @@ -37,7 +37,7 @@ export interface MultiAttributeTooltipContentProps { values: Payload[] isAfterToday: boolean tooltipFormatter?: (value: any) => any - unit: 'bytes' | 'percentage' | 'absolute' | 'hours' + unit: 'bytes' | 'percentage' | 'absolute' | 'hours' | 'gigabytes' } const AttributeContent = ({ @@ -51,7 +51,7 @@ const AttributeContent = ({ attributeMeta?: Payload sumValue: number tooltipFormatter?: (value: any) => any - unit: 'bytes' | 'percentage' | 'absolute' | 'hours' + unit: 'bytes' | 'percentage' | 'absolute' | 'hours' | 'gigabytes' }) => { const attrValue = Number(attributeMeta?.value ?? 0) const percentageContribution = ((attrValue / sumValue) * 100).toFixed(1) diff --git a/apps/studio/components/interfaces/Organization/Usage/UsageSection/AttributeUsage.tsx b/apps/studio/components/interfaces/Organization/Usage/UsageSection/AttributeUsage.tsx index e0a01bd76c1..bebc034cb83 100644 --- a/apps/studio/components/interfaces/Organization/Usage/UsageSection/AttributeUsage.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/UsageSection/AttributeUsage.tsx @@ -93,7 +93,7 @@ const AttributeUsage = ({ {isSuccess && ( <> - {usageMeta?.available_in_plan ? ( + {!usageMeta || usageMeta?.available_in_plan ? ( <> {!projectRef && (
@@ -150,7 +150,7 @@ const AttributeUsage = ({
- {currentBillingCycleSelected && !usageMeta.unlimited && ( + {currentBillingCycleSelected && usageMeta && !usageMeta.unlimited && ( )} - { -
+
+ {usageMeta && (

Included in {subscription?.plan?.name.toLowerCase()} plan @@ -179,43 +179,42 @@ const AttributeUsage = ({

Unlimited

) : (

- {attribute.unit === 'bytes' + {attribute.unit === 'bytes' || attribute.unit === 'gigabytes' ? `${usageMeta.pricing_free_units ?? 0} GB` : (usageMeta.pricing_free_units ?? 0).toLocaleString()}

)}
- {currentBillingCycleSelected && ( -
-

- {attribute.chartPrefix || 'Used '} in period -

-

- {attribute.unit === 'bytes' - ? `${(usageMeta?.usage ?? 0).toFixed(2)} GB` - : (usageMeta?.usage ?? 0).toLocaleString()} -

-
- )} - {currentBillingCycleSelected && - (usageMeta?.pricing_free_units ?? 0) > 0 && ( -
-

Overage in period

-

- {(usageMeta?.pricing_free_units ?? 0) === -1 || usageExcess < 0 - ? `0${attribute.unit === 'bytes' ? ' GB' : ''}` - : attribute.unit === 'bytes' - ? `${usageExcess.toFixed(2)} GB` - : usageExcess.toLocaleString()} -

-
- )} -
- } + )} + {currentBillingCycleSelected && usageMeta && ( +
+

+ {attribute.chartPrefix || 'Used '} in period +

+

+ {attribute.unit === 'bytes' || attribute.unit === 'gigabytes' + ? `${(usageMeta?.usage ?? 0).toFixed(2)} GB` + : (usageMeta?.usage ?? 0).toLocaleString()} +

+
+ )} + {currentBillingCycleSelected && (usageMeta?.pricing_free_units ?? 0) > 0 && ( +
+

Overage in period

+

+ {(usageMeta?.pricing_free_units ?? 0) === -1 || usageExcess < 0 + ? `0${attribute.unit === 'bytes' || attribute.unit === 'gigabytes' ? ' GB' : ''}` + : attribute.unit === 'bytes' || attribute.unit === 'gigabytes' + ? `${usageExcess.toFixed(2)} GB` + : usageExcess.toLocaleString()} +

+
+ )} +
)} - {attribute.additionalInfo?.(subscription, usage)} + {attribute.additionalInfo?.(usage)}

diff --git a/apps/studio/components/interfaces/Organization/Usage/UsageSection/UsageSection.tsx b/apps/studio/components/interfaces/Organization/Usage/UsageSection/UsageSection.tsx index f5a4fe47b8f..21f118c093f 100644 --- a/apps/studio/components/interfaces/Organization/Usage/UsageSection/UsageSection.tsx +++ b/apps/studio/components/interfaces/Organization/Usage/UsageSection/UsageSection.tsx @@ -35,7 +35,9 @@ const UsageSection = ({ isSuccess: isSuccessUsage, } = useOrgUsageQuery({ orgSlug }) - const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === categoryKey) + const categoryMeta = USAGE_CATEGORIES(subscription).find( + (category) => category.key === categoryKey + ) if (!categoryMeta) return null return ( diff --git a/apps/studio/components/ui/NoPermission.tsx b/apps/studio/components/ui/NoPermission.tsx index ab96619caca..3fb1a0b8554 100644 --- a/apps/studio/components/ui/NoPermission.tsx +++ b/apps/studio/components/ui/NoPermission.tsx @@ -22,7 +22,7 @@ const NoPermission = ({ resourceText, isFullPage = false }: NoPermissionProps) =

You need additional permissions to {resourceText}

- Contact your organization owner or adminstrator for assistance. + Contact your organization owner or administrator for assistance.

diff --git a/apps/studio/data/analytics/org-daily-stats-query.ts b/apps/studio/data/analytics/org-daily-stats-query.ts index 8b74d5e8d30..fa4e3797cc1 100644 --- a/apps/studio/data/analytics/org-daily-stats-query.ts +++ b/apps/studio/data/analytics/org-daily-stats-query.ts @@ -21,6 +21,7 @@ export enum PricingMetric { EGRESS = 'EGRESS', DATABASE_SIZE = 'DATABASE_SIZE', STORAGE_SIZE = 'STORAGE_SIZE', + DISK_SIZE_GB_HOURS = 'DISK_SIZE_GB_HOURS', MONTHLY_ACTIVE_USERS = 'MONTHLY_ACTIVE_USERS', MONTHLY_ACTIVE_SSO_USERS = 'MONTHLY_ACTIVE_SSO_USERS', FUNCTION_INVOCATIONS = 'FUNCTION_INVOCATIONS', diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e59cfb968a2..9edd76f50bc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,7 +10,7 @@ version: "3.8" services: studio: container_name: supabase-studio - image: supabase/studio:20240722-c670708 + image: supabase/studio:20240729-ce42139 restart: unless-stopped healthcheck: test: diff --git a/package-lock.json b/package-lock.json index 480c239c932..6fede8c2768 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7844,8 +7844,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "license": "MIT" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index f1ad7619ef2..a56e891dd08 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -3911,7 +3911,7 @@ export interface components { | 'STORAGE_IMAGES_TRANSFORMED' | 'REALTIME_MESSAGE_COUNT' | 'REALTIME_PEAK_CONNECTIONS' - | 'DISK_GB_HOURS' + | 'DISK_SIZE_GB_HOURS' | 'COMPUTE_HOURS_BRANCH' | 'COMPUTE_HOURS_XS' | 'COMPUTE_HOURS_SM' @@ -3941,7 +3941,6 @@ export interface components { usage_original: number } OrgUsageResponse: { - slugs: string[] usage_billing_enabled: boolean usages: components['schemas']['OrgMetricUsage'][] } @@ -4308,6 +4307,7 @@ export interface components { price_type: components['schemas']['ProjectAddonVariantPricingType'] } ProjectAllocation: { + hours?: number name: string ref: string usage: number @@ -7803,7 +7803,7 @@ export interface operations { | 'STORAGE_IMAGES_TRANSFORMED' | 'REALTIME_MESSAGE_COUNT' | 'REALTIME_PEAK_CONNECTIONS' - | 'DISK_GB_HOURS' + | 'DISK_SIZE_GB_HOURS' | 'COMPUTE_HOURS_BRANCH' | 'COMPUTE_HOURS_XS' | 'COMPUTE_HOURS_SM'