WrappersTab.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import { useParams } from 'common'
  3. import { HTMLProps, ReactNode, useCallback, useState } from 'react'
  4. import { Sheet, SheetContent } from 'ui'
  5. import { CreateWrapperSheet } from './CreateWrapperSheet'
  6. import { WRAPPERS } from './Wrappers.constants'
  7. import { wrapperMetaComparator } from './Wrappers.utils'
  8. import { WrapperTable } from './WrapperTable'
  9. import { DiscardChangesConfirmationDialog } from '@/components/ui-patterns/Dialogs/DiscardChangesConfirmationDialog'
  10. import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
  11. import { useFDWsQuery } from '@/data/fdw/fdws-query'
  12. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  13. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  14. import { useConfirmOnClose } from '@/hooks/ui/useConfirmOnClose'
  15. export const WrappersTab = () => {
  16. const { id } = useParams()
  17. const { data: project } = useSelectedProjectQuery()
  18. const [createWrapperShown, setCreateWrapperShown] = useState(false)
  19. const { can: canCreateWrapper } = useAsyncCheckPermissions(
  20. PermissionAction.TENANT_SQL_ADMIN_WRITE,
  21. 'wrappers'
  22. )
  23. const { data } = useFDWsQuery({
  24. projectRef: project?.ref,
  25. connectionString: project?.connectionString,
  26. })
  27. const wrappers = data ?? []
  28. const wrapperMeta = WRAPPERS.find((w) => w.name === id)
  29. // this contains a collection of all wrapper instances for the wrapper type
  30. const createdWrappers = wrapperMeta
  31. ? wrappers.filter((w) => wrapperMetaComparator(wrapperMeta, w))
  32. : []
  33. const [isDirty, setIsDirty] = useState(false)
  34. const { confirmOnClose, handleOpenChange, modalProps } = useConfirmOnClose({
  35. checkIsDirty: useCallback(() => isDirty, [isDirty]),
  36. onClose: useCallback(() => {
  37. setCreateWrapperShown(false)
  38. setIsDirty(false)
  39. }, []),
  40. })
  41. const Container = useCallback(
  42. ({ ...props }: { children: ReactNode } & HTMLProps<HTMLDivElement>) => (
  43. <div className="w-full mx-10 py-10 ">
  44. {props.children}
  45. <Sheet open={!!createWrapperShown} onOpenChange={handleOpenChange}>
  46. <SheetContent size="lg" tabIndex={undefined}>
  47. {wrapperMeta && (
  48. <CreateWrapperSheet
  49. wrapperMeta={wrapperMeta}
  50. onDirty={setIsDirty}
  51. onClose={() => setCreateWrapperShown(false)}
  52. onCloseWithConfirmation={confirmOnClose}
  53. />
  54. )}
  55. </SheetContent>
  56. </Sheet>
  57. </div>
  58. ),
  59. [createWrapperShown, handleOpenChange, wrapperMeta, confirmOnClose]
  60. )
  61. if (!wrapperMeta) {
  62. return <div>Missing integration.</div>
  63. }
  64. if (createdWrappers.length === 0) {
  65. return (
  66. <Container>
  67. <div className=" w-full h-48 max-w-4xl">
  68. <div className="border rounded-lg h-full flex flex-col gap-y-2 items-center justify-center">
  69. <p className="text-sm text-foreground-light">
  70. No {wrapperMeta.label} wrappers have been installed
  71. </p>
  72. <ButtonTooltip
  73. type="default"
  74. onClick={() => setCreateWrapperShown(true)}
  75. disabled={!canCreateWrapper}
  76. tooltip={{
  77. content: {
  78. text: !canCreateWrapper
  79. ? 'You need additional permissions to create a foreign data wrapper'
  80. : undefined,
  81. },
  82. }}
  83. >
  84. Add new wrapper
  85. </ButtonTooltip>
  86. </div>
  87. </div>
  88. </Container>
  89. )
  90. }
  91. return (
  92. <Container>
  93. <WrapperTable />
  94. <DiscardChangesConfirmationDialog {...modalProps} />
  95. </Container>
  96. )
  97. }