import { PermissionAction } from '@supabase/shared-types/out/constants' import dayjs from 'dayjs' import Link from 'next/link' import { useMemo, useState } from 'react' import { useParams } from 'common' import { ScaffoldContainer, ScaffoldHeader, ScaffoldSection, ScaffoldTitle, } from 'components/layouts/Scaffold' import AlertError from 'components/ui/AlertError' import DateRangePicker from 'components/ui/DateRangePicker' import NoPermission from 'components/ui/NoPermission' import { OrganizationProjectSelector } from 'components/ui/OrganizationProjectSelector' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useOrgDailyStatsQuery } from 'data/analytics/org-daily-stats-query' import { useProjectDetailQuery } from 'data/projects/project-detail-query' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { TIME_PERIODS_BILLING, TIME_PERIODS_REPORTS } from 'lib/constants/metrics' import { Check, ChevronDown } from 'lucide-react' import { useQueryState } from 'nuqs' import { Button, cn, CommandGroup_Shadcn_, CommandItem_Shadcn_ } from 'ui' import { Admonition } from 'ui-patterns' import { Restriction } from '../BillingSettings/Restriction' import Activity from './Activity' import Compute from './Compute' import Egress from './Egress' import SizeAndCounts from './SizeAndCounts' import { TotalUsage } from './TotalUsage' export const Usage = () => { const { slug } = useParams() const [dateRange, setDateRange] = useState() const [selectedProjectRef, setSelectedProjectRef] = useQueryState('projectRef') const [openProjectSelector, setOpenProjectSelector] = useState(false) const { can: canReadSubscriptions, isLoading: isLoadingPermissions } = useAsyncCheckPermissions( PermissionAction.BILLING_READ, 'stripe.subscriptions' ) const { data: subscription, error: subscriptionError, isPending: isLoadingSubscription, isError: isErrorSubscription, isSuccess: isSuccessSubscription, } = useOrgSubscriptionQuery({ orgSlug: slug }) const { data: selectedProject } = useProjectDetailQuery({ ref: selectedProjectRef ?? undefined, }) const billingCycleStart = useMemo(() => { return dayjs.unix(subscription?.current_period_start ?? 0).utc() }, [subscription]) const billingCycleEnd = useMemo(() => { return dayjs.unix(subscription?.current_period_end ?? 0).utc() }, [subscription]) const currentBillingCycleSelected = useMemo(() => { // Selected by default if (!dateRange?.period_start || !dateRange?.period_end) return true return ( dayjs(dateRange.period_start.date).isSame(billingCycleStart) && dayjs(dateRange.period_end.date).isSame(billingCycleEnd) ) }, [dateRange, billingCycleStart, billingCycleEnd]) const startDate = useMemo(() => { // If end date is in future, set end date to now if (!dateRange?.period_start?.date) { return undefined } else { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes return new Date(dateRange?.period_start?.date).toISOString().slice(0, -5) + 'Z' } // eslint-disable-next-line react-hooks/exhaustive-deps }, [dateRange, subscription]) const endDate = useMemo(() => { // If end date is in future, set end date to end of current day if (dateRange?.period_end?.date && dayjs(dateRange.period_end.date).isAfter(dayjs())) { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes // In order to have full days from Prometheus metrics when using 1d interval, // the time needs to be greater or equal than the time of the start date return dayjs().endOf('day').toISOString().slice(0, -5) + 'Z' } else if (dateRange?.period_end?.date) { // LF seems to have an issue with the milliseconds, causes infinite loading sometimes return new Date(dateRange.period_end.date).toISOString().slice(0, -5) + 'Z' } // eslint-disable-next-line react-hooks/exhaustive-deps }, [dateRange, subscription]) const { data: orgDailyStats, error: orgDailyStatsError, isPending: isLoadingOrgDailyStats, isError: isErrorOrgDailyStats, } = useOrgDailyStatsQuery({ orgSlug: slug, projectRef: selectedProjectRef ?? undefined, startDate, endDate, }) return ( <> Usage
{isLoadingSubscription || isLoadingPermissions ? (
) : !canReadSubscriptions ? ( ) : null} {isErrorSubscription && ( )} {isSuccessSubscription && (
{ setSelectedProjectRef(project.ref) }} renderTrigger={() => { return ( ) }} renderRow={(project) => { const isSelected = selectedProjectRef === project.ref return (
{project.name} {isSelected && }
) }} renderActions={() => ( { setOpenProjectSelector(false) setSelectedProjectRef(null) }} onClick={() => { setOpenProjectSelector(false) setSelectedProjectRef(null) }} > All projects {!selectedProjectRef && } )} />

Organization is on the{' '} {subscription.plan.name} Plan

{billingCycleStart.format('DD MMM YYYY')} -{' '} {billingCycleEnd.format('DD MMM YYYY')}

)}
{isErrorOrgDailyStats && ( )} {selectedProject ? ( You are currently viewing usage for the{' '} {selectedProject?.name || selectedProjectRef} {' '} project. Supabase uses{' '} organization-level billing {' '} and quotas. For billing purposes, we sum up usage from all your projects. To view your usage quota, set the project filter above back to "All Projects". } /> ) : ( )} {subscription?.plan.id !== 'free' && ( )} ) }