import * as Tooltip from '@radix-ui/react-tooltip' import type { PostgresPolicy, PostgresTable } from '@supabase/postgres-meta' import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import { MousePointer2 } from 'lucide-react' import Link from 'next/link' import { useEffect, useRef, useState } from 'react' import { Button, IconAlertCircle, IconCode, IconLock, Modal } from 'ui' import { rlsAcknowledgedKey } from 'components/grid/constants' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import ConfirmationModal from 'components/ui/ConfirmationModal' import { useCheckPermissions, useStore } from 'hooks' export interface GridHeaderActionsProps { table: PostgresTable openAPIDocsPanel: () => void refreshDocs: () => void } const GridHeaderActions = ({ table, openAPIDocsPanel, refreshDocs }: GridHeaderActionsProps) => { const { ref } = useParams() const { meta, ui } = useStore() const { project } = useProjectContext() const [isTogglingRealtime, setIsTogglingRealtime] = useState(false) const [showEnableRealtime, setShowEnableRealtime] = useState(false) const projectRef = project?.ref const publications = meta.publications.list() const policies = meta.policies.list((policy: PostgresPolicy) => policy.table_id === table.id) const realtimePublication = publications.find( (publication) => publication.name === 'supabase_realtime' ) const realtimeEnabledTables = realtimePublication?.tables ?? [] const isRealtimeEnabled = realtimeEnabledTables.some((t: any) => t.id === table?.id) const canSqlWriteTables = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables') const canSqlWriteColumns = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'columns') const isReadOnly = !canSqlWriteTables && !canSqlWriteColumns // This will change when we allow autogenerated API docs for schemas other than `public` const doesHaveAutoGeneratedAPIdocs = table.schema === 'public' const rlsKey = rlsAcknowledgedKey(table.id.toString()) const rlsAcknowledgedChannel = useRef(new BroadcastChannel(rlsKey)) const [showRLSWarning, setShowRLSWarning] = useState( !table.rls_enabled && localStorage.getItem(rlsKey) === 'true' ) useEffect(() => { if (rlsAcknowledgedChannel.current) { rlsAcknowledgedChannel.current.close() } rlsAcknowledgedChannel.current = new BroadcastChannel(rlsKey) rlsAcknowledgedChannel.current.onmessage = (event) => { if (event.data.type === 'dismiss') { setShowRLSWarning(true) } } return () => rlsAcknowledgedChannel.current.close() }, [rlsKey]) function openAPIDocs() { openAPIDocsPanel() refreshDocs() } const RenderAPIPreviewToggle = () => { return ( } onClick={openAPIDocs} > API ) } const toggleRealtime = async () => { if (!realtimePublication) return console.error('Unable to find realtime publication') setIsTogglingRealtime(true) const exists = realtimeEnabledTables.some((x: any) => x.id == table.id) const tables = !exists ? [`${table.schema}.${table.name}`].concat( realtimeEnabledTables.map((t: any) => `${t.schema}.${t.name}`) ) : realtimeEnabledTables .filter((x: any) => x.id != table.id) .map((x: any) => `${x.schema}.${x.name}`) try { const id = realtimePublication.id const payload = { tables, id } const { error } = await meta.publications.update(id, payload) if (error) throw error setShowEnableRealtime(false) } catch (error: any) { ui.setNotification({ category: 'error', message: `Failed to toggle realtime for ${table.name}: ${error.message}`, }) } finally { setIsTogglingRealtime(false) } } return ( <>
Once realtime has been {isRealtimeEnabled ? 'disabled' : 'enabled'}, the table will{' '} {isRealtimeEnabled ? 'no longer ' : ''}broadcast any changes to authorized subscribers.
{!isRealtimeEnabled && (You may also select which events to broadcast to subscribers on the{' '} database replication {' '} settings.
)}