diff --git a/studio/components/interfaces/Settings/ProjectUsageBars/ProjectUsageBars.tsx b/studio/components/interfaces/Settings/ProjectUsageBars/ProjectUsageBars.tsx index a7d3134706e..4e29da3c019 100644 --- a/studio/components/interfaces/Settings/ProjectUsageBars/ProjectUsageBars.tsx +++ b/studio/components/interfaces/Settings/ProjectUsageBars/ProjectUsageBars.tsx @@ -1,5 +1,14 @@ -import { FC, useEffect } from 'react' -import { Badge, Button, IconAlertCircle, IconInfo, Loading, IconExternalLink } from 'ui' +import { FC, useEffect, useState } from 'react' +import { + Badge, + Button, + IconAlertCircle, + IconInfo, + Loading, + IconExternalLink, + Alert, + IconBookOpen, +} from 'ui' import { useStore } from 'hooks' import { formatBytes } from 'lib/helpers' @@ -11,6 +20,9 @@ import { USAGE_BASED_PRODUCTS } from 'components/interfaces/Billing/Billing.cons import { ProjectUsageResponseUsageKeys, useProjectUsageQuery } from 'data/usage/project-usage-query' import { useRouter } from 'next/router' import * as Tooltip from '@radix-ui/react-tooltip' +import Link from 'next/link' +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' +import { executeSql } from 'data/sql/execute-sql-query' interface Props { projectRef?: string @@ -21,8 +33,10 @@ const ProjectUsage: FC = ({ projectRef }) => { const { data: usage, error, isLoading } = useProjectUsageQuery({ projectRef }) const router = useRouter() - const subscriptionTier = ui.selectedProject?.subscription_tier + const { project } = useProjectContext() + const [isReadOnlyMode, setIsReadOnlyMode] = useState(false) + const subscriptionTier = ui.selectedProject?.subscription_tier const projectHasNoLimits = subscriptionTier === PRICING_TIER_PRODUCT_IDS.PAYG || subscriptionTier === PRICING_TIER_PRODUCT_IDS.TEAM || @@ -59,6 +73,20 @@ const ProjectUsage: FC = ({ projectRef }) => { /> ) } + // [Terry] + // temporary solution to check if project is in read only mode + // until we get an api endpoint for this + + async function checkForReadOnlyMode() { + const sql = `show default_transaction_read_only;` + const connectionString = project?.connectionString + const { result: readOnlyStatus } = await executeSql({ projectRef, connectionString, sql }) + if (readOnlyStatus[0]?.default_transaction_read_only === 'on') setIsReadOnlyMode(true) + } + + useEffect(() => { + checkForReadOnlyMode() + }) const isPaidTier = subscriptionTier !== PRICING_TIER_PRODUCT_IDS.FREE @@ -127,7 +155,6 @@ const ProjectUsage: FC = ({ projectRef }) => { - {/* Line items */} {usage === undefined ? (
@@ -253,6 +280,44 @@ const ProjectUsage: FC = ({ projectRef }) => { )} + + {!isReadOnlyMode && product.title === 'Database' && ( +
+ +
+ {isPaidTier ? ( +

+ Your disk has reached 90% capacity. For Pro and Enterprise projects, + disk size expands ~1.5x automatically (e.g., 8GB to 12GB), but can only + occur once every six hours.{' '} +

+ ) : ( +

+ This project is on the Free tier. Consider{' '} + + upgrading + {' '} + to resume service as usual. +

+ )} + +

+ +

+
+
+
+ )}
) })} diff --git a/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx b/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx index cf8789a80e2..bfb11815157 100644 --- a/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx +++ b/studio/components/layouts/ProjectLayout/LayoutHeader/LayoutHeader.tsx @@ -11,19 +11,43 @@ import HelpPopover from './HelpPopover' import NotificationsPopover from './NotificationsPopover' import { getResourcesExceededLimits } from 'components/ui/OveragesBanner/OveragesBanner.utils' import { useProjectUsageQuery } from 'data/usage/project-usage-query' +import { Badge } from 'ui' +import { executeSql } from 'data/sql/execute-sql-query' +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' + +import { useEffect, useState } from 'react' const LayoutHeader = ({ customHeaderComponents, breadcrumbs = [], headerBorder = true }: any) => { const { ui } = useStore() const { selectedOrganization, selectedProject } = ui const { ref: projectRef } = useParams() + const { project } = useProjectContext() + + const [isReadOnlyMode, setIsReadOnlyMode] = useState(false) + + // [Terry] + // temporary solution to check if project is in read only mode + // until we get an api endpoint for this + async function checkForReadOnlyMode() { + const sql = `show default_transaction_read_only;` + const connectionString = project?.connectionString + const { result: readOnlyStatus } = await executeSql({ projectRef, connectionString, sql }) + if (readOnlyStatus[0]?.default_transaction_read_only === 'on') setIsReadOnlyMode(true) + } + + useEffect(() => { + checkForReadOnlyMode() + }) const { data: usage } = useProjectUsageQuery({ projectRef }) const resourcesExceededLimits = getResourcesExceededLimits(usage) + const projectHasNoLimits = ui.selectedProject?.subscription_tier === PRICING_TIER_PRODUCT_IDS.PAYG || ui.selectedProject?.subscription_tier === PRICING_TIER_PRODUCT_IDS.ENTERPRISE || ui.selectedProject?.subscription_tier === PRICING_TIER_PRODUCT_IDS.TEAM + const showOverUsageBadge = selectedProject?.subscription_tier !== undefined && !projectHasNoLimits && @@ -63,6 +87,20 @@ const LayoutHeader = ({ customHeaderComponents, breadcrumbs = [], headerBorder = {/* Project Dropdown */} + {/* [Terry] Temporary until we figure out how we want to display this permanently */} + {/* context: https://www.notion.so/supabase/DB-Disk-Size-Free-tier-Read-only-Critical-f2b8937c13a149e3ac769fe5888f6db0*/} + {!isReadOnlyMode && ( +
+ + + + Project limits exceeded. Project in read-only mode. + + + +
+ )} + {/* [Joshen TODO] Temporarily hidden until usage endpoint is sorted out */} {/* {showOverUsageBadge && (