mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 23:59:08 +03:00
feat(db-playground): animated edge path length
This commit is contained in:
1 parent
debc6569c2
commit
0fb5faf114
2 files changed
+96
-16
No files matched your search
@@ -12,7 +12,7 @@ import ReactFlow, {
|
||||
useReactFlow,
|
||||
} from 'reactflow'
|
||||
import SchemaGraphLegend from './legend'
|
||||
import { TABLE_NODE_ROW_HEIGHT, TABLE_NODE_WIDTH, TableNode } from './table-node'
|
||||
import { TABLE_NODE_ROW_HEIGHT, TABLE_NODE_WIDTH, TableEdge, TableNode } from './table-node'
|
||||
|
||||
export default function TablesGraph({ tables }: { tables: PostgresTable[] }) {
|
||||
const { resolvedTheme } = useTheme()
|
||||
@@ -24,6 +24,12 @@ export default function TablesGraph({ tables }: { tables: PostgresTable[] }) {
|
||||
}),
|
||||
[]
|
||||
)
|
||||
const edgeTypes = useMemo(
|
||||
() => ({
|
||||
table: TableEdge,
|
||||
}),
|
||||
[]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
getGraphDataFromTables(tables).then(({ nodes, edges }) => {
|
||||
@@ -49,14 +55,17 @@ export default function TablesGraph({ tables }: { tables: PostgresTable[] }) {
|
||||
defaultEdges={[]}
|
||||
defaultEdgeOptions={{
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
deletable: false,
|
||||
style: {
|
||||
stroke: 'hsl(var(--border-stronger))',
|
||||
strokeWidth: 0.5,
|
||||
strokeWidth: 1,
|
||||
strokeDasharray: 5,
|
||||
// Manually create animation so that it doesn't interfere with our custom edge component
|
||||
animation: 'dashdraw 0.5s linear infinite',
|
||||
},
|
||||
}}
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
minZoom={0.8}
|
||||
maxZoom={1.8}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
@@ -103,18 +112,20 @@ async function getGraphDataFromTables(tables: PostgresTable[]): Promise<{
|
||||
}
|
||||
|
||||
const nodes = tables.map((table) => {
|
||||
const columns = (table.columns || []).map((column) => {
|
||||
return {
|
||||
id: column.id,
|
||||
isPrimary: table.primary_keys.some((pk) => pk.name === column.name),
|
||||
name: column.name,
|
||||
format: column.format,
|
||||
isNullable: column.is_nullable,
|
||||
isUnique: column.is_unique,
|
||||
isUpdateable: column.is_updatable,
|
||||
isIdentity: column.is_identity,
|
||||
}
|
||||
})
|
||||
const columns = (table.columns || [])
|
||||
.sort((a, b) => a.ordinal_position - b.ordinal_position)
|
||||
.map((column) => {
|
||||
return {
|
||||
id: column.id,
|
||||
isPrimary: table.primary_keys.some((pk) => pk.name === column.name),
|
||||
name: column.name,
|
||||
format: column.format,
|
||||
isNullable: column.is_nullable,
|
||||
isUnique: column.is_unique,
|
||||
isUpdateable: column.is_updatable,
|
||||
isIdentity: column.is_identity,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
id: `${table.id}`,
|
||||
@@ -163,6 +174,7 @@ async function getGraphDataFromTables(tables: PostgresTable[]): Promise<{
|
||||
if (source) {
|
||||
edges.push({
|
||||
id: String(rel.id),
|
||||
type: 'table',
|
||||
source,
|
||||
sourceHandle,
|
||||
target: rel.constraint_name,
|
||||
@@ -188,6 +200,7 @@ async function getGraphDataFromTables(tables: PostgresTable[]): Promise<{
|
||||
if (source && target) {
|
||||
edges.push({
|
||||
id: String(rel.id),
|
||||
type: 'table',
|
||||
source,
|
||||
sourceHandle,
|
||||
target,
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { AnimatePresence, m } from 'framer-motion'
|
||||
import { DiamondIcon, Fingerprint, Hash, Key, Table2 } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { Handle, NodeProps, useUpdateNodeInternals } from 'reactflow'
|
||||
import {
|
||||
EdgeProps,
|
||||
Handle,
|
||||
NodeProps,
|
||||
Position,
|
||||
getSmoothStepPath,
|
||||
useUpdateNodeInternals,
|
||||
} from 'reactflow'
|
||||
import { cn } from 'ui'
|
||||
|
||||
// ReactFlow is scaling everything by the factor of 2
|
||||
@@ -33,6 +40,9 @@ const inOutTop = {
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom node to display database tables.
|
||||
*/
|
||||
export const TableNode = ({
|
||||
id,
|
||||
data,
|
||||
@@ -258,3 +268,60 @@ export const TableNode = ({
|
||||
</m.div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom edge that animates its path length.
|
||||
*/
|
||||
export function TableEdge({
|
||||
id,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
style,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetPosition = Position.Top,
|
||||
markerEnd,
|
||||
markerStart,
|
||||
pathOptions,
|
||||
}: EdgeProps) {
|
||||
const [path] = getSmoothStepPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition,
|
||||
borderRadius: pathOptions?.borderRadius,
|
||||
offset: pathOptions?.offset,
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<defs>
|
||||
{/* Create a mask with the same shape that animates its path length */}
|
||||
<mask id={`mask-${id}`}>
|
||||
<m.path
|
||||
d={path}
|
||||
fill="none"
|
||||
stroke="white"
|
||||
strokeWidth={10}
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: 1 }}
|
||||
transition={{ duration: 0.25 }}
|
||||
/>
|
||||
</mask>
|
||||
</defs>
|
||||
<path
|
||||
id={id}
|
||||
d={path}
|
||||
style={style}
|
||||
className={cn(['react-flow__edge-path'])}
|
||||
fill="none"
|
||||
mask={`url(#mask-${id})`}
|
||||
markerEnd={markerEnd}
|
||||
markerStart={markerStart}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user