HookList.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import { useParams } from 'common'
  3. import { includes } from 'lodash'
  4. import { Edit3, MoreVertical, Trash } from 'lucide-react'
  5. import Image from 'next/legacy/image'
  6. import { parseAsString, useQueryState } from 'nuqs'
  7. import {
  8. Badge,
  9. Button,
  10. DropdownMenu,
  11. DropdownMenuContent,
  12. DropdownMenuItem,
  13. DropdownMenuSeparator,
  14. DropdownMenuTrigger,
  15. } from 'ui'
  16. import Table from '@/components/to-be-cleaned/Table'
  17. import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
  18. import { useDatabaseHooksQuery } from '@/data/database-triggers/database-triggers-query'
  19. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  20. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  21. import { BASE_PATH } from '@/lib/constants'
  22. export interface HookListProps {
  23. schema: string
  24. filterString: string
  25. }
  26. export const HookList = ({ schema, filterString }: HookListProps) => {
  27. const { ref } = useParams()
  28. const { data: project } = useSelectedProjectQuery()
  29. const { data: hooks } = useDatabaseHooksQuery({
  30. projectRef: project?.ref,
  31. connectionString: project?.connectionString,
  32. })
  33. const [, setSelectedHookIdToEdit] = useQueryState('edit', parseAsString.withDefault(''))
  34. const [, setSelectedHookIdToDelete] = useQueryState('delete', parseAsString.withDefault(''))
  35. const restUrl = project?.restUrl
  36. const restUrlTld = restUrl ? new URL(restUrl).hostname.split('.').pop() : 'co'
  37. const filteredHooks = (hooks ?? []).filter(
  38. (x) =>
  39. includes(x.name.toLowerCase(), filterString.toLowerCase()) &&
  40. x.schema === schema &&
  41. x.function_args.length >= 2
  42. )
  43. const { can: canUpdateWebhook } = useAsyncCheckPermissions(
  44. PermissionAction.TENANT_SQL_ADMIN_WRITE,
  45. 'triggers'
  46. )
  47. return (
  48. <>
  49. {filteredHooks.map((x) => {
  50. const isEdgeFunction = (url: string) =>
  51. url.includes(`https://${ref}.functions.briven.${restUrlTld}/`) ||
  52. url.includes(`https://${ref}.briven.${restUrlTld}/functions/`)
  53. const [url, method] = x.function_args
  54. return (
  55. <Table.tr key={x.id}>
  56. <Table.td>
  57. <div className="flex items-center space-x-4">
  58. <div>
  59. <Image
  60. src={
  61. isEdgeFunction(url)
  62. ? `${BASE_PATH}/img/function-providers/briven-severless-function.png`
  63. : `${BASE_PATH}/img/function-providers/http-request.png`
  64. }
  65. alt="hook-type"
  66. layout="fixed"
  67. width="20"
  68. height="20"
  69. title={isEdgeFunction(url) ? 'Briven Edge Function' : 'HTTP Request'}
  70. />
  71. </div>
  72. <p title={x.name} className="truncate">
  73. {x.name}
  74. </p>
  75. </div>
  76. </Table.td>
  77. <Table.td className="hidden space-x-2 lg:table-cell">
  78. <p title={x.table}>{x.table}</p>
  79. </Table.td>
  80. <Table.td className="hidden space-x-1 xl:table-cell">
  81. {x.events.map((event: string) => (
  82. <Badge key={event}>{event}</Badge>
  83. ))}
  84. </Table.td>
  85. <Table.td className="hidden xl:table-cell">
  86. <p className="truncate" title={url}>
  87. <code className="text-code-inline">{method}</code>: {url}
  88. </p>
  89. </Table.td>
  90. <Table.td className="text-right">
  91. <div className="flex justify-end gap-4">
  92. {canUpdateWebhook ? (
  93. <DropdownMenu>
  94. <DropdownMenuTrigger asChild>
  95. <Button type="default" className="px-1" icon={<MoreVertical />} />
  96. </DropdownMenuTrigger>
  97. <DropdownMenuContent side="left">
  98. <>
  99. <DropdownMenuItem
  100. className="space-x-2"
  101. onClick={() => setSelectedHookIdToEdit(x.id.toString())}
  102. >
  103. <Edit3 size="14" />
  104. <p>Edit hook</p>
  105. </DropdownMenuItem>
  106. <DropdownMenuSeparator />
  107. <DropdownMenuItem
  108. className="space-x-2"
  109. onClick={() => setSelectedHookIdToDelete(x.id.toString())}
  110. >
  111. <Trash stroke="red" size="14" />
  112. <p>Delete hook</p>
  113. </DropdownMenuItem>
  114. </>
  115. </DropdownMenuContent>
  116. </DropdownMenu>
  117. ) : (
  118. <ButtonTooltip
  119. disabled
  120. type="default"
  121. className="px-1"
  122. icon={<MoreVertical />}
  123. tooltip={{
  124. content: {
  125. side: 'bottom',
  126. text: 'You need additional permissions to update webhooks',
  127. },
  128. }}
  129. />
  130. )}
  131. </div>
  132. </Table.td>
  133. </Table.tr>
  134. )
  135. })}
  136. </>
  137. )
  138. }