IntegrationConnection.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // @ts-nocheck
  2. import { ChevronDown, Loader2, RefreshCw, Trash } from 'lucide-react'
  3. import Link from 'next/link'
  4. import { useRouter } from 'next/router'
  5. import { forwardRef, useCallback, useState } from 'react'
  6. import { toast } from 'sonner'
  7. import {
  8. Button,
  9. DropdownMenu,
  10. DropdownMenuContent,
  11. DropdownMenuItem,
  12. DropdownMenuSeparator,
  13. DropdownMenuTrigger,
  14. } from 'ui'
  15. import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
  16. import {
  17. IntegrationConnection,
  18. IntegrationConnectionProps,
  19. } from '@/components/interfaces/Integrations/VercelGithub/IntegrationPanels'
  20. import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
  21. import { useIntegrationsVercelConnectionSyncEnvsMutation } from '@/data/integrations/integrations-vercel-connection-sync-envs-mutation'
  22. import type { IntegrationProjectConnection } from '@/data/integrations/integrations.types'
  23. import { useProjectDetailQuery } from '@/data/projects/project-detail-query'
  24. import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
  25. interface IntegrationConnectionItemProps extends IntegrationConnectionProps {
  26. disabled?: boolean
  27. onDeleteConnection: (connection: IntegrationProjectConnection) => void | Promise<void>
  28. }
  29. export const IntegrationConnectionItem = forwardRef<HTMLLIElement, IntegrationConnectionItemProps>(
  30. ({ disabled, onDeleteConnection, ...props }, _ref) => {
  31. const router = useRouter()
  32. const { data: org } = useSelectedOrganizationQuery()
  33. const { type, connection } = props
  34. const { data: project } = useProjectDetailQuery({ ref: connection.briven_project_ref })
  35. const isBranchingEnabled = project?.is_branch_enabled === true
  36. const [isOpen, setIsOpen] = useState(false)
  37. const [isDeleting, setIsDeleting] = useState(false)
  38. const [dropdownVisible, setDropdownVisible] = useState(false)
  39. const onConfirm = useCallback(async () => {
  40. try {
  41. setIsDeleting(true)
  42. await onDeleteConnection(connection)
  43. } catch (error) {
  44. // [Joshen] No need for error handler
  45. } finally {
  46. setIsDeleting(false)
  47. setIsOpen(false)
  48. }
  49. }, [connection, onDeleteConnection])
  50. const onCancel = useCallback(() => {
  51. setIsOpen(false)
  52. }, [])
  53. const { mutate: syncEnvs, isPending: isSyncEnvLoading } =
  54. useIntegrationsVercelConnectionSyncEnvsMutation({
  55. onSuccess: () => {
  56. toast.success('Successfully synced environment variables')
  57. setDropdownVisible(false)
  58. },
  59. })
  60. const onReSyncEnvVars = useCallback(async () => {
  61. syncEnvs({ connectionId: connection.id })
  62. }, [connection, syncEnvs])
  63. const projectIntegrationUrl = `/project/[ref]/settings/integrations`
  64. return (
  65. <>
  66. <IntegrationConnection
  67. showNode={false}
  68. actions={
  69. disabled ? (
  70. <ButtonTooltip
  71. disabled
  72. iconRight={<ChevronDown size={14} />}
  73. type="default"
  74. tooltip={{
  75. content: {
  76. side: 'bottom',
  77. text: 'You need additional permissions to manage this connection',
  78. },
  79. }}
  80. >
  81. Manage
  82. </ButtonTooltip>
  83. ) : (
  84. <DropdownMenu
  85. open={dropdownVisible}
  86. onOpenChange={() => setDropdownVisible(!dropdownVisible)}
  87. modal={false}
  88. >
  89. <DropdownMenuTrigger asChild>
  90. <Button iconRight={<ChevronDown size={14} />} type="default">
  91. <span>Manage</span>
  92. </Button>
  93. </DropdownMenuTrigger>
  94. <DropdownMenuContent side="bottom" align="end">
  95. {router.pathname !== projectIntegrationUrl && (
  96. <DropdownMenuItem asChild>
  97. <Link
  98. href={projectIntegrationUrl.replace(
  99. '[ref]',
  100. connection.briven_project_ref
  101. )}
  102. >
  103. Configure connection
  104. </Link>
  105. </DropdownMenuItem>
  106. )}
  107. {type === 'Vercel' && org?.managed_by !== 'vercel-marketplace' && (
  108. <DropdownMenuItem
  109. className="space-x-2"
  110. onSelect={(event) => {
  111. event.preventDefault()
  112. onReSyncEnvVars()
  113. }}
  114. disabled={isSyncEnvLoading}
  115. >
  116. {isSyncEnvLoading ? (
  117. <Loader2 className="animate-spin" size={14} />
  118. ) : (
  119. <RefreshCw size={14} />
  120. )}
  121. <p>Resync environment variables</p>
  122. </DropdownMenuItem>
  123. )}
  124. {((type === 'Vercel' && org?.managed_by !== 'vercel-marketplace') ||
  125. router.pathname !== projectIntegrationUrl) && <DropdownMenuSeparator />}
  126. <DropdownMenuItem className="space-x-2" onSelect={() => setIsOpen(true)}>
  127. <Trash size={14} />
  128. <p>Delete connection</p>
  129. </DropdownMenuItem>
  130. </DropdownMenuContent>
  131. </DropdownMenu>
  132. )
  133. }
  134. {...props}
  135. />
  136. <ConfirmationModal
  137. variant="destructive"
  138. size={type === 'GitHub' && isBranchingEnabled ? 'medium' : 'small'}
  139. visible={isOpen}
  140. title={`Confirm to delete ${type} connection`}
  141. confirmLabel="Delete connection"
  142. onCancel={onCancel}
  143. onConfirm={onConfirm}
  144. loading={isDeleting}
  145. >
  146. <p className="text-sm text-foreground-light">
  147. {type === 'Vercel'
  148. ? 'Deleting this Vercel connection will stop syncing environment variables to your Vercel project. Existing environment variables will remain unchanged.'
  149. : 'Deleting this GitHub connection will stop automatic creation and merging of preview branches. Existing preview branches will remain unchanged.'}
  150. </p>
  151. </ConfirmationModal>
  152. </>
  153. )
  154. }
  155. )
  156. IntegrationConnectionItem.displayName = 'IntegrationConnectionItem'