DataApiProjectUrlCard.tsx 3.8 KB

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