WrapperTable.tsx132 lines · main
1import { useParams } from 'common'
2import { parseAsString, useQueryState } from 'nuqs'
3import { useEffect, useMemo, useState } from 'react'
4import { toast } from 'sonner'
5import {
6 Card,
7 cn,
8 Sheet,
9 SheetContent,
10 Table,
11 TableBody,
12 TableCell,
13 TableFooter,
14 TableHead,
15 TableHeader,
16 TableRow,
17} from 'ui'
18
19import { INTEGRATIONS } from '../Landing/Integrations.constants'
20import { DeleteWrapperModal } from './DeleteWrapperModal'
21import { EditWrapperSheet } from './EditWrapperSheet'
22import { WrapperRow } from './WrapperRow'
23import { wrapperMetaComparator } from './Wrappers.utils'
24import { useFDWsQuery } from '@/data/fdw/fdws-query'
25import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
26
27interface WrapperTableProps {
28 isLatest?: boolean
29}
30
31export const WrapperTable = ({ isLatest = false }: WrapperTableProps) => {
32 const { id, ref } = useParams()
33 const { data: project } = useSelectedProjectQuery()
34 const integration = INTEGRATIONS.find((i) => i.id === id)
35
36 const [isClosingEditWrapper, setIsClosingEditWrapper] = useState(false)
37
38 const { data, isError } = useFDWsQuery({
39 projectRef: ref,
40 connectionString: project?.connectionString,
41 })
42
43 const wrappers = useMemo(
44 () =>
45 integration && integration.type === 'wrapper' && data
46 ? data.filter((wrapper) => wrapperMetaComparator(integration.meta, wrapper))
47 : [],
48 [data, integration]
49 )
50
51 const [selectedWrapperIdToEdit, setSelectedWrapperToEdit] = useQueryState('edit', parseAsString)
52 const selectedWrapperToEdit = wrappers.find((w) => w.id.toString() === selectedWrapperIdToEdit)
53
54 useEffect(() => {
55 if (isError && !!selectedWrapperIdToEdit && !selectedWrapperToEdit) {
56 toast('Wrapper not found')
57 setSelectedWrapperToEdit(null)
58 }
59 }, [isError, selectedWrapperIdToEdit, selectedWrapperToEdit, setSelectedWrapperToEdit])
60
61 if (!integration || integration.type !== 'wrapper') {
62 return (
63 <p className="text-foreground-light text-sm">
64 The referenced ID doesn't correspond to a wrapper integration
65 </p>
66 )
67 }
68
69 return (
70 <>
71 <Card className="max-w-5xl">
72 <Table>
73 <TableHeader>
74 <TableRow>
75 <TableHead className="w-[220px]">Name</TableHead>
76 <TableHead>Tables</TableHead>
77 <TableHead>Encrypted key</TableHead>
78 <TableHead className="w-24">
79 <span className="sr-only">Actions</span>
80 </TableHead>
81 </TableRow>
82 </TableHeader>
83 <TableBody>
84 {(isLatest ? wrappers.slice(0, 3) : wrappers).map((x) => {
85 return <WrapperRow key={x.id} wrapper={x} />
86 })}
87 </TableBody>
88 <TableFooter
89 className={cn(
90 'text-xs font-normal text-center text-foreground-muted',
91 // Prevent the footer from being highlighted on hover
92 '[&>tr>td]:hover:bg-inherit',
93 // Conditionally remove the border-top if there are no wrappers
94 wrappers.length === 0 ? 'border-t-0' : ''
95 )}
96 >
97 <TableRow className="border-b-0">
98 <TableCell colSpan={4}>
99 {wrappers.length} {integration?.name}
100 {wrappers.length === 0 || wrappers.length > 1 ? 's' : ''} created
101 </TableCell>
102 </TableRow>
103 </TableFooter>
104 </Table>
105 </Card>
106
107 <Sheet
108 open={!!selectedWrapperToEdit}
109 onOpenChange={(open) => {
110 if (!open) setIsClosingEditWrapper(true)
111 }}
112 >
113 <SheetContent size="lg" tabIndex={undefined}>
114 {selectedWrapperToEdit && (
115 <EditWrapperSheet
116 wrapper={selectedWrapperToEdit}
117 wrapperMeta={integration.meta}
118 onClose={() => {
119 setSelectedWrapperToEdit(null)
120 setIsClosingEditWrapper(false)
121 }}
122 isClosing={isClosingEditWrapper}
123 setIsClosing={setIsClosingEditWrapper}
124 />
125 )}
126 </SheetContent>
127 </Sheet>
128
129 <DeleteWrapperModal />
130 </>
131 )
132}