PITRStatus.tsx103 lines · main
1import { PermissionAction } from '@supabase/shared-types/out/constants'
2import { useParams } from 'common'
3import dayjs from 'dayjs'
4import { AlertCircle } from 'lucide-react'
5
6import type { Timezone } from './PITR.types'
7import { TimezoneSelection } from './TimezoneSelection'
8import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
9import { FormPanel } from '@/components/ui/Forms/FormPanel'
10import { useBackupsQuery } from '@/data/database/backups-query'
11import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query'
12import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
13
14interface PITRStatusProps {
15 selectedTimezone: Timezone
16 onUpdateTimezone: (timezone: Timezone) => void
17 onSetConfiguration: () => void
18}
19
20const PITRStatus = ({
21 selectedTimezone,
22 onUpdateTimezone,
23 onSetConfiguration,
24}: PITRStatusProps) => {
25 const { ref } = useParams()
26 const { data: backups } = useBackupsQuery({ projectRef: ref })
27 const { data: databases } = useReadReplicasQuery({ projectRef: ref })
28
29 const hasReadReplicas = (databases ?? []).length > 1
30
31 const { earliestPhysicalBackupDateUnix, latestPhysicalBackupDateUnix } =
32 backups?.physicalBackupData ?? {}
33
34 const earliestAvailableBackup = dayjs
35 .unix(earliestPhysicalBackupDateUnix ?? 0)
36 .tz(selectedTimezone?.utc[0])
37 .format('DD MMM YYYY, HH:mm:ss')
38
39 const latestAvailableBackup = dayjs
40 .unix(latestPhysicalBackupDateUnix ?? 0)
41 .tz(selectedTimezone?.utc[0])
42 .format('DD MMM YYYY, HH:mm:ss')
43
44 const { can: canTriggerPhysicalBackup } = useAsyncCheckPermissions(
45 PermissionAction.INFRA_EXECUTE,
46 'queue_job.walg.prepare_restore'
47 )
48
49 return (
50 <>
51 <FormPanel
52 disabled={true}
53 footer={
54 <div className="flex items-center justify-between p-6">
55 <div className="flex items-center space-x-4">
56 <AlertCircle className="text-foreground-light" size={18} strokeWidth={1.5} />
57 <span className="text-foreground-light text-sm">
58 You'll be able to pick the right date and time when you begin
59 </span>
60 </div>
61 <ButtonTooltip
62 disabled={hasReadReplicas || !canTriggerPhysicalBackup}
63 onClick={() => onSetConfiguration()}
64 tooltip={{
65 content: {
66 side: 'left',
67 text: hasReadReplicas
68 ? 'You will need to remove all read replicas first to trigger a PITR recovery'
69 : !canTriggerPhysicalBackup
70 ? 'You need additional permissions to trigger a PITR recovery'
71 : undefined,
72 },
73 }}
74 >
75 Start a restore
76 </ButtonTooltip>
77 </div>
78 }
79 >
80 <div className="p-6 space-y-6">
81 <div className="w-[350px]">
82 <TimezoneSelection
83 selectedTimezone={selectedTimezone}
84 onSelectTimezone={onUpdateTimezone}
85 />
86 </div>
87 <div className="flex items-center space-x-20">
88 <div className="space-y-2">
89 <p className="text-sm text-foreground-light">Database restore available from</p>
90 <p className="text-2xl">{earliestAvailableBackup}</p>
91 </div>
92 <div className="space-y-2">
93 <p className="text-sm text-foreground-light">Latest restore available at</p>
94 <p className="text-2xl">{latestAvailableBackup}</p>
95 </div>
96 </div>
97 </div>
98 </FormPanel>
99 </>
100 )
101}
102
103export default PITRStatus