SidePanelVercelProjectLinker.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { useParams } from 'common'
  2. import { keyBy } from 'lodash'
  3. import { useCallback, useMemo } from 'react'
  4. import { toast } from 'sonner'
  5. import { SidePanel } from 'ui'
  6. import { ENV_VAR_RAW_KEYS } from '@/components/interfaces/Integrations/Vercel/Integrations-Vercel.constants'
  7. import ProjectLinker, {
  8. ForeignProject,
  9. } from '@/components/interfaces/Integrations/VercelGithub/ProjectLinker'
  10. import { Markdown } from '@/components/interfaces/Markdown'
  11. import { vercelIcon } from '@/components/to-be-cleaned/ListIcons'
  12. import { useOrgIntegrationsQuery } from '@/data/integrations/integrations-query-org-only'
  13. import { useIntegrationVercelConnectionsCreateMutation } from '@/data/integrations/integrations-vercel-connections-create-mutation'
  14. import { useVercelProjectsQuery } from '@/data/integrations/integrations-vercel-projects-query'
  15. import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
  16. import { BASE_PATH } from '@/lib/constants'
  17. import { EMPTY_ARR } from '@/lib/void'
  18. import { useSidePanelsStateSnapshot } from '@/state/side-panels'
  19. const VERCEL_ICON = (
  20. <svg xmlns="http://www.w3.org/2000/svg" fill="white" viewBox="0 0 512 512" className="w-6">
  21. <path fillRule="evenodd" d="M256,48,496,464H16Z" />
  22. </svg>
  23. )
  24. export const SidePanelVercelProjectLinker = () => {
  25. const { ref } = useParams()
  26. const { data: selectedOrganization } = useSelectedOrganizationQuery()
  27. const sidePanelStateSnapshot = useSidePanelsStateSnapshot()
  28. const organizationIntegrationId = sidePanelStateSnapshot.vercelConnectionsIntegrationId
  29. const { data: integrationData } = useOrgIntegrationsQuery({
  30. orgSlug: selectedOrganization?.slug,
  31. })
  32. const vercelIntegrations = integrationData?.filter(
  33. (integration) => integration.integration.name === 'Vercel'
  34. ) // vercel
  35. /**
  36. * Find the right integration
  37. *
  38. * we use the snapshot.organizationIntegrationId which should be set whenever this sidepanel is opened
  39. */
  40. const selectedIntegration = vercelIntegrations?.find((x) => x.id === organizationIntegrationId)
  41. const { data: vercelProjectsData } = useVercelProjectsQuery(
  42. {
  43. organization_integration_id: organizationIntegrationId,
  44. },
  45. { enabled: organizationIntegrationId !== undefined }
  46. )
  47. const vercelProjects = useMemo(() => vercelProjectsData ?? EMPTY_ARR, [vercelProjectsData])
  48. const vercelProjectsById = useMemo(() => keyBy(vercelProjects, 'id'), [vercelProjects])
  49. const getForeignProjectIcon = useCallback(
  50. (_project: ForeignProject) => {
  51. const project = vercelProjectsById[_project.id]
  52. return !project?.framework ? (
  53. vercelIcon
  54. ) : (
  55. <img
  56. src={`${BASE_PATH}/img/icons/frameworks/${project.framework}.svg`}
  57. width={21}
  58. height={21}
  59. alt={`icon`}
  60. />
  61. )
  62. },
  63. [vercelProjectsById]
  64. )
  65. const { mutate: createConnections, isPending: isCreatingConnection } =
  66. useIntegrationVercelConnectionsCreateMutation({
  67. async onSuccess({ env_sync_error: envSyncError }) {
  68. if (envSyncError) {
  69. toast.error(
  70. `Failed to sync environment variables: ${envSyncError.message}. Please try re-syncing manually from settings.`
  71. )
  72. }
  73. sidePanelStateSnapshot.setVercelConnectionsOpen(false)
  74. },
  75. })
  76. const onCreateConnections = useCallback(
  77. (vars: any) => {
  78. createConnections({
  79. ...vars,
  80. connection: {
  81. ...vars.connection,
  82. metadata: {
  83. ...vars.connection.metadata,
  84. brivenConfig: {
  85. projectEnvVars: {
  86. write: true,
  87. },
  88. },
  89. },
  90. },
  91. })
  92. },
  93. [createConnections]
  94. )
  95. return (
  96. <SidePanel
  97. hideFooter
  98. size="large"
  99. header="Add new Vercel project connection"
  100. visible={sidePanelStateSnapshot.vercelConnectionsOpen}
  101. onCancel={() => sidePanelStateSnapshot.setVercelConnectionsOpen(false)}
  102. >
  103. <div className="py-6 flex flex-col gap-6 bg-studio h-full">
  104. <SidePanel.Content>
  105. <Markdown
  106. content={`
  107. ### Choose repository to connect to
  108. Check the details below before proceeding
  109. `}
  110. />
  111. </SidePanel.Content>
  112. <SidePanel.Content className="flex flex-col gap-2">
  113. <ProjectLinker
  114. slug={selectedOrganization?.slug}
  115. defaultBrivenProjectRef={ref}
  116. organizationIntegrationId={selectedIntegration?.id}
  117. foreignProjects={vercelProjects}
  118. onCreateConnections={onCreateConnections}
  119. installedConnections={selectedIntegration?.connections}
  120. isLoading={isCreatingConnection}
  121. integrationIcon={VERCEL_ICON}
  122. getForeignProjectIcon={getForeignProjectIcon}
  123. choosePrompt="Choose Vercel Project"
  124. mode="Vercel"
  125. />
  126. <Markdown
  127. content={`
  128. The following environment variables will be added:
  129. ${ENV_VAR_RAW_KEYS.map((x) => {
  130. return `\n - \`${x}\``
  131. })}
  132. `}
  133. />
  134. </SidePanel.Content>
  135. <SidePanel.Content>
  136. <ul>
  137. <li className="border px-10">
  138. {/* <IntegrationConnectionOption connection={githubIntegrations[0]} /> */}
  139. </li>
  140. </ul>
  141. </SidePanel.Content>
  142. </div>
  143. </SidePanel>
  144. )
  145. }
  146. export default SidePanelVercelProjectLinker