EnableReplicationCallout.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { useParams } from 'common'
  2. import { useState } from 'react'
  3. import { toast } from 'sonner'
  4. import {
  5. Button,
  6. cn,
  7. Dialog,
  8. DialogContent,
  9. DialogFooter,
  10. DialogHeader,
  11. DialogSection,
  12. DialogSectionSeparator,
  13. DialogTitle,
  14. DialogTrigger,
  15. } from 'ui'
  16. import { Admonition } from 'ui-patterns'
  17. import { DestinationType } from './DestinationPanel/DestinationPanel.types'
  18. import { DocsButton } from '@/components/ui/DocsButton'
  19. import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton'
  20. import { useCreateTenantSourceMutation } from '@/data/replication/create-tenant-source-mutation'
  21. import { DOCS_URL } from '@/lib/constants'
  22. const EnableReplicationModal = () => {
  23. const { ref: projectRef } = useParams()
  24. const [open, setOpen] = useState(false)
  25. const { mutate: createTenantSource, isPending: creatingTenantSource } =
  26. useCreateTenantSourceMutation({
  27. onSuccess: () => {
  28. toast.success('External replication has been successfully enabled!')
  29. setOpen(false)
  30. },
  31. onError: (error) => {
  32. toast.error(`Failed to enable external replication: ${error.message}`)
  33. },
  34. })
  35. const onEnableReplication = async () => {
  36. if (!projectRef) return console.error('Project ref is required')
  37. createTenantSource({ projectRef })
  38. }
  39. return (
  40. <Dialog open={open} onOpenChange={setOpen}>
  41. <DialogTrigger asChild>
  42. <Button type="primary" className="w-min">
  43. Enable external replication
  44. </Button>
  45. </DialogTrigger>
  46. <DialogContent>
  47. <DialogHeader>
  48. <DialogTitle>Enable external replication</DialogTitle>
  49. </DialogHeader>
  50. <DialogSectionSeparator />
  51. <DialogSection className="flex flex-col gap-y-2 p-0!">
  52. <Admonition
  53. type="warning"
  54. className="rounded-none border-0"
  55. title="Replication is currently in Alpha"
  56. >
  57. <p className="text-sm leading-normal!">
  58. This feature is in active development and may change as we gather feedback.
  59. Availability and behavior can evolve while in Alpha.
  60. </p>
  61. <p className="text-sm leading-normal!">
  62. Pricing has not been finalized yet. You can enable replication now; we'll announce
  63. pricing later and notify you before any charges apply.
  64. </p>
  65. </Admonition>
  66. </DialogSection>
  67. <DialogFooter>
  68. <Button type="default" disabled={creatingTenantSource} onClick={() => setOpen(false)}>
  69. Cancel
  70. </Button>
  71. <Button type="primary" loading={creatingTenantSource} onClick={onEnableReplication}>
  72. Enable external replication
  73. </Button>
  74. </DialogFooter>
  75. </DialogContent>
  76. </Dialog>
  77. )
  78. }
  79. export const EnableReplicationCallout = ({
  80. type,
  81. className,
  82. hasAccess,
  83. }: {
  84. type?: DestinationType | null
  85. className?: string
  86. hasAccess: boolean
  87. }) => {
  88. return (
  89. <div className={cn('border rounded-md p-4 md:p-12 flex flex-col gap-y-4', className)}>
  90. <div className="flex flex-col gap-y-1">
  91. <h4>Replicate data to external destinations in real time</h4>
  92. <p className="text-sm text-foreground-light">
  93. {hasAccess ? 'Enable external replication' : 'Upgrade to the Pro plan'} to start
  94. replicating your database changes to {type ?? 'data warehouses and analytics platforms'}
  95. </p>
  96. </div>
  97. <div className="flex gap-x-2">
  98. {hasAccess ? (
  99. <EnableReplicationModal />
  100. ) : (
  101. <UpgradePlanButton source="replication" featureProposition="use replication" />
  102. )}
  103. <DocsButton href={`${DOCS_URL}/guides/database/replication#replication`} />
  104. </div>
  105. </div>
  106. )
  107. }