pitr.tsx144 lines · main
1import { PermissionAction } from '@supabase/shared-types/out/constants'
2import { useParams } from 'common'
3import { AlertCircle } from 'lucide-react'
4import { Alert, AlertDescription, AlertTitle } from 'ui'
5import { Admonition } from 'ui-patterns'
6import { PageContainer } from 'ui-patterns/PageContainer'
7import {
8 PageHeader,
9 PageHeaderMeta,
10 PageHeaderNavigationTabs,
11 PageHeaderSummary,
12 PageHeaderTitle,
13} from 'ui-patterns/PageHeader'
14import { PageSection, PageSectionContent } from 'ui-patterns/PageSection'
15import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
16
17import DatabaseBackupsNav from '@/components/interfaces/Database/Backups/DatabaseBackupsNav'
18import { PITRNotice } from '@/components/interfaces/Database/Backups/PITR/PITRNotice'
19import { PITRSelection } from '@/components/interfaces/Database/Backups/PITR/PITRSelection'
20import DatabaseLayout from '@/components/layouts/DatabaseLayout/DatabaseLayout'
21import DefaultLayout from '@/components/layouts/DefaultLayout'
22import AlertError from '@/components/ui/AlertError'
23import { DocsButton } from '@/components/ui/DocsButton'
24import NoPermission from '@/components/ui/NoPermission'
25import { UpgradeToPro } from '@/components/ui/UpgradeToPro'
26import { useBackupsQuery } from '@/data/database/backups-query'
27import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
28import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
29import { useIsOrioleDbInAws, useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
30import { DOCS_URL, PROJECT_STATUS } from '@/lib/constants'
31import type { NextPageWithLayout } from '@/types'
32
33const DatabasePhysicalBackups: NextPageWithLayout = () => {
34 return (
35 <>
36 <PageHeader>
37 <PageHeaderMeta>
38 <PageHeaderSummary>
39 <PageHeaderTitle>Database Backups</PageHeaderTitle>
40 </PageHeaderSummary>
41 </PageHeaderMeta>
42 <PageHeaderNavigationTabs>
43 <DatabaseBackupsNav active="pitr" />
44 </PageHeaderNavigationTabs>
45 </PageHeader>
46 <PageContainer>
47 <PageSection>
48 <PageSectionContent>
49 <div className="space-y-8">
50 <PITR />
51 </div>
52 </PageSectionContent>
53 </PageSection>
54 </PageContainer>
55 </>
56 )
57}
58
59DatabasePhysicalBackups.getLayout = (page) => (
60 <DefaultLayout>
61 <DatabaseLayout title="Backups">{page}</DatabaseLayout>
62 </DefaultLayout>
63)
64
65const PITR = () => {
66 const { ref: projectRef } = useParams()
67 const { data: project } = useSelectedProjectQuery()
68 const { hasAccess: hasAccessToPitr, isLoading: isLoadingEntitlements } =
69 useCheckEntitlements('pitr.available_variants')
70 const isOrioleDbInAws = useIsOrioleDbInAws()
71 const {
72 data: backups,
73 error,
74 isPending: isLoadingBackups,
75 isError,
76 isSuccess,
77 } = useBackupsQuery({ projectRef })
78
79 const isLoading = isLoadingBackups || isLoadingEntitlements
80 const isEnabled = backups?.pitr_enabled
81 const isActiveHealthy = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
82
83 const { can: canReadPhysicalBackups, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions(
84 PermissionAction.READ,
85 'physical_backups'
86 )
87
88 if (isPermissionsLoaded && !canReadPhysicalBackups) {
89 return <NoPermission resourceText="view PITR backups" />
90 }
91
92 if (isOrioleDbInAws) {
93 return (
94 <Admonition
95 type="default"
96 title="Database backups are not available for OrioleDB"
97 description="OrioleDB is currently in public alpha and projects created are strictly ephemeral with no database backups"
98 >
99 <DocsButton abbrev={false} className="mt-2" href={DOCS_URL} />
100 </Admonition>
101 )
102 }
103
104 return (
105 <>
106 {isLoading && <GenericSkeletonLoader />}
107 {isError && <AlertError error={error} subject="Failed to retrieve PITR backups" />}
108 {isSuccess && (
109 <>
110 {!isEnabled ? (
111 <UpgradeToPro
112 addon={hasAccessToPitr ? 'pitr' : undefined}
113 source="pitr"
114 featureProposition="enable Point-in-Time Recovery"
115 primaryText="Point in Time Recovery is a Pro Plan add-on"
116 secondaryText={
117 !hasAccessToPitr
118 ? 'Roll back your database to a specific second. Starts at $100/month. Pro Plan already includes daily backups at no extra cost.'
119 : 'Enable the add-on to add point-in-time recovery to your project.'
120 }
121 />
122 ) : !isActiveHealthy ? (
123 <Alert>
124 <AlertCircle />
125 <AlertTitle>
126 Point in Time Recovery is not available while project is offline
127 </AlertTitle>
128 <AlertDescription>
129 Your project needs to be online to restore your database with Point in Time Recovery
130 </AlertDescription>
131 </Alert>
132 ) : (
133 <>
134 <PITRNotice />
135 <PITRSelection />
136 </>
137 )}
138 </>
139 )}
140 </>
141 )
142}
143
144export default DatabasePhysicalBackups