DataApiProjectUrlCard.tsx106 lines · main
| 1 | import { useParams } from 'common' |
| 2 | import { AlertCircle } from 'lucide-react' |
| 3 | import { parseAsString, useQueryState } from 'nuqs' |
| 4 | import { useEffect } from 'react' |
| 5 | import { Alert, AlertTitle } from 'ui' |
| 6 | import { |
| 7 | PageSection, |
| 8 | PageSectionAside, |
| 9 | PageSectionContent, |
| 10 | PageSectionDescription, |
| 11 | PageSectionMeta, |
| 12 | PageSectionSummary, |
| 13 | PageSectionTitle, |
| 14 | } from 'ui-patterns' |
| 15 | import { Input } from 'ui-patterns/DataInputs/Input' |
| 16 | import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' |
| 17 | |
| 18 | import { getApiEndpoint } from '@/components/interfaces/Integrations/DataApi/DataApi.utils' |
| 19 | import { DatabaseSelector } from '@/components/ui/DatabaseSelector' |
| 20 | import { useProjectApiUrl } from '@/data/config/project-endpoint-query' |
| 21 | import { useLoadBalancersQuery } from '@/data/read-replicas/load-balancers-query' |
| 22 | import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query' |
| 23 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 24 | import { useStaticEffectEvent } from '@/hooks/useStaticEffectEvent' |
| 25 | import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector' |
| 26 | |
| 27 | export const DataApiProjectUrlCard = () => { |
| 28 | const { isPending: isLoading } = useSelectedProjectQuery() |
| 29 | const { ref: projectRef } = useParams() |
| 30 | const state = useDatabaseSelectorStateSnapshot() |
| 31 | |
| 32 | const [querySource, setQuerySource] = useQueryState('source', parseAsString) |
| 33 | |
| 34 | const { data: resolvedEndpoint } = useProjectApiUrl({ projectRef }) |
| 35 | const { |
| 36 | data: databases, |
| 37 | isError, |
| 38 | isPending: isLoadingDatabases, |
| 39 | } = useReadReplicasQuery({ projectRef }) |
| 40 | const { data: loadBalancers } = useLoadBalancersQuery({ projectRef }) |
| 41 | |
| 42 | const syncSelectedDb = useStaticEffectEvent(() => { |
| 43 | if (querySource && querySource !== state.selectedDatabaseId) { |
| 44 | state.setSelectedDatabaseId(querySource) |
| 45 | } |
| 46 | }) |
| 47 | useEffect(() => { |
| 48 | syncSelectedDb() |
| 49 | }, [syncSelectedDb, querySource, projectRef]) |
| 50 | |
| 51 | const selectedDatabase = databases?.find((db) => db.identifier === state.selectedDatabaseId) |
| 52 | const loadBalancerSelected = state.selectedDatabaseId === 'load-balancer' |
| 53 | const replicaSelected = selectedDatabase?.identifier !== projectRef |
| 54 | |
| 55 | const endpoint = getApiEndpoint({ |
| 56 | selectedDatabaseId: state.selectedDatabaseId, |
| 57 | projectRef, |
| 58 | resolvedEndpoint, |
| 59 | loadBalancers, |
| 60 | selectedDatabase, |
| 61 | }) |
| 62 | |
| 63 | return ( |
| 64 | <PageSection className="first:pt-0"> |
| 65 | <PageSectionMeta> |
| 66 | <PageSectionSummary> |
| 67 | <PageSectionTitle>API URL</PageSectionTitle> |
| 68 | <PageSectionDescription> |
| 69 | {loadBalancerSelected |
| 70 | ? 'RESTful endpoint for querying and managing your databases through your load balancer' |
| 71 | : replicaSelected |
| 72 | ? 'RESTful endpoint for querying your read replica' |
| 73 | : 'RESTful endpoint for querying and managing your database'} |
| 74 | </PageSectionDescription> |
| 75 | </PageSectionSummary> |
| 76 | <PageSectionAside> |
| 77 | <DatabaseSelector |
| 78 | additionalOptions={ |
| 79 | (loadBalancers ?? []).length > 0 |
| 80 | ? [{ id: 'load-balancer', name: 'API Load Balancer' }] |
| 81 | : [] |
| 82 | } |
| 83 | onSelectId={() => { |
| 84 | setQuerySource(null) |
| 85 | }} |
| 86 | /> |
| 87 | </PageSectionAside> |
| 88 | </PageSectionMeta> |
| 89 | <PageSectionContent> |
| 90 | {isLoading || isLoadingDatabases ? ( |
| 91 | <div className="space-y-2"> |
| 92 | <ShimmeringLoader /> |
| 93 | <ShimmeringLoader className="w-3/4" delayIndex={1} /> |
| 94 | </div> |
| 95 | ) : isError ? ( |
| 96 | <Alert variant="destructive"> |
| 97 | <AlertCircle size={16} /> |
| 98 | <AlertTitle>Failed to retrieve project URL</AlertTitle> |
| 99 | </Alert> |
| 100 | ) : ( |
| 101 | <Input copy readOnly className="font-mono" value={endpoint} /> |
| 102 | )} |
| 103 | </PageSectionContent> |
| 104 | </PageSection> |
| 105 | ) |
| 106 | } |