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