CreateCommands.utils.tsx202 lines · main
1import { useParams } from 'common'
2import { useMemo } from 'react'
3import { useSetPage } from 'ui-patterns/CommandMenu'
4
5import type { Hook } from '@/components/interfaces/Auth/Hooks/hooks.constants'
6import { HOOKS_DEFINITIONS } from '@/components/interfaces/Auth/Hooks/hooks.constants'
7import { extractMethod, isValidHook } from '@/components/interfaces/Auth/Hooks/hooks.utils'
8import {
9 INTEGRATIONS,
10 type IntegrationDefinition,
11} from '@/components/interfaces/Integrations/Landing/Integrations.constants'
12import { useInstalledIntegrations } from '@/components/interfaces/Integrations/Landing/useInstalledIntegrations'
13import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
14import {
15 useIsAnalyticsBucketsEnabled,
16 useIsVectorBucketsEnabled,
17} from '@/data/config/project-storage-config-query'
18import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
19import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
20import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
21import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
22import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
23
24export function getIntegrationRoute(
25 integration: IntegrationDefinition,
26 ref: string,
27 installedIntegrationIds: Set<string>
28): string | null {
29 // For wrappers, route to overview with new=true (always available if wrappers feature is enabled)
30 if (integration.type === 'wrapper') {
31 return `/project/${ref}/integrations/${integration.id}/overview?new=true`
32 }
33
34 // For non-wrapper integrations, check if installed and determine route
35 if (!installedIntegrationIds.has(integration.id)) {
36 return null
37 }
38
39 // Map integration IDs to their create routes
40 switch (integration.id) {
41 case 'vault':
42 return `/project/${ref}/integrations/vault/secrets?new=true`
43 case 'cron':
44 return `/project/${ref}/integrations/cron/jobs?new=true`
45 case 'webhooks':
46 return `/project/${ref}/integrations/webhooks/webhooks?new=true`
47 case 'queues':
48 return `/project/${ref}/integrations/queues/queues?new=true`
49 // Data API and GraphiQL don't have a create route
50 case 'data_api':
51 case 'graphiql':
52 return null
53 default: {
54 // For other integrations, try to find a navigation route that's not 'overview'
55 const createRoute = integration.navigation?.find((nav) => nav.route !== 'overview')
56 if (createRoute) {
57 return `/project/${ref}/integrations/${integration.id}/${createRoute.route}?new=true`
58 }
59 return null
60 }
61 }
62}
63
64export function getIntegrationCommandName(integration: IntegrationDefinition): string {
65 if (integration.type === 'wrapper') {
66 // Extract the wrapper name (e.g., "Stripe Wrapper" -> "Stripe")
67 const wrapperName = integration.name.replace(' Wrapper', '')
68 return `Add ${wrapperName} wrapper`
69 }
70
71 // Map integration IDs to their command names
72 switch (integration.id) {
73 case 'vault':
74 return 'Create Vault Secret'
75 case 'cron':
76 return 'Create Cron Job'
77 case 'webhooks':
78 return 'Create Database Webhook'
79 case 'queues':
80 return 'Create Queue'
81 default:
82 return `Create ${integration.name}`
83 }
84}
85
86export function useCreateCommandsConfig() {
87 let { ref } = useParams()
88 ref ||= '_'
89 const setPage = useSetPage()
90 const { openSidebar } = useSidebarManagerSnapshot()
91 const snap = useAiAssistantStateSnapshot()
92
93 const {
94 projectAuthAll: authEnabled,
95 projectEdgeFunctionAll: edgeFunctionsEnabled,
96 projectStorageAll: storageEnabled,
97 reportsAll: reportsEnabled,
98 integrationsWrappers: integrationsWrappersEnabled,
99 } = useIsFeatureEnabled([
100 'project_auth:all',
101 'project_edge_function:all',
102 'project_storage:all',
103 'reports:all',
104 'integrations:wrappers',
105 ])
106
107 const {
108 data: authConfig,
109 isError: isAuthConfigError,
110 isPending: isAuthConfigLoading,
111 } = useAuthConfigQuery({ projectRef: ref })
112
113 const { getEntitlementSetValues: getEntitledHookSet } = useCheckEntitlements('auth.hooks')
114 const entitledHookSet = getEntitledHookSet()
115
116 const { nonAvailableHooks } = useMemo(() => {
117 const allHooks: Hook[] = HOOKS_DEFINITIONS.map((definition) => ({
118 ...definition,
119 enabled: authConfig?.[definition.enabledKey] || false,
120 method: extractMethod(
121 authConfig?.[definition.uriKey] || '',
122 authConfig?.[definition.secretsKey] || ''
123 ),
124 }))
125
126 const nonAvailableHooks: string[] = allHooks
127 .filter((h) => !isValidHook(h) && !entitledHookSet.includes(h.entitlementKey))
128 .map((h) => h.entitlementKey)
129
130 return { nonAvailableHooks }
131 }, [entitledHookSet, authConfig])
132
133 const showAuthConfig = !isAuthConfigError && !isAuthConfigLoading
134
135 const sendSmsHook = HOOKS_DEFINITIONS.find((hook) => hook.id === 'send-sms')
136 const sendEmailHook = HOOKS_DEFINITIONS.find((hook) => hook.id === 'send-email')
137 const customAccessTokenHook = HOOKS_DEFINITIONS.find(
138 (hook) => hook.id === 'custom-access-token-claims'
139 )
140 const mfaVerificationHook = HOOKS_DEFINITIONS.find(
141 (hook) => hook.id === 'mfa-verification-attempt'
142 )
143 const mfaVerificationHookEnabled =
144 showAuthConfig &&
145 mfaVerificationHook &&
146 nonAvailableHooks.includes(mfaVerificationHook.entitlementKey)
147 const passwordVerificationHook = HOOKS_DEFINITIONS.find(
148 (hook) => hook.id === 'password-verification-attempt'
149 )
150 const passwordVerificationHookEnabled =
151 showAuthConfig &&
152 passwordVerificationHook &&
153 nonAvailableHooks.includes(passwordVerificationHook.entitlementKey)
154 const beforeUserCreatedHook = HOOKS_DEFINITIONS.find((hook) => hook.id === 'before-user-created')
155
156 // Storage
157 const { data: organization } = useSelectedOrganizationQuery()
158 const isFreePlan = organization?.plan.id === 'free'
159 const isVectorBucketsEnabled = useIsVectorBucketsEnabled({ projectRef: ref })
160 const isAnalyticsBucketsEnabled = useIsAnalyticsBucketsEnabled({ projectRef: ref })
161
162 // Integrations
163 const { installedIntegrations } = useInstalledIntegrations()
164
165 const installedIntegrationIds = useMemo(
166 () => new Set(installedIntegrations.map((integration) => integration.id)),
167 [installedIntegrations]
168 )
169
170 const allIntegrations = useMemo(
171 () =>
172 integrationsWrappersEnabled
173 ? INTEGRATIONS
174 : INTEGRATIONS.filter((x) => !x.id.endsWith('_wrapper')),
175 [integrationsWrappersEnabled]
176 )
177
178 return {
179 ref,
180 setPage,
181 openSidebar,
182 snap,
183 authEnabled,
184 edgeFunctionsEnabled,
185 storageEnabled,
186 sendSmsHook,
187 sendEmailHook,
188 customAccessTokenHook,
189 mfaVerificationHook,
190 mfaVerificationHookEnabled,
191 passwordVerificationHook,
192 passwordVerificationHookEnabled,
193 beforeUserCreatedHook,
194 isFreePlan,
195 isVectorBucketsEnabled,
196 isAnalyticsBucketsEnabled,
197 installedIntegrationIds,
198 integrationsWrappers: integrationsWrappersEnabled,
199 allIntegrations,
200 reportsEnabled,
201 }
202}