useIntegrationDetail.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { useParams } from 'common'
  2. import { useRouter } from 'next/router'
  3. import { useEffect, useMemo } from 'react'
  4. import { useAvailableIntegrations } from './useAvailableIntegrations'
  5. import { useInstalledIntegrations } from './useInstalledIntegrations'
  6. import { useDatabaseExtensionsQuery } from '@/data/database-extensions/database-extensions-query'
  7. import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
  8. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  9. export type IntegrationTab = {
  10. label: string
  11. href: string
  12. active: boolean
  13. }
  14. export const useIntegrationDetail = () => {
  15. const router = useRouter()
  16. const { ref, id, pageId, childId } = useParams()
  17. const { integrationsWrappers } = useIsFeatureEnabled(['integrations:wrappers'])
  18. const { data: project } = useSelectedProjectQuery()
  19. const { data: extensions } = useDatabaseExtensionsQuery({
  20. projectRef: project?.ref,
  21. connectionString: project?.connectionString,
  22. })
  23. const { data: allIntegrations, isPending: isAvailableLoading } = useAvailableIntegrations()
  24. const { installedIntegrations, isLoading: isInstalledLoading } = useInstalledIntegrations()
  25. // wrapped in useMemo to avoid UI resets when installing additional extensions like pg_net
  26. const integration = useMemo(() => allIntegrations.find((i) => i.id === id), [allIntegrations, id])
  27. const installation = useMemo(
  28. () => installedIntegrations.find((i) => i.id === id),
  29. [installedIntegrations, id]
  30. )
  31. const installableExtensions = (extensions ?? []).filter((ext) =>
  32. (integration?.requiredExtensions ?? []).includes(ext.name)
  33. )
  34. const extensionsInstalled = installableExtensions.every((x) => x.installed_version)
  35. // installedIntegrations doesn't return wrappers unless there's a wrapper created
  36. const isInstalled =
  37. !!integration && (!!installation || (integration.type === 'wrapper' && extensionsInstalled))
  38. const navItems = useMemo(() => {
  39. if (!integration?.navigation) return []
  40. return isInstalled
  41. ? integration.navigation
  42. : integration.navigation.filter((nav) => nav.route === 'overview')
  43. }, [integration, isInstalled])
  44. const activeRoute = pageId ?? 'overview'
  45. const activeNav = useMemo(
  46. () => navItems.find((nav) => nav.route === activeRoute),
  47. [navItems, activeRoute]
  48. )
  49. const isKnownRoute = !!activeNav
  50. const layout = (activeNav?.layout ?? 'full') as 'full' | 'constrained'
  51. const tabs: IntegrationTab[] = useMemo(
  52. () =>
  53. navItems.map((nav) => ({
  54. label: nav.label,
  55. href: `/project/${ref}/integrations/${id}/${nav.route}`,
  56. active: nav.route === activeRoute,
  57. })),
  58. [navItems, ref, id, activeRoute]
  59. )
  60. const Component = useMemo(
  61. () => integration?.navigate({ id, pageId, childId }),
  62. [integration, id, pageId, childId]
  63. )
  64. const isReady = !!router?.isReady
  65. const isWrapperBlocked = !integrationsWrappers && !!id?.endsWith('_wrapper')
  66. const pageTitle = integration?.name ?? 'Integration not found'
  67. const pageSubTitle =
  68. integration?.description ?? 'If you think this is an error, please contact support'
  69. useEffect(() => {
  70. if (
  71. router?.isReady &&
  72. !isAvailableLoading &&
  73. !isInstalledLoading &&
  74. !!integration &&
  75. pageId &&
  76. !isKnownRoute
  77. ) {
  78. router.replace(`/project/${ref}/integrations/${id}/overview`)
  79. }
  80. }, [router, pageId, ref, id, integration, isKnownRoute, isAvailableLoading, isInstalledLoading])
  81. return {
  82. ref,
  83. id,
  84. pageId,
  85. childId,
  86. activeRoute,
  87. activeNav,
  88. isKnownRoute,
  89. layout,
  90. tabs,
  91. isReady,
  92. isWrapperBlocked,
  93. pageTitle,
  94. pageSubTitle,
  95. integrationsWrappers,
  96. integration,
  97. installation,
  98. isInstalled,
  99. isAvailableLoading,
  100. isInstalledLoading,
  101. Component,
  102. }
  103. }