useInstalledIntegrations.tsx162 lines · main
1import { useMemo } from 'react'
2
3import {
4 hasMatchingWrapper,
5 hasRequiredExtensions,
6 isOAuthInstalled,
7 isStripeSyncEngineInstalled,
8} from './Landing.utils'
9import { useAvailableIntegrations } from './useAvailableIntegrations'
10import { useAPIKeysQuery } from '@/data/api-keys/api-keys-query'
11import { useDatabaseExtensionsQuery } from '@/data/database-extensions/database-extensions-query'
12import { useSchemasQuery } from '@/data/database/schemas-query'
13import { useFDWsQuery } from '@/data/fdw/fdws-query'
14import { useSecretsQuery } from '@/data/secrets/secrets-query'
15import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
16import { EMPTY_ARR } from '@/lib/void'
17
18export const useInstalledIntegrations = () => {
19 const { data: project } = useSelectedProjectQuery()
20
21 const {
22 data: allIntegrations = EMPTY_ARR,
23 error: availableIntegrationsError,
24 isPending: isAvailableIntegrationsLoading,
25 isSuccess: isSuccessAvailableIntegrations,
26 isError: isErrorAvailableIntegrations,
27 } = useAvailableIntegrations()
28
29 const hasSecretKeyPrefixIntegration = useMemo(() => {
30 return allIntegrations.some(
31 (integration) =>
32 integration.type === 'oauth' &&
33 integration.installIdentificationMethod === 'secret_key_prefix' &&
34 !!integration.secretKeyPrefix
35 )
36 }, [allIntegrations])
37
38 const hasEdgeFunctionSecretNameIntegration = useMemo(() => {
39 return allIntegrations.some(
40 (integration) =>
41 integration.type === 'oauth' &&
42 integration.installIdentificationMethod === 'edge_function_secret_name' &&
43 !!integration.edgeFunctionSecretName
44 )
45 }, [allIntegrations])
46
47 const {
48 data: apiKeys = EMPTY_ARR,
49 error: apiKeysError,
50 isError: isErrorApiKeys,
51 isLoading: isApiKeysLoading,
52 isSuccess: isSuccessApiKeys,
53 } = useAPIKeysQuery(
54 { projectRef: project?.ref, reveal: false },
55 { enabled: hasSecretKeyPrefixIntegration }
56 )
57
58 const {
59 data: edgeFunctionSecrets = EMPTY_ARR,
60 error: edgeFunctionSecretsError,
61 isError: isErrorEdgeFunctionSecrets,
62 isLoading: isEdgeFunctionSecretsLoading,
63 isSuccess: isSuccessEdgeFunctionSecrets,
64 } = useSecretsQuery(
65 { projectRef: project?.ref },
66 { enabled: hasEdgeFunctionSecretNameIntegration }
67 )
68
69 const {
70 data: wrappers = EMPTY_ARR,
71 error: fdwError,
72 isError: isErrorFDWs,
73 isPending: isFDWLoading,
74 isSuccess: isSuccessFDWs,
75 } = useFDWsQuery({
76 projectRef: project?.ref,
77 connectionString: project?.connectionString,
78 })
79 const {
80 data: extensions = EMPTY_ARR,
81 error: extensionsError,
82 isError: isErrorExtensions,
83 isPending: isExtensionsLoading,
84 isSuccess: isSuccessExtensions,
85 } = useDatabaseExtensionsQuery({
86 projectRef: project?.ref,
87 connectionString: project?.connectionString,
88 })
89
90 const {
91 data: schemas = EMPTY_ARR,
92 error: schemasError,
93 isError: isErrorSchemas,
94 isPending: isSchemasLoading,
95 isSuccess: isSuccessSchemas,
96 } = useSchemasQuery({
97 projectRef: project?.ref,
98 connectionString: project?.connectionString,
99 })
100
101 const isHooksEnabled = schemas?.some((schema) => schema.name === 'briven_functions')
102
103 const installedIntegrations = useMemo(() => {
104 return allIntegrations
105 .filter((integration) => {
106 if (integration.id === 'webhooks') return isHooksEnabled
107 if (integration.id === 'data_api') return true
108 if (integration.id === 'stripe_sync_engine') {
109 return isStripeSyncEngineInstalled(schemas)
110 }
111 if (integration.type === 'wrapper') {
112 return hasMatchingWrapper({ meta: integration.meta, wrappers })
113 }
114 if (integration.type === 'postgres_extension') {
115 return hasRequiredExtensions({ integration, extensions })
116 }
117 if (integration.type === 'oauth') {
118 return isOAuthInstalled({ integration, apiKeys, secrets: edgeFunctionSecrets })
119 }
120 return false
121 })
122 .sort((a, b) => a.name.localeCompare(b.name))
123 }, [allIntegrations, wrappers, extensions, schemas, isHooksEnabled, apiKeys, edgeFunctionSecrets])
124
125 const error =
126 fdwError ||
127 extensionsError ||
128 schemasError ||
129 availableIntegrationsError ||
130 (hasSecretKeyPrefixIntegration ? apiKeysError : null) ||
131 (hasEdgeFunctionSecretNameIntegration ? edgeFunctionSecretsError : null)
132 const isLoading =
133 isSchemasLoading ||
134 isFDWLoading ||
135 isExtensionsLoading ||
136 isAvailableIntegrationsLoading ||
137 (hasSecretKeyPrefixIntegration && isApiKeysLoading) ||
138 (hasEdgeFunctionSecretNameIntegration && isEdgeFunctionSecretsLoading)
139 const isError =
140 isErrorFDWs ||
141 isErrorExtensions ||
142 isErrorSchemas ||
143 isErrorAvailableIntegrations ||
144 (hasSecretKeyPrefixIntegration && isErrorApiKeys) ||
145 (hasEdgeFunctionSecretNameIntegration && isErrorEdgeFunctionSecrets)
146 const isSuccess =
147 isSuccessFDWs &&
148 isSuccessExtensions &&
149 isSuccessSchemas &&
150 isSuccessAvailableIntegrations &&
151 (!hasSecretKeyPrefixIntegration || isSuccessApiKeys) &&
152 (!hasEdgeFunctionSecretNameIntegration || isSuccessEdgeFunctionSecrets)
153
154 return {
155 // show all integrations at once instead of showing partial results
156 installedIntegrations: isLoading ? EMPTY_ARR : installedIntegrations,
157 error,
158 isError,
159 isLoading,
160 isSuccess,
161 }
162}