CreateCommands.utils.tsx 6.8 KB

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