PublicationsTables.tsx152 lines · main
1import { PermissionAction } from '@supabase/shared-types/out/constants'
2import { useParams } from 'common'
3import { Search } from 'lucide-react'
4import { useMemo, useRef, useState } from 'react'
5import { Card, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from 'ui'
6import { Admonition } from 'ui-patterns'
7import { Input } from 'ui-patterns/DataInputs/Input'
8
9import { PublicationTablesSkeleton } from './PublicationSkeleton'
10import { PublicationsTableItem } from './PublicationsTableItem'
11import { AlertError } from '@/components/ui/AlertError'
12import { NoSearchResults } from '@/components/ui/NoSearchResults'
13import { useDatabasePublicationsQuery } from '@/data/database-publications/database-publications-query'
14import { useTablesQuery } from '@/data/tables/tables-query'
15import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
16import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
17import { onSearchInputEscape } from '@/lib/keyboard'
18import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
19import { useShortcut } from '@/state/shortcuts/useShortcut'
20
21export const PublicationsTables = () => {
22 const { id } = useParams()
23 const { data: project } = useSelectedProjectQuery()
24 const [filterString, setFilterString] = useState<string>('')
25 const searchInputRef = useRef<HTMLInputElement>(null)
26
27 const { can: canUpdatePublications, isLoading: isLoadingPermissions } = useAsyncCheckPermissions(
28 PermissionAction.TENANT_SQL_ADMIN_WRITE,
29 'publications'
30 )
31
32 useShortcut(
33 SHORTCUT_IDS.LIST_PAGE_FOCUS_SEARCH,
34 () => {
35 searchInputRef.current?.focus()
36 searchInputRef.current?.select()
37 },
38 { label: 'Search publications' }
39 )
40
41 const { data: publications = [] } = useDatabasePublicationsQuery({
42 projectRef: project?.ref,
43 connectionString: project?.connectionString,
44 })
45 const selectedPublication = publications.find((pub) => pub.id === Number(id))
46
47 const {
48 data: tablesData = [],
49 isPending: isLoading,
50 isSuccess,
51 isError,
52 error,
53 } = useTablesQuery({
54 projectRef: project?.ref,
55 connectionString: project?.connectionString,
56 })
57
58 const tables = useMemo(() => {
59 return tablesData.filter((table) =>
60 filterString.length === 0 ? table : table.name.includes(filterString)
61 )
62 }, [tablesData, filterString])
63
64 return (
65 <>
66 <div className="flex items-center justify-between mb-4">
67 <Input
68 size="tiny"
69 ref={searchInputRef}
70 icon={<Search />}
71 className="w-48"
72 placeholder="Search for a table"
73 value={filterString}
74 onChange={(e) => setFilterString(e.target.value)}
75 onKeyDown={onSearchInputEscape(filterString, setFilterString)}
76 />
77 </div>
78
79 {!isLoadingPermissions && !canUpdatePublications && (
80 <Admonition
81 type="warning"
82 className="mb-4 w-full"
83 description="You need additional permissions to update database replications."
84 />
85 )}
86
87 <Card>
88 <Table>
89 <TableHeader>
90 <TableRow>
91 <TableHead>Name</TableHead>
92 <TableHead>Schema</TableHead>
93 <TableHead className="hidden lg:table-cell">Description</TableHead>
94 {/*
95 We've disabled All tables toggle for publications.
96 See https://github.com/briven/briven/pull/7233.
97 */}
98 <TableHead />
99 </TableRow>
100 </TableHeader>
101 <TableBody>
102 {(isLoading || isLoadingPermissions) &&
103 Array.from({ length: 2 }).map((_, i) => (
104 <PublicationTablesSkeleton key={i} index={i} />
105 ))}
106
107 {isError && (
108 <TableRow>
109 <TableCell colSpan={4}>
110 <AlertError error={error} subject="Failed to retrieve tables" />
111 </TableCell>
112 </TableRow>
113 )}
114
115 {!isLoading && !isLoadingPermissions && tables.length === 0 && (
116 <TableRow>
117 <TableCell colSpan={4}>
118 <NoSearchResults
119 className="border-none !p-0"
120 searchString={filterString}
121 onResetFilter={() => setFilterString('')}
122 />
123 </TableCell>
124 </TableRow>
125 )}
126
127 {isSuccess ? (
128 !!selectedPublication ? (
129 tables.map((table) => (
130 <PublicationsTableItem
131 key={table.id}
132 table={table}
133 selectedPublication={selectedPublication}
134 />
135 ))
136 ) : (
137 <TableRow>
138 <TableCell colSpan={4}>
139 <p>The selected publication with ID {id} cannot be found</p>
140 <p className="text-foreground-light">
141 Head back to the list of publications to select one from there
142 </p>
143 </TableCell>
144 </TableRow>
145 )
146 ) : null}
147 </TableBody>
148 </Table>
149 </Card>
150 </>
151 )
152}