PITRStatus.tsx 3.6 KB

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