IPv4StatusPanel.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { ChevronRight, X } from 'lucide-react'
  2. import Link from 'next/link'
  3. import { ReactNode } from 'react'
  4. import { Button, cn, Collapsible, CollapsibleContent, CollapsibleTrigger, WarningIcon } from 'ui'
  5. import { IS_PLATFORM } from '@/lib/constants'
  6. const IPv4StatusIcon = ({ className, active }: { className?: string; active: boolean }) => {
  7. return (
  8. <div className={cn('relative inline-flex', className)}>
  9. <svg
  10. xmlns="http://www.w3.org/2000/svg"
  11. fill="none"
  12. viewBox="0 0 24 24"
  13. strokeWidth="1"
  14. stroke="currentColor"
  15. className="size-6 stroke-foreground-lighter"
  16. >
  17. <path
  18. strokeLinecap="round"
  19. strokeLinejoin="round"
  20. d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418"
  21. />
  22. </svg>
  23. {!active ? (
  24. <div className="absolute -right-1.5 -top-1.5 bg-destructive rounded-sm w-4 h-4 flex items-center justify-center">
  25. <X size={10} strokeWidth={4} className="text-white rounded-full" />
  26. </div>
  27. ) : (
  28. <div className="absolute -right-1.5 -top-1.5 bg-brand-500 rounded-sm w-4 h-4 flex items-center justify-center">
  29. <svg
  30. width="10"
  31. height="10"
  32. viewBox="0 0 10 10"
  33. fill="none"
  34. xmlns="http://www.w3.org/2000/svg"
  35. >
  36. <path
  37. d="M8.33325 2.5L3.74992 7.08333L1.66659 5"
  38. stroke="white"
  39. strokeWidth="2"
  40. strokeLinecap="round"
  41. strokeLinejoin="round"
  42. />
  43. </svg>
  44. </div>
  45. )}
  46. </div>
  47. )
  48. }
  49. export interface IPv4Status {
  50. type: 'error' | 'success'
  51. title: string
  52. description?: string | ReactNode
  53. links?: { text: string; url: string }[]
  54. }
  55. interface IPv4StatusPanelProps {
  56. method: 'direct' | 'transaction' | 'session'
  57. ipv4Status: IPv4Status
  58. projectRef: string
  59. }
  60. export function IPv4StatusPanel({ method, ipv4Status, projectRef }: IPv4StatusPanelProps) {
  61. if (!IS_PLATFORM) return null
  62. const links = ipv4Status.links ?? []
  63. return (
  64. <div className="flex flex-col -space-y-px w-full">
  65. {method === 'session' ? (
  66. <div className="border border-muted px-5 flex gap-7 items-center py-3 rounded-sm bg-alternative/50">
  67. <div className="flex w-6 h-6 rounded-sm items-center justify-center gap-2 shrink-0 bg-surface-100">
  68. <WarningIcon />
  69. </div>
  70. <div className="flex flex-col">
  71. <span className="text-xs text-foreground">Only use on a IPv4 network</span>
  72. <div className="flex flex-col text-xs text-foreground-lighter">
  73. <p>Session pooler connections are IPv4 proxied for free.</p>
  74. <p>Use Direct Connection if connecting via an IPv6 network.</p>
  75. </div>
  76. </div>
  77. </div>
  78. ) : (
  79. <>
  80. <div
  81. className={cn(
  82. 'border border-muted px-5 flex gap-7 items-center py-3 first:rounded-t',
  83. ipv4Status.type === 'error' ? 'rounded-b-none' : 'last:rounded-b'
  84. )}
  85. >
  86. <div className="flex items-center gap-2">
  87. <IPv4StatusIcon active={ipv4Status.type === 'success'} />
  88. </div>
  89. <div className="flex flex-col">
  90. <span className="text-xs text-foreground">{ipv4Status.title}</span>
  91. {ipv4Status.description &&
  92. (typeof ipv4Status.description === 'string' ? (
  93. <span className="text-xs text-foreground-lighter">{ipv4Status.description}</span>
  94. ) : (
  95. ipv4Status.description
  96. ))}
  97. {links.length > 0 && (
  98. <div className="flex items-center gap-x-2 mt-2">
  99. {links.map((link) => (
  100. <Button key={link.text} asChild type="default" size="tiny">
  101. <Link href={link.url} className="text-xs text-light hover:text-foreground">
  102. {link.text}
  103. </Link>
  104. </Button>
  105. ))}
  106. </div>
  107. )}
  108. </div>
  109. </div>
  110. {ipv4Status.type === 'error' && (
  111. <Collapsible className="group -space-y-px">
  112. <CollapsibleTrigger
  113. asChild
  114. className="group/collapse w-full justify-start rounded-t-none !last:rounded-b group-data-open:rounded-b-none border-muted"
  115. >
  116. <Button
  117. type="default"
  118. size="tiny"
  119. className="text-foreground-lighter bg-dash-sidebar!"
  120. icon={
  121. <ChevronRight
  122. className={cn(
  123. 'group-data-open/collapse:rotate-90 text-foreground-muted transition-transform'
  124. )}
  125. />
  126. }
  127. >
  128. Some platforms are IPv4-only:
  129. </Button>
  130. </CollapsibleTrigger>
  131. <CollapsibleContent className="bg-dash-sidebar rounded-b border px-3 py-2">
  132. <div className="flex flex-col gap-2">
  133. <p className="text-xs text-foreground-light max-w-xs">
  134. A few major platforms are IPv4-only and may not work with a Direct Connection:
  135. </p>
  136. <div className="flex gap-4">
  137. <div className="text-foreground text-xs">Vercel</div>
  138. <div className="text-foreground text-xs">GitHub Actions</div>
  139. <div className="text-foreground text-xs">Render</div>
  140. <div className="text-foreground text-xs">Retool</div>
  141. </div>
  142. <p className="text-xs text-foreground-lighter max-w-xs">
  143. If you wish to use a Direct Connection with these, please purchase{' '}
  144. <Link
  145. href={`/project/${projectRef}/settings/addons?panel=ipv4`}
  146. className="text-xs text-light hover:text-foreground"
  147. >
  148. IPv4 support
  149. </Link>
  150. .
  151. </p>
  152. <p className="text-xs text-foreground-lighter max-w-xs">
  153. You may also use the{' '}
  154. <span className="text-foreground-light">Session Pooler</span> or{' '}
  155. <span className="text-foreground-light">Transaction Pooler</span> if you are on
  156. a IPv4 network.
  157. </p>
  158. </div>
  159. </CollapsibleContent>
  160. </Collapsible>
  161. )}
  162. </>
  163. )}
  164. </div>
  165. )
  166. }