Files
Sankofa/src/components/editors/ResourceGraphEditor.tsx

136 lines
3.2 KiB
TypeScript
Raw Normal View History

'use client'
import { useCallback, useMemo } from 'react'
import ReactFlow, {
Node,
Edge,
addEdge,
Connection,
useNodesState,
useEdgesState,
Controls,
MiniMap,
Background,
MarkerType,
} from 'reactflow'
import { useQuery } from '@tanstack/react-query'
import { gql } from 'graphql-tag'
import { apolloClient } from '@/lib/graphql/client'
import 'reactflow/dist/style.css'
const GET_RESOURCE_GRAPH = gql`
query GetResourceGraph($query: ResourceGraphQuery) {
resourceGraph(query: $query) {
nodes {
id
resourceType
provider
name
region
}
edges {
id
source
target
relationshipType
}
}
}
`
export function ResourceGraphEditor({ query }: { query?: any }) {
const { data } = useQuery({
queryKey: ['resourceGraph', query],
queryFn: async () => {
const result = await apolloClient.query({
query: GET_RESOURCE_GRAPH,
variables: { query },
})
return result.data.resourceGraph
},
})
const initialNodes = useMemo<Node[]>(() => {
if (!data?.nodes) return []
return data.nodes.map((node: any, index: number) => ({
id: node.id,
type: 'default',
data: { label: node.name },
position: {
x: (index % 10) * 150 + 50,
y: Math.floor(index / 10) * 150 + 50,
},
style: {
background: getProviderColor(node.provider),
color: '#FFFFFF',
border: '2px solid #FF4500',
borderRadius: '8px',
padding: '10px',
},
}))
}, [data?.nodes])
const initialEdges = useMemo<Edge[]>(() => {
if (!data?.edges) return []
return data.edges.map((edge: any) => ({
id: edge.id,
source: edge.source,
target: edge.target,
label: edge.relationshipType,
markerEnd: {
type: MarkerType.ArrowClosed,
color: '#FF4500',
},
style: {
stroke: '#FF4500',
strokeWidth: 2,
},
}))
}, [data?.edges])
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
const onConnect = useCallback(
(params: Connection) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
)
function getProviderColor(provider: string): string {
const colors: Record<string, string> = {
PROXMOX: '#FF4500',
KUBERNETES: '#326CE5',
CLOUDFLARE: '#F38020',
CEPH: '#FF6B35',
MINIO: '#FFD700',
}
return colors[provider] || '#2A2A2A'
}
return (
<div className="h-[800px] w-full rounded-lg border border-studio-medium bg-studio-black">
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
className="bg-studio-black"
>
<Controls className="bg-studio-dark border-studio-medium" />
<MiniMap
className="bg-studio-dark border-studio-medium"
nodeColor={(node) => {
return node.style?.background as string || '#2A2A2A'
}}
/>
<Background color="#2A2A2A" gap={16} />
</ReactFlow>
</div>
)
}