better no data handling

This commit is contained in:
Kevin Grüneberg committed 2023-06-03 00:24:26 +02:00
1 parent 216f2d4764
commit 620ee49d47
6 files changed
+124 -72

No files matched your search

@@ -2,7 +2,6 @@ import clsx from 'clsx'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import SparkBar from 'components/ui/SparkBar'
import { useDailyStatsQuery } from 'data/analytics/daily-stats-query'
import { useProjectSubscriptionQuery } from 'data/subscriptions/project-subscription-query'
import {
ProjectUsageResponse,
UsageMetric,
@@ -16,10 +15,10 @@ import UsageBarChart from './UsageBarChart'
import SectionContent from './SectionContent'
import SectionHeader from './SectionHeader'
import { USAGE_CATEGORIES } from './Usage.constants'
import { ChartYFormatterCompactNumber, getUpgradeUrl } from './Usage.utils'
import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
import { ChartYFormatterCompactNumber, getUpgradeUrlFromV2Subscription } from './Usage.utils'
import { DataPoint } from 'data/analytics/constants'
import Panel from 'components/ui/Panel'
import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
export interface ActivityProps {
projectRef: string
@@ -27,8 +26,8 @@ export interface ActivityProps {
const Activity = ({ projectRef }: ActivityProps) => {
const { data: usage } = useProjectUsageQuery({ projectRef })
const { data: subscription } = useProjectSubscriptionQuery({ projectRef })
const { current_period_start, current_period_end } = subscription?.billing ?? {}
const { data: subscription } = useProjectSubscriptionV2Query({ projectRef })
const { current_period_start, current_period_end } = subscription ?? {}
const startDate =
current_period_start !== undefined
? new Date(current_period_start * 1000).toISOString()
@@ -53,11 +52,9 @@ const Activity = ({ projectRef }: ActivityProps) => {
const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === 'activity')
const upgradeUrl = getUpgradeUrl(projectRef, subscription)
const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription)
const isFreeTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.FREE
const isProTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.PRO
const usageBasedBilling = !isFreeTier && !isProTier
const usageBasedBilling = subscription?.usage_billing_enabled
const exceededLimitStyle = !usageBasedBilling ? 'text-red-900' : 'text-amber-900'
const { data: mauData, isLoading: isLoadingMauData } = useDailyStatsQuery({
@@ -168,6 +165,10 @@ const Activity = ({ projectRef }: ActivityProps) => {
const chartData = chartMeta[attribute.key]?.data ?? []
const notAllValuesZero = chartData.some(
(dataPoint) => Number(dataPoint[attribute.attribute]) !== 0
)
return (
<div id={attribute.anchor} key={attribute.key}>
<SectionContent section={attribute} includedInPlan={usageMeta?.available_in_plan}>
@@ -227,7 +228,7 @@ const Activity = ({ projectRef }: ActivityProps) => {
<div>
<div className="flex items-center justify-between border-b py-1">
<p className="text-xs text-scale-1000">
Included in {subscription?.tier.name.toLowerCase()}
Included in {subscription?.plan?.name.toLowerCase()} plan
</p>
{usageMeta?.limit === -1 ? (
<p className="text-xs">None</p>
@@ -270,7 +271,7 @@ const Activity = ({ projectRef }: ActivityProps) => {
<ShimmeringLoader className="w-3/4" />
<ShimmeringLoader className="w-1/2" />
</div>
) : (
) : chartData.length > 1 && notAllValuesZero ? (
<UsageBarChart
name={`${attribute.chartPrefix || ''}${attribute.name}`}
unit={attribute.unit}
@@ -279,6 +280,17 @@ const Activity = ({ projectRef }: ActivityProps) => {
yLeftMargin={chartMeta[attribute.key].margin}
yFormatter={(value) => ChartYFormatterCompactNumber(value, attribute.unit)}
/>
) : (
<Panel>
<Panel.Content>
<div className="flex flex-col items-center justify-center space-y-2">
<p>No data</p>
<p className="text-sm text-scale-1000">
No {notAllValuesZero ? 'data' : 'usage'} in period
</p>
</div>
</Panel.Content>
</Panel>
)}
</>
) : (
@@ -3,7 +3,6 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import SparkBar from 'components/ui/SparkBar'
import { DataPoint } from 'data/analytics/constants'
import { useDailyStatsQuery } from 'data/analytics/daily-stats-query'
import { useProjectSubscriptionQuery } from 'data/subscriptions/project-subscription-query'
import {
ProjectUsageResponse,
UsageMetric,
@@ -17,8 +16,14 @@ import { Button, IconAlertTriangle } from 'ui'
import SectionContent from './SectionContent'
import SectionHeader from './SectionHeader'
import { USAGE_CATEGORIES } from './Usage.constants'
import { ChartYFormatterCompactNumber, getUpgradeUrl } from './Usage.utils'
import {
ChartYFormatterCompactNumber,
getUpgradeUrl,
getUpgradeUrlFromV2Subscription,
} from './Usage.utils'
import UsageBarChart from './UsageBarChart'
import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
import Panel from 'components/ui/Panel'
export interface BandwidthProps {
projectRef: string
@@ -26,8 +31,8 @@ export interface BandwidthProps {
const Bandwidth = ({ projectRef }: BandwidthProps) => {
const { data: usage } = useProjectUsageQuery({ projectRef })
const { data: subscription } = useProjectSubscriptionQuery({ projectRef })
const { current_period_start, current_period_end } = subscription?.billing ?? {}
const { data: subscription } = useProjectSubscriptionV2Query({ projectRef })
const { current_period_start, current_period_end } = subscription ?? {}
const startDate =
current_period_start !== undefined
? new Date(current_period_start * 1000).toISOString()
@@ -42,10 +47,8 @@ const Bandwidth = ({ projectRef }: BandwidthProps) => {
const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === 'bandwidth')
const upgradeUrl = getUpgradeUrl(projectRef, subscription)
const isFreeTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.FREE
const isProTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.PRO
const usageBasedBilling = !isFreeTier && !isProTier
const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription)
const usageBasedBilling = subscription?.usage_billing_enabled
const exceededLimitStyle = !usageBasedBilling ? 'text-red-900' : 'text-amber-900'
const { data: dbEgressData, isLoading: isLoadingDbEgressData } = useDailyStatsQuery({
@@ -95,6 +98,10 @@ const Bandwidth = ({ projectRef }: BandwidthProps) => {
const chartData = chartMeta[attribute.key]?.data ?? []
const notAllValuesZero = chartData.some(
(dataPoint) => Number(dataPoint[attribute.attribute]) !== 0
)
return (
<div id={attribute.anchor} key={attribute.key}>
<SectionContent section={attribute}>
@@ -148,7 +155,7 @@ const Bandwidth = ({ projectRef }: BandwidthProps) => {
<div>
<div className="flex items-center justify-between border-b py-1">
<p className="text-xs text-scale-1000">
Included in {subscription?.tier.name.toLowerCase()}
Included in {subscription?.plan?.name.toLowerCase()} plan
</p>
<p className="text-xs">
{usageMeta?.limit === 0 ? 'Unlimited' : formatBytes(usageMeta?.limit ?? 0)}
@@ -184,7 +191,7 @@ const Bandwidth = ({ projectRef }: BandwidthProps) => {
<ShimmeringLoader className="w-3/4" />
<ShimmeringLoader className="w-1/2" />
</div>
) : (
) : chartData.length > 1 && notAllValuesZero ? (
<UsageBarChart
name={`${attribute.chartPrefix || ''}${attribute.name}`}
unit={attribute.unit}
@@ -193,6 +200,17 @@ const Bandwidth = ({ projectRef }: BandwidthProps) => {
yLeftMargin={chartMeta[attribute.key].margin}
yFormatter={(value) => ChartYFormatterCompactNumber(value, attribute.unit)}
/>
) : (
<Panel>
<Panel.Content>
<div className="flex flex-col items-center justify-center space-y-2">
<p>No data</p>
<p className="text-sm text-scale-1000">
No {notAllValuesZero ? 'data' : 'usage'} in period
</p>
</div>
</Panel.Content>
</Panel>
)}
</SectionContent>
</div>
@@ -1,7 +1,6 @@
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { DataPoint } from 'data/analytics/constants'
import { useInfraMonitoringQuery } from 'data/analytics/infra-monitoring-query'
import { useProjectSubscriptionQuery } from 'data/subscriptions/project-subscription-query'
import dayjs from 'dayjs'
import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
import Link from 'next/link'
@@ -9,9 +8,10 @@ import { Alert, Button } from 'ui'
import SectionContent from './SectionContent'
import SectionHeader from './SectionHeader'
import { COMPUTE_INSTANCE_SPECS, USAGE_CATEGORIES } from './Usage.constants'
import { getUpgradeUrl } from './Usage.utils'
import { getUpgradeUrl, getUpgradeUrlFromV2Subscription } from './Usage.utils'
import UsageBarChart from './UsageBarChart'
import Panel from 'components/ui/Panel'
import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
export interface InfrastructureProps {
projectRef: string
@@ -20,8 +20,8 @@ export interface InfrastructureProps {
// [Joshen] Need to update the IO budget chart to show burst mbps and duration next time
const Infrastructure = ({ projectRef }: InfrastructureProps) => {
const { data: subscription } = useProjectSubscriptionQuery({ projectRef })
const { current_period_start, current_period_end } = subscription?.billing ?? {}
const { data: subscription } = useProjectSubscriptionV2Query({ projectRef })
const { current_period_start, current_period_end } = subscription ?? {}
const startDate =
current_period_start !== undefined
? new Date(current_period_start * 1000).toISOString()
@@ -37,8 +37,8 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => {
const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === 'infra')
const upgradeUrl = getUpgradeUrl(projectRef, subscription)
const isFreeTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.FREE
const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription)
const isFreeTier = subscription?.plan?.id === 'free'
const currentComputeInstance = subscription?.addons.find((addon) =>
addon.supabase_prod_id.includes('_instance_')
)
@@ -249,9 +249,7 @@ const Infrastructure = ({ projectRef }: InfrastructureProps) => {
<Panel.Content>
<div className="flex flex-col items-center justify-center space-y-2">
<p>No data</p>
<p className="text-sm text-scale-1000">
There is no data in the timeframe available
</p>
<p className="text-sm text-scale-1000">There is no data in period</p>
</div>
</Panel.Content>
</Panel>
@@ -2,14 +2,12 @@ import clsx from 'clsx'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import SparkBar from 'components/ui/SparkBar'
import { useDailyStatsQuery } from 'data/analytics/daily-stats-query'
import { useProjectSubscriptionQuery } from 'data/subscriptions/project-subscription-query'
import {
ProjectUsageResponse,
UsageMetric,
useProjectUsageQuery,
} from 'data/usage/project-usage-query'
import dayjs from 'dayjs'
import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
import { formatBytes } from 'lib/helpers'
import Link from 'next/link'
import { Badge, Button, IconAlertTriangle, IconExternalLink } from 'ui'
@@ -18,8 +16,10 @@ import UsageBarChart from './UsageBarChart'
import SectionContent from './SectionContent'
import SectionHeader from './SectionHeader'
import { USAGE_CATEGORIES } from './Usage.constants'
import { ChartYFormatterCompactNumber, getUpgradeUrl } from './Usage.utils'
import { ChartYFormatterCompactNumber, getUpgradeUrlFromV2Subscription } from './Usage.utils'
import { DataPoint } from 'data/analytics/constants'
import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
import Panel from 'components/ui/Panel'
export interface SizeAndCountsProps {
projectRef: string
@@ -27,8 +27,8 @@ export interface SizeAndCountsProps {
const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
const { data: usage } = useProjectUsageQuery({ projectRef })
const { data: subscription } = useProjectSubscriptionQuery({ projectRef })
const { current_period_start, current_period_end } = subscription?.billing ?? {}
const { data: subscription } = useProjectSubscriptionV2Query({ projectRef })
const { current_period_start, current_period_end } = subscription ?? {}
const startDate =
current_period_start !== undefined
? new Date(current_period_start * 1000).toISOString()
@@ -43,10 +43,8 @@ const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
const categoryMeta = USAGE_CATEGORIES.find((category) => category.key === 'sizeCount')
const upgradeUrl = getUpgradeUrl(projectRef, subscription)
const isFreeTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.FREE
const isProTier = subscription?.tier.supabase_prod_id === PRICING_TIER_PRODUCT_IDS.PRO
const usageBasedBilling = !isFreeTier && !isProTier
const upgradeUrl = getUpgradeUrlFromV2Subscription(projectRef, subscription)
const usageBasedBilling = subscription?.usage_billing_enabled
const exceededLimitStyle = !usageBasedBilling ? 'text-red-900' : 'text-amber-900'
const { data: dbSizeData, isLoading: isLoadingDbSizeData } = useDailyStatsQuery({
@@ -110,6 +108,10 @@ const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
const chartData = chartMeta[attribute.key]?.data ?? []
const notAllValuesZero = chartData.some(
(dataPoint) => Number(dataPoint[attribute.attribute]) !== 0
)
return (
<div id={attribute.anchor} key={attribute.key}>
<SectionContent section={attribute}>
@@ -164,7 +166,7 @@ const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
<div>
<div className="flex items-center justify-between border-b py-1">
<p className="text-xs text-scale-1000">
Included in {subscription?.tier.name.toLowerCase()}
Included in {subscription?.plan?.name.toLowerCase()} plan
</p>
<p className="text-xs">
{attribute.unit === 'bytes'
@@ -199,25 +201,24 @@ const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
</div>
</div>
{attribute.key === 'db_size' &&
subscription?.tier.supabase_prod_id !== PRICING_TIER_PRODUCT_IDS.FREE && (
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<p className="text-sm">Disk size:</p>
<p className="text-sm">{usage?.disk_volume_size_gb} GB</p>
<Badge color="green" size="small">
Auto-scaling
</Badge>
</div>
<Link href="https://supabase.com/docs/guides/platform/database-usage#disk-management">
<a>
<Button size="tiny" type="default" icon={<IconExternalLink size={14} />}>
What is disk size?
</Button>
</a>
</Link>
{attribute.key === 'db_size' && subscription?.plan?.id !== 'free' && (
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<p className="text-sm">Disk size:</p>
<p className="text-sm">{usage?.disk_volume_size_gb} GB</p>
<Badge color="green" size="small">
Auto-scaling
</Badge>
</div>
)}
<Link href="https://supabase.com/docs/guides/platform/database-usage#disk-management">
<a>
<Button size="tiny" type="default" icon={<IconExternalLink size={14} />}>
What is disk size?
</Button>
</a>
</Link>
</div>
)}
<div className="space-y-1">
<p>
@@ -236,7 +237,7 @@ const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
<ShimmeringLoader className="w-3/4" />
<ShimmeringLoader className="w-1/2" />
</div>
) : (
) : chartData.length > 1 && notAllValuesZero ? (
<UsageBarChart
name={`${attribute.chartPrefix || ''}${attribute.name}`}
unit={attribute.unit}
@@ -245,6 +246,17 @@ const SizeAndCounts = ({ projectRef }: SizeAndCountsProps) => {
yLeftMargin={chartMeta[attribute.key].margin}
yFormatter={(value) => ChartYFormatterCompactNumber(value, attribute.unit)}
/>
) : (
<Panel>
<Panel.Content>
<div className="flex flex-col items-center justify-center space-y-2">
<p>No data</p>
<p className="text-sm text-scale-1000">
No {notAllValuesZero ? 'data' : 'usage'} in period
</p>
</div>
</Panel.Content>
</Panel>
)}
</SectionContent>
</div>
@@ -1,11 +1,10 @@
import clsx from 'clsx'
import { useParams } from 'common'
import { useProjectSubscriptionQuery } from 'data/subscriptions/project-subscription-query'
import { useProjectUsageQuery } from 'data/usage/project-usage-query'
import dayjs from 'dayjs'
import Link from 'next/link'
import { useRef, useState } from 'react'
import { Button, IconAlertCircle, IconCheckCircle, IconLoader, Listbox } from 'ui'
import { Button, IconAlertCircle, IconLoader, Listbox } from 'ui'
import Activity from './Activity'
import Bandwidth from './Bandwidth'
import Infrastructure from './Infrastructure'
@@ -13,7 +12,7 @@ import SizeAndCounts from './SizeAndCounts'
import { USAGE_CATEGORIES, USAGE_STATUS } from './Usage.constants'
import { getUsageStatus } from './Usage.utils'
import { useInfraMonitoringQuery } from 'data/analytics/infra-monitoring-query'
import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
const Usage = () => {
const { ref } = useParams()
@@ -28,11 +27,11 @@ const Usage = () => {
const activityRef = useRef<HTMLDivElement>(null)
const { data: usage } = useProjectUsageQuery({ projectRef: ref })
const { data: subscription, isLoading: isLoadingSubscription } = useProjectSubscriptionQuery({
const { data: subscription, isLoading: isLoadingSubscription } = useProjectSubscriptionV2Query({
projectRef: selectedProjectRef,
})
const { current_period_start, current_period_end } = subscription?.billing ?? {}
const { current_period_start, current_period_end } = subscription ?? {}
const startDate =
current_period_start !== undefined
? new Date(current_period_start * 1000).toISOString()
@@ -52,13 +51,10 @@ const Usage = () => {
] ?? 100
)
const billingCycleStart = dayjs.unix(subscription?.billing?.current_period_start ?? 0).utc()
const billingCycleEnd = dayjs.unix(subscription?.billing?.current_period_end ?? 0).utc()
const billingCycleStart = dayjs.unix(subscription?.current_period_start ?? 0).utc()
const billingCycleEnd = dayjs.unix(subscription?.current_period_end ?? 0).utc()
const subscriptionTierId = subscription?.tier?.supabase_prod_id
const usageBillingEnabled =
subscriptionTierId !== PRICING_TIER_PRODUCT_IDS.FREE &&
subscriptionTierId !== PRICING_TIER_PRODUCT_IDS.PRO
const usageBillingEnabled = subscription?.usage_billing_enabled
const scrollTo = (id: 'infra' | 'bandwidth' | 'sizeCount' | 'activity') => {
switch (id) {
@@ -107,7 +103,7 @@ const Usage = () => {
) : subscription !== undefined ? (
<div>
<p className={clsx('text-sm transition', isLoadingSubscription && 'opacity-50')}>
Project is on {subscription.tier.name}
Project is on {subscription.plan.name} plan
</p>
<p className="text-sm text-scale-1000">
{billingCycleStart.format('DD MMM YYYY')} -{' '}
@@ -5,6 +5,7 @@ import { CategoryAttribute, USAGE_STATUS } from './Usage.constants'
import { StripeSubscription } from 'components/interfaces/Billing'
import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
import { formatBytes } from 'lib/helpers'
import { ProjectSubscriptionResponse } from 'data/subscriptions/project-subscription-v2-query'
// [Joshen] This is just for development to generate some test data for chart rendering
export const generateUsageData = (attribute: string, days: number): DataPoint[] => {
@@ -48,6 +49,21 @@ export const getUpgradeUrl = (projectRef: string, subscription?: StripeSubscript
: `/project/${projectRef}/settings/billing/update/pro`
}
export const getUpgradeUrlFromV2Subscription = (
projectRef: string,
subscription?: ProjectSubscriptionResponse
) => {
if (!subscription) return `/project/${projectRef}/settings/billing/update`
return subscription?.plan.id === 'enterprise'
? `/project/${projectRef}/settings/billing/update/enterprise`
: subscription?.plan.id === 'team'
? `/project/${projectRef}/settings/billing/update/team`
: subscription?.plan.id === 'free'
? `/project/${projectRef}/settings/billing/update`
: `/project/${projectRef}/settings/billing/update/pro`
}
const compactNumberFormatter = new Intl.NumberFormat('en-US', {
notation: 'compact',
compactDisplay: 'short',
@@ -58,7 +74,7 @@ export const ChartYFormatterCompactNumber = (number: number | string, unit: stri
if (unit === 'bytes') {
const formattedBytes = formatBytes(number, 0).replace(/\s/g, '')
return formattedBytes === '0bytes' ? '0' : formattedBytes
} else {
return compactNumberFormatter.format(number)