AWSPrivateLinkSection.tsx143 lines · main
| 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 | |
| 6 | import { IntegrationImageHandler } from '../IntegrationsSettings' |
| 7 | import { AWSPrivateLinkAccountItem } from './AWSPrivateLinkAccountItem' |
| 8 | import { AWSPrivateLinkForm } from './AWSPrivateLinkForm' |
| 9 | import { |
| 10 | ScaffoldContainer, |
| 11 | ScaffoldSection, |
| 12 | ScaffoldSectionContent, |
| 13 | ScaffoldSectionDetail, |
| 14 | } from '@/components/layouts/Scaffold' |
| 15 | import { ResourceList } from '@/components/ui/Resource/ResourceList' |
| 16 | import { UpgradeToPro } from '@/components/ui/UpgradeToPro' |
| 17 | import { useAWSAccountDeleteMutation } from '@/data/aws-accounts/aws-account-delete-mutation' |
| 18 | import type { AWSAccount } from '@/data/aws-accounts/aws-accounts-query' |
| 19 | import { useAWSAccountsQuery } from '@/data/aws-accounts/aws-accounts-query' |
| 20 | import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' |
| 21 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 22 | import { IS_PLATFORM } from '@/lib/constants' |
| 23 | |
| 24 | export 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 | } |