CreateCommands.utils.tsx202 lines · main
| 1 | import { useParams } from 'common' |
| 2 | import { useMemo } from 'react' |
| 3 | import { useSetPage } from 'ui-patterns/CommandMenu' |
| 4 | |
| 5 | import type { Hook } from '@/components/interfaces/Auth/Hooks/hooks.constants' |
| 6 | import { HOOKS_DEFINITIONS } from '@/components/interfaces/Auth/Hooks/hooks.constants' |
| 7 | import { extractMethod, isValidHook } from '@/components/interfaces/Auth/Hooks/hooks.utils' |
| 8 | import { |
| 9 | INTEGRATIONS, |
| 10 | type IntegrationDefinition, |
| 11 | } from '@/components/interfaces/Integrations/Landing/Integrations.constants' |
| 12 | import { useInstalledIntegrations } from '@/components/interfaces/Integrations/Landing/useInstalledIntegrations' |
| 13 | import { useAuthConfigQuery } from '@/data/auth/auth-config-query' |
| 14 | import { |
| 15 | useIsAnalyticsBucketsEnabled, |
| 16 | useIsVectorBucketsEnabled, |
| 17 | } from '@/data/config/project-storage-config-query' |
| 18 | import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' |
| 19 | import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' |
| 20 | import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' |
| 21 | import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state' |
| 22 | import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state' |
| 23 | |
| 24 | export 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 | |
| 64 | export 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 | |
| 86 | export 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 | } |