diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.sections.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.sections.tsx index e2b51505797..690635bb508 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.sections.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.sections.tsx @@ -150,6 +150,9 @@ export function DiskSection({ + + + {isAws && } @@ -255,7 +258,7 @@ export function AdvancedSection({ - + diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx index 98cae8cb731..0d9be46fa80 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx @@ -55,12 +55,12 @@ import { AddonVariantId } from '@/data/subscriptions/types' import { useResourceWarningsQuery } from '@/data/usage/resource-warnings-query' import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' -import { useHighAvailability } from '@/hooks/misc/useHighAvailability' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useIsAwsCloudProvider, useIsAwsK8sCloudProvider, useIsAwsNimbusCloudProvider, + useIsHighAvailability, useSelectedProjectQuery, } from '@/hooks/misc/useSelectedProject' import { GB, PROJECT_STATUS } from '@/lib/constants' @@ -102,7 +102,7 @@ export function DiskManagementForm({ const isAws = useIsAwsCloudProvider() const isAwsK8s = useIsAwsK8sCloudProvider() const isAwsNimbus = useIsAwsNimbusCloudProvider() - const { isHighAvailability } = useHighAvailability() + const isHighAvailability = useIsHighAvailability() const { can: canUpdateDiskConfiguration, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions(PermissionAction.UPDATE, 'projects', { @@ -209,9 +209,10 @@ export function DiskManagementForm({ const usedPercentage = (usedSize / totalSize) * 100 const disableIopsThroughputConfig = - modifiedComputeSize && - !isSpendCapEnabled && - RESTRICTED_COMPUTE_FOR_THROUGHPUT_ON_GP3.includes(modifiedComputeSize) + isHighAvailability || + (modifiedComputeSize && + !isSpendCapEnabled && + RESTRICTED_COMPUTE_FOR_THROUGHPUT_ON_GP3.includes(modifiedComputeSize)) const watchedTotalSize = useWatch({ control: form.control, name: 'totalSize' }) ?? 0 const watchedStorageType = useWatch({ control: form.control, name: 'storageType' }) @@ -231,10 +232,11 @@ export function DiskManagementForm({ isRequestingChanges || isPlanUpgradeRequired || isWithinCooldownWindow || + isHighAvailability || !canUpdateDiskConfiguration || !isAws - const disableDiskInputs = disableDiskSizeInput || isSpendCapEnabled + const disableDiskInputs = disableDiskSizeInput || isSpendCapEnabled || isHighAvailability // Compute resizing is not supported for High Availability projects during Alpha const disableComputeInputs = isPlanUpgradeRequired || isHighAvailability diff --git a/apps/studio/components/interfaces/DiskManagement/fields/AutoScaleFields.tsx b/apps/studio/components/interfaces/DiskManagement/fields/AutoScaleFields.tsx index d5651c249df..d2d105de22c 100644 --- a/apps/studio/components/interfaces/DiskManagement/fields/AutoScaleFields.tsx +++ b/apps/studio/components/interfaces/DiskManagement/fields/AutoScaleFields.tsx @@ -17,9 +17,10 @@ import { useDiskAutoscaleCustomConfigQuery } from '@/data/config/disk-autoscale- type AutoScaleFieldProps = { form: UseFormReturn + disableInput?: boolean } -export const AutoScaleFields = ({ form }: AutoScaleFieldProps) => { +export const AutoScaleFields = ({ form, disableInput = false }: AutoScaleFieldProps) => { const { ref: projectRef } = useParams() const { control, @@ -76,7 +77,7 @@ export const AutoScaleFields = ({ form }: AutoScaleFieldProps) => { id={field.name} type="number" value={field.value ?? undefined} - disabled={isError} + disabled={disableInput || isError} onChange={(e) => { setValue( 'growthPercent', @@ -123,7 +124,7 @@ export const AutoScaleFields = ({ form }: AutoScaleFieldProps) => { id={field.name} type="number" value={field.value ?? undefined} - disabled={isError} + disabled={disableInput || isError} onChange={(e) => { setValue( 'minIncrementGb', @@ -165,7 +166,7 @@ export const AutoScaleFields = ({ form }: AutoScaleFieldProps) => { id={field.name} type="number" value={field.value ?? undefined} - disabled={isError} + disabled={disableInput || isError} onChange={(e) => { setValue('maxSizeGb', e.target.value === '' ? null : e.target.valueAsNumber, { shouldDirty: true, diff --git a/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTab.test.tsx b/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTab.test.tsx index 68dd6a4a79f..426e516a4d8 100644 --- a/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTab.test.tsx +++ b/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTab.test.tsx @@ -40,6 +40,7 @@ vi.mock('@/hooks/misc/useSelectedProject', () => ({ data: { ref: 'default', connectionString: 'postgres://localhost' }, }), useIsOrioleDb: () => false, + useIsHighAvailability: () => false, })) vi.mock('common', async (importOriginal) => { diff --git a/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet.test.tsx b/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet.test.tsx index 89f2bef940d..7fcde7fc422 100644 --- a/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet.test.tsx +++ b/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet.test.tsx @@ -15,6 +15,7 @@ vi.mock('@/hooks/misc/useSelectedProject', () => ({ useSelectedProjectQuery: () => ({ data: { ref: 'default', connectionString: 'postgres://localhost' }, }), + useIsHighAvailability: () => false, })) vi.mock('@/hooks/useProtectedSchemas', () => ({ diff --git a/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.test.tsx b/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.test.tsx index 491aaf978fe..8a99bec0ec2 100644 --- a/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.test.tsx +++ b/apps/studio/components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.test.tsx @@ -45,6 +45,7 @@ vi.mock('@/hooks/misc/useHighAvailability', () => ({ vi.mock('@/hooks/misc/useSelectedProject', () => ({ useSelectedProjectQuery: mockUseSelectedProjectQuery, + useIsHighAvailability: () => mockUseHighAvailability().isHighAvailability ?? false, })) vi.mock('@/data/database/max-connections-query', () => ({ diff --git a/apps/studio/components/interfaces/Settings/Database/DiskSizeConfiguration.tsx b/apps/studio/components/interfaces/Settings/Database/DiskSizeConfiguration.tsx index 7cdcf23e888..515cf67241d 100644 --- a/apps/studio/components/interfaces/Settings/Database/DiskSizeConfiguration.tsx +++ b/apps/studio/components/interfaces/Settings/Database/DiskSizeConfiguration.tsx @@ -2,7 +2,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import { ExternalLink, Info } from 'lucide-react' import Link from 'next/link' -import { SetStateAction } from 'react' +import { parseAsBoolean, useQueryState } from 'nuqs' import { toast } from 'sonner' import { Alert, AlertDescription, AlertTitle, Button, InfoIcon } from 'ui' import { @@ -26,9 +26,9 @@ import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useIsAwsNimbusCloudProvider, + useIsHighAvailability, useSelectedProjectQuery, } from '@/hooks/misc/useSelectedProject' -import { useUrlState } from '@/hooks/ui/useUrlState' import { DOCS_URL } from '@/lib/constants' import { formatBytes } from '@/lib/helpers' @@ -42,14 +42,13 @@ export const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfiguratio const { data: organization } = useSelectedOrganizationQuery() const isAwsNimbus = useIsAwsNimbusCloudProvider() + const isHighAvailability = useIsHighAvailability() const { reportsAll } = useIsFeatureEnabled(['reports:all']) - const [{ show_increase_disk_size_modal }, setUrlParams] = useUrlState() - const showIncreaseDiskSizeModal = show_increase_disk_size_modal === 'true' - const setShowIncreaseDiskSizeModal = (value: SetStateAction) => { - const show = typeof value === 'function' ? value(showIncreaseDiskSizeModal) : value - setUrlParams({ show_increase_disk_size_modal: show ? 'true' : undefined }) - } + const [showIncreaseDiskSizeModal, setShowIncreaseDiskSizeModal] = useQueryState( + 'show_increase_disk_size_modal', + parseAsBoolean.withDefault(false) + ) const { can: canUpdateDiskSizeConfig } = useAsyncCheckPermissions( PermissionAction.UPDATE, @@ -110,14 +109,16 @@ export const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfiguratio setShowIncreaseDiskSizeModal(true)} tooltip={{ content: { side: 'bottom', text: !canUpdateDiskSizeConfig ? 'You need additional permissions to increase the disk size' - : undefined, + : isHighAvailability + ? 'Disk size management is unavailable for High Availability projects' + : undefined, }, }} > @@ -219,11 +220,13 @@ Read more about [disk management](${DOCS_URL}/guides/platform/database-size#disk - + {!isHighAvailability && ( + + )} ) } diff --git a/apps/studio/components/ui/HighAvailability/HighAvailabilityDisabledSectionNotice.tsx b/apps/studio/components/ui/HighAvailability/HighAvailabilityDisabledSectionNotice.tsx index 29e7c1f7eee..28a928bcd9c 100644 --- a/apps/studio/components/ui/HighAvailability/HighAvailabilityDisabledSectionNotice.tsx +++ b/apps/studio/components/ui/HighAvailability/HighAvailabilityDisabledSectionNotice.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react' import { Admonition } from 'ui-patterns/Admonition' -import { useHighAvailability } from '@/hooks/misc/useHighAvailability' +import { useIsHighAvailability } from '@/hooks/misc/useSelectedProject' const DEFAULT_TITLE = 'This feature is unavailable on High Availability projects' const DEFAULT_DESCRIPTION = @@ -16,7 +16,7 @@ export function HighAvailabilityDisabledSectionNotice({ title = DEFAULT_TITLE, description = DEFAULT_DESCRIPTION, }: HighAvailabilityDisabledSectionNoticeProps) { - const { isHighAvailability } = useHighAvailability() + const isHighAvailability = useIsHighAvailability() if (!isHighAvailability) return null diff --git a/apps/studio/hooks/misc/useHighAvailability.ts b/apps/studio/hooks/misc/useHighAvailability.ts index 90648f6b802..626a484e623 100644 --- a/apps/studio/hooks/misc/useHighAvailability.ts +++ b/apps/studio/hooks/misc/useHighAvailability.ts @@ -1,14 +1,13 @@ import { useMemo } from 'react' import { MULTIGRES_SCHEMA_NAME, resolveHighAvailability } from './useHighAvailability.constants' -import { useSelectedProjectQuery } from './useSelectedProject' +import { useIsHighAvailability, useSelectedProjectQuery } from './useSelectedProject' export { MULTIGRES_SCHEMA_NAME, resolveHighAvailability } export function useHighAvailability() { - const { data: project, isPending } = useSelectedProjectQuery() - - const isHighAvailability = resolveHighAvailability(project) + const isHighAvailability = useIsHighAvailability() + const { isPending } = useSelectedProjectQuery() return { isHighAvailability, diff --git a/apps/studio/hooks/misc/useSelectedProject.ts b/apps/studio/hooks/misc/useSelectedProject.ts index 27dd57a4b9a..4fd2d5fd894 100644 --- a/apps/studio/hooks/misc/useSelectedProject.ts +++ b/apps/studio/hooks/misc/useSelectedProject.ts @@ -54,6 +54,7 @@ export const useIsOrioleDbInAws = () => { return isOrioleDbInAws } +// [Joshen TODO] There's a duplicate method `resolveHighAvailability` in `useHighAvailability.constants` export const useIsHighAvailability = () => { const { data: project } = useSelectedProjectQuery() return project?.high_availability ?? false diff --git a/apps/studio/pages/project/[ref]/observability/database.tsx b/apps/studio/pages/project/[ref]/observability/database.tsx index 86956d32ab5..20b18cedcd9 100644 --- a/apps/studio/pages/project/[ref]/observability/database.tsx +++ b/apps/studio/pages/project/[ref]/observability/database.tsx @@ -43,7 +43,7 @@ import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' import { useRefreshHandler, useReportDateRange } from '@/hooks/misc/useReportDateRange' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' -import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' +import { useIsHighAvailability, useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { DOCS_URL } from '@/lib/constants' import { formatBytes } from '@/lib/helpers' import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector' @@ -74,6 +74,7 @@ const DatabaseUsage = () => { const { db, chart, ref } = useParams() const { data: project } = useSelectedProjectQuery() const { data: org } = useSelectedOrganizationQuery() + const isHighAvailability = useIsHighAvailability() const { selectedDateRange, @@ -240,6 +241,7 @@ const DatabaseUsage = () => { side="bottom" > ) : ( setshowIncreaseDiskSizeModal(true)} tooltip={{ content: { side: 'bottom', text: !canUpdateDiskSizeConfig ? 'You need additional permissions to increase the disk size' - : undefined, + : isHighAvailability + ? 'Disk size management is unavailable for High Availability projects' + : undefined, }, }} > @@ -432,32 +440,7 @@ const DatabaseUsage = () => { ) }} - append={() => ( -
- - -
-

- New Supabase projects have a database size of ~40-60mb. This space includes - pre-installed extensions, schemas, and default Postgres data. Additional - database size is used when installing extensions, even if those extensions are - inactive. -

- - -
-
-
-
- )} + append={renderDatabaseSizeAdditionalInfo} /> { ) } + +const renderDatabaseSizeAdditionalInfo = () => { + return ( +
+ + +
+

+ New Supabase projects have a database size of ~40-60mb. This space includes + pre-installed extensions, schemas, and default Postgres data. Additional database size + is used when installing extensions, even if those extensions are inactive. +

+ + +
+
+
+
+ ) +}