index.tsx105 lines · main
1import { useParams } from 'common'
2import { useRouter } from 'next/router'
3import { useEffect, useMemo } from 'react'
4import { Admonition } from 'ui-patterns'
5import { PageContainer } from 'ui-patterns/PageContainer'
6import {
7 PageHeader,
8 PageHeaderDescription,
9 PageHeaderMeta,
10 PageHeaderSummary,
11 PageHeaderTitle,
12} from 'ui-patterns/PageHeader'
13import { PageSection, PageSectionContent } from 'ui-patterns/PageSection'
14import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
15
16import { useAvailableIntegrations } from '@/components/interfaces/Integrations/Landing/useAvailableIntegrations'
17import { useInstalledIntegrations } from '@/components/interfaces/Integrations/Landing/useInstalledIntegrations'
18import { DefaultLayout } from '@/components/layouts/DefaultLayout'
19import { ProjectIntegrationsLayoutDispatch } from '@/components/layouts/ProjectIntegrationsLayoutDispatch'
20import type { NextPageWithLayout } from '@/types'
21
22const IntegrationPage: NextPageWithLayout = () => {
23 const router = useRouter()
24 const { ref, id, pageId, childId } = useParams()
25
26 const { data: allIntegrations } = useAvailableIntegrations()
27 const { installedIntegrations: installedIntegrations, isLoading: isIntegrationsLoading } =
28 useInstalledIntegrations()
29
30 // everything is wrapped in useMemo to avoid UI resets when installing additional extensions like pg_net
31 const integration = useMemo(() => allIntegrations.find((i) => i.id === id), [allIntegrations, id])
32
33 const installation = useMemo(
34 () => installedIntegrations.find((inst) => inst.id === id),
35 [installedIntegrations, id]
36 )
37
38 // Get the corresponding component dynamically
39 const Component = useMemo(
40 () => integration?.navigate({ id, pageId, childId }),
41 [integration, id, pageId, childId]
42 )
43
44 useEffect(() => {
45 // if the integration is not installed, redirect to the overview page
46 if (
47 router &&
48 router?.isReady &&
49 !isIntegrationsLoading &&
50 !installation &&
51 pageId !== 'overview'
52 ) {
53 router.replace(`/project/${ref}/integrations/${id}/overview`)
54 }
55 }, [installation, isIntegrationsLoading, pageId, router, ref, id])
56
57 // Determine content based on state
58 const content = useMemo(() => {
59 if (!router?.isReady || isIntegrationsLoading) {
60 return (
61 <PageContainer size="full">
62 <PageSection>
63 <PageSectionContent>
64 <GenericSkeletonLoader />
65 </PageSectionContent>
66 </PageSection>
67 </PageContainer>
68 )
69 } else if (!Component || !id || !integration) {
70 return (
71 <PageContainer size="full">
72 <PageHeader size="full">
73 <PageHeaderMeta>
74 <PageHeaderSummary>
75 <PageHeaderTitle>Integration not found</PageHeaderTitle>
76 <PageHeaderDescription>
77 If you think this is an error, please contact support.
78 </PageHeaderDescription>
79 </PageHeaderSummary>
80 </PageHeaderMeta>
81 </PageHeader>
82 <PageSection>
83 <PageSectionContent>
84 <Admonition type="warning" title="This integration is not currently available">
85 Please try again later or contact support if the problem persists.
86 </Admonition>
87 </PageSectionContent>
88 </PageSection>
89 </PageContainer>
90 )
91 } else {
92 return <Component />
93 }
94 }, [router?.isReady, isIntegrationsLoading, id, integration, Component])
95
96 return content
97}
98
99IntegrationPage.getLayout = (page) => (
100 <DefaultLayout>
101 <ProjectIntegrationsLayoutDispatch>{page}</ProjectIntegrationsLayoutDispatch>
102 </DefaultLayout>
103)
104
105export default IntegrationPage