AWSPrivateLinkSection.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { useState } from 'react'
  2. import { toast } from 'sonner'
  3. import { Button, Card, CardContent, cn } from 'ui'
  4. import { ConfirmationModal } from 'ui-patterns/Dialogs/ConfirmationModal'
  5. import { IntegrationImageHandler } from '../IntegrationsSettings'
  6. import { AWSPrivateLinkAccountItem } from './AWSPrivateLinkAccountItem'
  7. import { AWSPrivateLinkForm } from './AWSPrivateLinkForm'
  8. import {
  9. ScaffoldContainer,
  10. ScaffoldSection,
  11. ScaffoldSectionContent,
  12. ScaffoldSectionDetail,
  13. } from '@/components/layouts/Scaffold'
  14. import { ResourceList } from '@/components/ui/Resource/ResourceList'
  15. import { UpgradeToPro } from '@/components/ui/UpgradeToPro'
  16. import { useAWSAccountDeleteMutation } from '@/data/aws-accounts/aws-account-delete-mutation'
  17. import type { AWSAccount } from '@/data/aws-accounts/aws-accounts-query'
  18. import { useAWSAccountsQuery } from '@/data/aws-accounts/aws-accounts-query'
  19. import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
  20. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  21. import { IS_PLATFORM } from '@/lib/constants'
  22. export const AWSPrivateLinkSection = () => {
  23. const { data: project } = useSelectedProjectQuery()
  24. const { data: accounts } = useAWSAccountsQuery({ projectRef: project?.ref })
  25. const [selectedAccount, setSelectedAccount] = useState<AWSAccount>()
  26. const [showForm, setShowForm] = useState(false)
  27. const [showDeleteModal, setShowDeleteModal] = useState(false)
  28. const { mutate: deleteAccount, isPending: isDeleting } = useAWSAccountDeleteMutation({
  29. onSuccess: () => {
  30. toast.success('Account will be deleted shortly')
  31. setShowDeleteModal(false)
  32. setSelectedAccount(undefined)
  33. },
  34. })
  35. const { hasAccess: hasPrivateLinkAccess } = useCheckEntitlements('security.private_link')
  36. const promptPlanUpgrade = IS_PLATFORM && !hasPrivateLinkAccess
  37. const onAddAccount = () => {
  38. setSelectedAccount(undefined)
  39. setShowForm(true)
  40. }
  41. const onEditAccount = (account: AWSAccount) => {
  42. setSelectedAccount(account)
  43. setShowForm(true)
  44. }
  45. const onDeleteAccount = (account: AWSAccount) => {
  46. setSelectedAccount(account)
  47. setShowDeleteModal(true)
  48. }
  49. const onConfirmDelete = () => {
  50. if (selectedAccount && project) {
  51. deleteAccount({ projectRef: project.ref, awsAccountId: selectedAccount.aws_account_id })
  52. }
  53. }
  54. return (
  55. <>
  56. <ScaffoldContainer>
  57. <ScaffoldSection className="py-12">
  58. <ScaffoldSectionDetail title="AWS PrivateLink">
  59. <p>Connect to your Briven project from your AWS VPC using AWS PrivateLink.</p>
  60. <IntegrationImageHandler title="aws" />
  61. </ScaffoldSectionDetail>
  62. <ScaffoldSectionContent>
  63. <div className="space-y-6">
  64. <div className="space-y-4">
  65. <div className="space-y-1">
  66. <h3 className="text-sm font-medium text-foreground">
  67. How does the AWS PrivateLink integration work?
  68. </h3>
  69. <p className="text-sm text-foreground-light">
  70. Connecting to AWS PrivateLink allows you to create a private connection between
  71. your AWS VPC and your Briven project.
  72. </p>
  73. </div>
  74. {promptPlanUpgrade && (
  75. <UpgradeToPro
  76. layout="vertical"
  77. primaryText="Only available on Team or Enterprise Plan and above"
  78. secondaryText="Connect your AWS VPC privately to your Briven project using AWS PrivateLink."
  79. buttonText="Upgrade to Team"
  80. source="aws-privatelink-integration"
  81. />
  82. )}
  83. </div>
  84. <div className={cn(promptPlanUpgrade && 'opacity-25 pointer-events-none')}>
  85. <div className="flex items-center justify-between mb-3">
  86. <h3 className="text-sm font-medium text-foreground">AWS Accounts</h3>
  87. <Button type="default" onClick={onAddAccount}>
  88. Add account
  89. </Button>
  90. </div>
  91. {(accounts?.length ?? 0) > 0 ? (
  92. <ResourceList>
  93. {accounts?.map((account) => (
  94. <AWSPrivateLinkAccountItem
  95. key={account.aws_account_id}
  96. {...account}
  97. onEdit={() => onEditAccount(account)}
  98. onDelete={() => onDeleteAccount(account)}
  99. />
  100. ))}
  101. </ResourceList>
  102. ) : (
  103. <Card>
  104. <CardContent>
  105. <p className="text-foreground-lighter text-sm">No accounts connected</p>
  106. </CardContent>
  107. </Card>
  108. )}
  109. </div>
  110. </div>
  111. </ScaffoldSectionContent>
  112. </ScaffoldSection>
  113. </ScaffoldContainer>
  114. <AWSPrivateLinkForm account={selectedAccount} open={showForm} onOpenChange={setShowForm} />
  115. <ConfirmationModal
  116. variant="destructive"
  117. visible={showDeleteModal}
  118. title="Confirm to delete AWS Account"
  119. confirmLabel="Delete"
  120. loading={isDeleting}
  121. onCancel={() => setShowDeleteModal(false)}
  122. onConfirm={onConfirmDelete}
  123. >
  124. <p className="text-sm text-foreground-light">
  125. Are you sure you want to delete the AWS account connection for{' '}
  126. {selectedAccount?.aws_account_id}?
  127. </p>
  128. </ConfirmationModal>
  129. </>
  130. )
  131. }