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