Edges.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { BaseEdge, EdgeLabelRenderer, getSmoothStepPath, type EdgeProps } from '@xyflow/react'
  2. import { useParams } from 'common'
  3. import { Loader2, X } from 'lucide-react'
  4. import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
  5. import { useReplicationLagQuery } from '@/data/read-replicas/replica-lag-query'
  6. import { formatDatabaseID } from '@/data/read-replicas/replicas.utils'
  7. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  8. type EdgeData = {
  9. type: string
  10. identifier: string
  11. isComingUp: boolean
  12. isReplicating: boolean
  13. isFailed: boolean
  14. shiftEdgeEnd: boolean
  15. }
  16. export const SmoothstepEdge = ({
  17. sourceX,
  18. sourceY,
  19. targetX,
  20. targetY,
  21. sourcePosition,
  22. targetPosition,
  23. style = {},
  24. markerEnd,
  25. data,
  26. }: EdgeProps) => {
  27. const { ref } = useParams()
  28. const { data: project } = useSelectedProjectQuery()
  29. const { type, identifier, isComingUp, isReplicating, isFailed, shiftEdgeEnd } = (data ||
  30. {}) as EdgeData
  31. const formattedId = type === 'replica' ? formatDatabaseID(identifier ?? '') : identifier
  32. const [edgePath, labelX, labelY] = getSmoothStepPath({
  33. sourceX,
  34. sourceY,
  35. sourcePosition,
  36. targetX,
  37. targetY,
  38. targetPosition,
  39. })
  40. const {
  41. data: lagDuration,
  42. isPending: isLoading,
  43. isError,
  44. } = useReplicationLagQuery(
  45. {
  46. id: identifier,
  47. projectRef: ref,
  48. connectionString: project?.connectionString,
  49. },
  50. { enabled: type === 'replica' && isReplicating, refetchInterval: 10000 }
  51. )
  52. const lagValue = Number(lagDuration?.toFixed(2) ?? 0).toLocaleString()
  53. const hasReplicationLagData = data !== undefined && !isError && isReplicating
  54. return (
  55. <>
  56. <BaseEdge path={edgePath} markerEnd={markerEnd} style={style} />
  57. {isFailed && (
  58. <EdgeLabelRenderer>
  59. <div
  60. className={cn('bg-surface-100 p-1 rounded-sm absolute nodrag nopan border')}
  61. style={{
  62. transform: `translate(-50%, -50%) translate(${targetX - 30}px,${targetY}px)`,
  63. }}
  64. >
  65. <X size={12} strokeWidth={4} className="text-destructive" />
  66. </div>
  67. </EdgeLabelRenderer>
  68. )}
  69. {(isComingUp || hasReplicationLagData) && (
  70. <EdgeLabelRenderer>
  71. <Tooltip>
  72. <TooltipTrigger asChild>
  73. <div
  74. className={cn(
  75. 'bg-surface-100 py-1 rounded-sm absolute nodrag nopan border',
  76. isLoading || isComingUp ? 'px-1' : 'px-1.5'
  77. )}
  78. style={{
  79. transform: `translate(-50%, -50%) translate(${shiftEdgeEnd ? targetX - 30 : labelX}px,${shiftEdgeEnd ? targetY : labelY}px)`,
  80. pointerEvents: 'all',
  81. }}
  82. >
  83. {isLoading || isComingUp ? (
  84. <Loader2 size={12} className="animate-spin" />
  85. ) : (
  86. <p className="font-mono text-xs">{lagValue}s</p>
  87. )}
  88. </div>
  89. </TooltipTrigger>
  90. {!isComingUp && (
  91. <TooltipContent side="bottom" align="center">
  92. {isLoading
  93. ? `Checking replication lag for replica ID: ${formattedId}`
  94. : `Replication lag (seconds) for replica ID: ${formattedId}`}
  95. </TooltipContent>
  96. )}
  97. </Tooltip>
  98. </EdgeLabelRenderer>
  99. )}
  100. </>
  101. )
  102. }