import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import { AlertCircle, Info, Search } from 'lucide-react' import Link from 'next/link' import { useRef, useState } from 'react' import { toast } from 'sonner' import { Button, Card, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tooltip, TooltipContent, TooltipTrigger, } from 'ui' import { Input } from 'ui-patterns/DataInputs/Input' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { PublicationSkeleton } from './PublicationSkeleton' import AlertError from '@/components/ui/AlertError' import InformationBox from '@/components/ui/InformationBox' import { NoSearchResults } from '@/components/ui/NoSearchResults' import { useDatabasePublicationsQuery } from '@/data/database-publications/database-publications-query' import { useDatabasePublicationUpdateMutation } from '@/data/database-publications/database-publications-update-mutation' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { onSearchInputEscape } from '@/lib/keyboard' import { SHORTCUT_IDS } from '@/state/shortcuts/registry' import { useShortcut } from '@/state/shortcuts/useShortcut' interface PublicationEvent { event: string key: string } export const PublicationsList = () => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const [filterString, setFilterString] = useState('') const searchInputRef = useRef(null) useShortcut( SHORTCUT_IDS.LIST_PAGE_FOCUS_SEARCH, () => { searchInputRef.current?.focus() searchInputRef.current?.select() }, { label: 'Search publications' } ) useShortcut(SHORTCUT_IDS.LIST_PAGE_RESET_FILTERS, () => { setFilterString('') }) const { data = [], error, isPending: isLoading, isSuccess, isError, } = useDatabasePublicationsQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: updatePublications } = useDatabasePublicationUpdateMutation({ onSuccess: () => { toast.success('Successfully updated event') setToggleListenEventValue(null) }, }) const { can: canUpdatePublications, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions( PermissionAction.TENANT_SQL_ADMIN_WRITE, 'publications' ) const publicationEvents: PublicationEvent[] = [ { event: 'Insert', key: 'publish_insert' }, { event: 'Update', key: 'publish_update' }, { event: 'Delete', key: 'publish_delete' }, { event: 'Truncate', key: 'publish_truncate' }, ] const publications = ( filterString.length === 0 ? data : data.filter((publication) => publication.name.includes(filterString)) ).sort((a, b) => a.id - b.id) const [toggleListenEventValue, setToggleListenEventValue] = useState<{ publication: any event: PublicationEvent currentStatus: any } | null>(null) const toggleListenEvent = async () => { if (!toggleListenEventValue || !project) return const { publication, event, currentStatus } = toggleListenEventValue const payload = { projectRef: project.ref, connectionString: project.connectionString, id: publication.id, } as any payload[`publish_${event.event.toLowerCase()}`] = !currentStatus updatePublications(payload) } return ( <>
} className="w-48" placeholder="Search for a publication" value={filterString} onChange={(e) => setFilterString(e.target.value)} onKeyDown={onSearchInputEscape(filterString, setFilterString)} />
{isPermissionsLoaded && !canUpdatePublications && (
} title="You need additional permissions to update database publications" />
)}
Name System ID Insert Update Delete Truncate {isLoading && Array.from({ length: 2 }).map((_, i) => )} {isError && ( )} {!isLoading && publications.length === 0 && ( setFilterString('')} className="border-none !p-0" /> )} {isSuccess && publications.map((x) => (
{x.name} {/* [Joshen] Making this tooltip very specific for these 2 publications */} {['briven_realtime', 'briven_realtime_messages_publication'].includes( x.name ) && ( {x.name === 'briven_realtime' ? 'Managed by Briven and handles Postgres changes' : x.name === 'briven_realtime_messages_publication' ? 'Managed by Briven and handles broadcasts from the database' : undefined} )}
{x.id} {publicationEvents.map((event) => ( { setToggleListenEventValue({ publication: x, event, currentStatus: (x as any)[event.key], }) }} /> ))}
))}
setToggleListenEventValue(null)} onConfirm={() => { toggleListenEvent() }} >

Are you sure you want to {toggleListenEventValue?.currentStatus ? 'stop' : 'start'}{' '} sending {toggleListenEventValue?.event.event.toLowerCase()} events for{' '} {toggleListenEventValue?.publication.name}?

) }