mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
## Problem In branched Pipelines diagrams, status chips sit on the shared vertical bend, making flow direction unclear. - Resolves [DEPR-689](https://linear.app/supabase/issue/DEPR-689/move-pipeline-arrows-to-horizontal-edge-segments) - Resolves duplicate [PIPE-1079](https://linear.app/supabase/issue/PIPE-1079/move-destination-chart-arrows-to-horizontal-edges) ## Solution Place each chip on its destination's final horizontal edge segment. Keep the single-destination chip centred on its straight edge. | 1× Destination (No Change) | | --- | | <img width="1352" height="678" alt="CleanShot 2026-09-29 at 14 03 22@2x" src="https://github.com/user-attachments/assets/c495318c-811b-4817-9b25-af32d12d8e08" /> | | _Before_ | | <img width="1350" height="682" alt="CleanShot 2026-09-29 at 14 02 37@2x" src="https://github.com/user-attachments/assets/da862b82-4605-48df-93cd-c035443acc9d" /> | | _After_ | | 2× Destinations | | --- | | <img width="1354" height="680" alt="CleanShot 2026-09-29 at 14 01 15@2x" src="https://github.com/user-attachments/assets/970aa562-1ab9-4ff1-90e0-3c0fe95d01dc" /> | | _Before_ | | <img width="1354" height="674" alt="CleanShot 2026-09-29 at 14 00 50@2x" src="https://github.com/user-attachments/assets/5501657b-32a2-485d-907f-8a0a8fae595d" /> | | _After_ | ## Review instructions 1. Open Database > Pipelines with one destination, then with several. Check the chip position and arrow direction at desktop and phone widths. ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved label placement in the database replication diagram when edges are shifted, making the connections easier to read. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
import { BaseEdge, EdgeLabelRenderer, getSmoothStepPath, type EdgeProps } from '@xyflow/react'
|
|
import { useParams, useReducedMotion } from 'common'
|
|
import { useMemo } from 'react'
|
|
|
|
import { getStatusName } from '../Pipeline.utils'
|
|
import {
|
|
EdgeVisualChip,
|
|
getEdgeVisual,
|
|
type ReplicationState,
|
|
} from '@/components/ui/ReactFlow/EdgeVisual'
|
|
import { useReplicationPipelineStatusQuery } from '@/data/replication/pipeline-status-query'
|
|
import { useReplicationPipelinesQuery } from '@/data/replication/pipelines-query'
|
|
import {
|
|
PipelineStatusRequestStatus,
|
|
usePipelineRequestStatus,
|
|
} from '@/state/replication-pipeline-request-status'
|
|
|
|
type EdgeData = {
|
|
type: string
|
|
identifier: string
|
|
shiftEdgeEnd: boolean
|
|
}
|
|
|
|
export const SmoothstepEdge = ({
|
|
sourceX,
|
|
sourceY,
|
|
targetX,
|
|
targetY,
|
|
sourcePosition,
|
|
targetPosition,
|
|
style = {},
|
|
markerEnd,
|
|
data,
|
|
}: EdgeProps) => {
|
|
const { ref: projectRef = 'default' } = useParams()
|
|
const prefersReducedMotion = useReducedMotion()
|
|
const { identifier, shiftEdgeEnd } = (data || {}) as EdgeData
|
|
|
|
const { data: pipelinesData } = useReplicationPipelinesQuery({ projectRef })
|
|
const pipeline = (pipelinesData?.pipelines ?? []).find(
|
|
(p) => p.destination_id.toString() === identifier
|
|
)
|
|
const { data: pipelineStatusData } = useReplicationPipelineStatusQuery(
|
|
{ projectRef, pipelineId: pipeline?.id },
|
|
{ enabled: !!pipeline?.id }
|
|
)
|
|
const { getRequestStatus } = usePipelineRequestStatus()
|
|
const requestStatus = pipeline?.id
|
|
? getRequestStatus(pipeline.id)
|
|
: PipelineStatusRequestStatus.None
|
|
|
|
const replicationState = useMemo<ReplicationState>(() => {
|
|
const isTransitioning = requestStatus !== PipelineStatusRequestStatus.None
|
|
const statusName = getStatusName(pipelineStatusData?.status)
|
|
return {
|
|
isReplicating: statusName === 'started' && !isTransitioning,
|
|
isComingUp: isTransitioning || statusName === 'starting' || statusName === 'stopping',
|
|
isFailed: statusName === 'failed',
|
|
}
|
|
}, [pipelineStatusData?.status, requestStatus])
|
|
|
|
const edgeTargetX = shiftEdgeEnd ? targetX - 8 : targetX
|
|
const [edgePath, labelX, labelY] = getSmoothStepPath({
|
|
sourceX,
|
|
sourceY,
|
|
sourcePosition,
|
|
targetX: edgeTargetX,
|
|
targetY,
|
|
targetPosition,
|
|
})
|
|
// Branched paths label their shared vertical bend, so move the chip onto each final segment.
|
|
const chipX = shiftEdgeEnd ? (labelX + edgeTargetX) / 2 : labelX
|
|
const chipY = shiftEdgeEnd ? targetY : labelY
|
|
|
|
const visual = getEdgeVisual(replicationState)
|
|
|
|
return (
|
|
<>
|
|
<BaseEdge
|
|
path={edgePath}
|
|
markerEnd={markerEnd}
|
|
style={{
|
|
...style,
|
|
stroke: visual.color,
|
|
strokeWidth: visual.strokeWidth,
|
|
opacity: visual.opacity,
|
|
strokeDasharray: visual.dashArray,
|
|
animation:
|
|
visual.shouldAnimate && !prefersReducedMotion
|
|
? 'dashdraw 0.5s linear infinite'
|
|
: undefined,
|
|
}}
|
|
/>
|
|
<EdgeLabelRenderer>
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
transform: `translate(-50%, -50%) translate(${chipX}px,${chipY}px)`,
|
|
pointerEvents: 'all',
|
|
}}
|
|
className="nodrag nopan"
|
|
>
|
|
<EdgeVisualChip visual={visual} />
|
|
</div>
|
|
</EdgeLabelRenderer>
|
|
</>
|
|
)
|
|
}
|