Files
supabase/apps/studio/components/interfaces/Settings/Integrations/AWSPrivateLink/AWSPrivateLink.utils.ts
Danny White 4760c1af77 feat(studio): polish PrivateLink connection UI (#49164)
## What kind of change does this PR introduce?

Polish for the AWS PrivateLink integrations UI.

## What is the current behavior?

The add/view sheet labels the optional nickname field as "Description",
delete confirmation always shows the AWS account ID, list admonitions
use generic copy, and delete uses a fire-and-forget mutation.

## What is the new behavior?

- Rename the optional nickname field to **Name**, with helper copy
explaining it appears on the connections list
- Tighten list admonition copy to reference connections below and
pluralise share wording
- Rename `showAcceptLink` to `shouldShowAcceptLink`
- Delete confirmation uses the connection name (or account ID when
unnamed) and clearer read replica fallback copy
- Delete uses `mutateAsync` so the dialog can await the mutation

| Before | After | 
| --- | --- |
| <img width="828" height="515" alt="Integrations Settings Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/9e255d4b-a048-459c-87ff-ee1b65f42f9a"
/> | <img width="828" height="515" alt="Integrations Settings Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/500e3922-912f-4e3b-a875-295ac7bd689e"
/> |

## To test

1. Open **Project settings → Integrations → AWS PrivateLink** on a
project with PrivateLink access
2. Click **Add connection** and confirm the optional field is labelled
**Name** with helper copy underneath
3. Add a connection with a name (e.g. `Production VPC`) and confirm the
list row shows that title
4. If you have a waiting or expired connection, confirm the list
admonition copy references shares below
5. Open a named connection, click **Delete**, and confirm the dialog
uses the connection name rather than always showing the raw account ID
6. Cancel delete and confirm the sheet stays open

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Updated AWS PrivateLink connection messages with clearer singular and
plural wording.
* Improved guidance for expired and pending connections, including
acceptance-instruction links.
* Renamed the account field to “Name,” marked it optional, and clarified
its purpose and default behavior.
* Enhanced deletion confirmations with clearer connection names and AWS
account identifiers.
  * Improved deletion handling to provide more reliable feedback.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-18 14:25:42 +10:00

107 lines
3.0 KiB
TypeScript

import type { AWSAccount } from '@/data/aws-accounts/aws-accounts-query'
export type PrivateLinkConnectionStatus = AWSAccount['status']
type BadgeVariant = 'success' | 'warning' | 'destructive' | 'default'
export type ConnectionStatusUi = {
badge: string
badgeVariant: BadgeVariant
}
const CONNECTION_STATUS_UI: Record<PrivateLinkConnectionStatus, ConnectionStatusUi> = {
ASSOCIATION_ACCEPTED: {
badge: 'Connected',
badgeVariant: 'success',
},
READY: {
badge: 'Waiting',
badgeVariant: 'warning',
},
CREATING: {
badge: 'Creating',
badgeVariant: 'default',
},
DELETING: {
badge: 'Deleting',
badgeVariant: 'warning',
},
ASSOCIATION_REQUEST_EXPIRED: {
badge: 'Expired',
badgeVariant: 'destructive',
},
CREATION_FAILED: {
badge: 'Failed',
badgeVariant: 'destructive',
},
}
const UNKNOWN_STATUS_UI: ConnectionStatusUi = {
badge: 'Unknown',
badgeVariant: 'default',
}
export function getConnectionStatusUi(status?: PrivateLinkConnectionStatus): ConnectionStatusUi {
if (!status) return UNKNOWN_STATUS_UI
return CONNECTION_STATUS_UI[status] ?? UNKNOWN_STATUS_UI
}
export function getConnectionTitle(
account: Pick<AWSAccount, 'account_name' | 'aws_account_id'>
): string {
const nickname = account.account_name?.trim()
if (nickname) return nickname
return account.aws_account_id
}
export type ConnectionsAttention = {
waitingCount: number
expiredCount: number
}
export function getConnectionsAttention(
accounts: Array<Pick<AWSAccount, 'status'>> | undefined
): ConnectionsAttention {
const waitingCount = accounts?.filter((account) => account.status === 'READY').length ?? 0
const expiredCount =
accounts?.filter((account) => account.status === 'ASSOCIATION_REQUEST_EXPIRED').length ?? 0
return { waitingCount, expiredCount }
}
export function getConnectionsAttentionCopy(attention: ConnectionsAttention): {
type: 'warning' | 'destructive'
title: string
description: string
shouldShowAcceptLink: boolean
} | null {
const { waitingCount, expiredCount } = attention
if (waitingCount === 0 && expiredCount === 0) return null
if (expiredCount > 0 && waitingCount === 0) {
return {
type: 'destructive',
title: expiredCount === 1 ? 'A connection request expired' : 'Connection requests expired',
description: `AWS can no longer accept ${expiredCount === 1 ? 'this share' : 'these shares'}.`,
shouldShowAcceptLink: false,
}
}
if (waitingCount > 0 && expiredCount > 0) {
return {
type: 'warning',
title: 'Some connections need attention',
description: `Accept the waiting resource share${waitingCount === 1 ? '' : 's'} in AWS within 12 hours.`,
shouldShowAcceptLink: true,
}
}
return {
type: 'warning',
title:
waitingCount === 1 ? 'Waiting for the AWS account owner' : 'Waiting for AWS account owners',
description: `Accept the resource share${waitingCount === 1 ? '' : 's'} in AWS within 12 hours.`,
shouldShowAcceptLink: true,
}
}