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