RealtimeToggleDialog.tsx121 lines · main
1import { useParams } from 'common'
2import { toast } from 'sonner'
3import {
4 Button,
5 Dialog,
6 DialogContent,
7 DialogFooter,
8 DialogHeader,
9 DialogSection,
10 DialogSectionSeparator,
11 DialogTitle,
12} from 'ui'
13
14import { InlineLink } from '@/components/ui/InlineLink'
15import { useDatabasePublicationsQuery } from '@/data/database-publications/database-publications-query'
16import { useDatabasePublicationUpdateMutation } from '@/data/database-publications/database-publications-update-mutation'
17import { Entity } from '@/data/table-editor/table-editor-types'
18import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
19import { useTrack } from '@/lib/telemetry/track'
20
21export const RealtimeToggleDialog = ({
22 table,
23 open,
24 setOpen,
25}: {
26 table: Entity
27 open: boolean
28 setOpen: (value: boolean) => void
29}) => {
30 const track = useTrack()
31 const { ref } = useParams()
32 const { data: project } = useSelectedProjectQuery()
33
34 const { data: publications } = useDatabasePublicationsQuery({
35 projectRef: project?.ref,
36 connectionString: project?.connectionString,
37 })
38 const realtimePublication = (publications ?? []).find(
39 (publication) => publication.name === 'briven_realtime'
40 )
41 const realtimeEnabledTables = realtimePublication?.tables ?? []
42 const isRealtimeEnabled = realtimeEnabledTables.some((t) => t.id === table?.id)
43
44 const { mutate: updatePublications, isPending: isTogglingRealtime } =
45 useDatabasePublicationUpdateMutation({
46 onSuccess: () => {
47 setOpen(false)
48
49 track(isRealtimeEnabled ? 'table_realtime_disabled' : 'table_realtime_enabled', {
50 method: 'ui',
51 schema_name: table.schema,
52 table_name: table.name,
53 })
54 },
55 onError: (error) => {
56 toast.error(`Failed to toggle realtime for ${table.name}: ${error.message}`)
57 },
58 })
59
60 const toggleRealtime = async () => {
61 if (!project || !realtimePublication) return
62
63 const exists = realtimeEnabledTables.some((x) => x.id === table.id)
64 const tables = !exists
65 ? [`${table.schema}.${table.name}`].concat(
66 realtimeEnabledTables.map((t) => `${t.schema}.${t.name}`)
67 )
68 : realtimeEnabledTables.filter((x) => x.id !== table.id).map((x) => `${x.schema}.${x.name}`)
69
70 track('realtime_toggle_table_clicked', {
71 newState: exists ? 'disabled' : 'enabled',
72 origin: 'tableGridHeader',
73 })
74
75 updatePublications({
76 projectRef: project?.ref,
77 connectionString: project?.connectionString,
78 id: realtimePublication.id,
79 tables,
80 })
81 }
82
83 return (
84 <Dialog open={open} onOpenChange={setOpen}>
85 <DialogContent size="small" aria-describedby={undefined}>
86 <DialogHeader>
87 <DialogTitle>
88 {isRealtimeEnabled ? 'Disable' : 'Enable'} realtime for {table.name}
89 </DialogTitle>
90 </DialogHeader>
91 <DialogSectionSeparator />
92 <DialogSection>
93 <div className="space-y-2">
94 <p className="text-sm">
95 Once realtime has been {isRealtimeEnabled ? 'disabled' : 'enabled'}, the table will{' '}
96 {isRealtimeEnabled ? 'no longer ' : ''}broadcast any changes to authorized
97 subscribers.
98 </p>
99 {!isRealtimeEnabled && (
100 <p className="text-sm">
101 You may also select which events to broadcast to subscribers on the{' '}
102 <InlineLink href={`/project/${ref}/database/publications`}>
103 database publications
104 </InlineLink>{' '}
105 settings.
106 </p>
107 )}
108 </div>
109 </DialogSection>
110 <DialogFooter>
111 <Button type="default" disabled={isTogglingRealtime} onClick={() => setOpen(false)}>
112 Cancel
113 </Button>
114 <Button type="primary" loading={isTogglingRealtime} onClick={toggleRealtime}>
115 {isRealtimeEnabled ? 'Disable' : 'Enable'} realtime
116 </Button>
117 </DialogFooter>
118 </DialogContent>
119 </Dialog>
120 )
121}