Skip to content
This repository has been archived by the owner on Dec 16, 2024. It is now read-only.

Commit

Permalink
Improve graph nodes (#28)
Browse files Browse the repository at this point in the history
- Module nodes should be draggable now

<img width="954" alt="Screenshot 2023-05-12 at 12 22 20 AM"
src="https://github.com/TBD54566975/ftl/assets/51647/f377cbb8-a923-4c61-9c49-9b21a7e3618a">
<img width="954" alt="Screenshot 2023-05-12 at 12 22 31 AM"
src="https://github.com/TBD54566975/ftl/assets/51647/96189f76-30d2-4959-aaac-e1719e9e7096">
  • Loading branch information
wesbillman authored May 11, 2023
1 parent 0c50b11 commit c75c0cc
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 59 deletions.
82 changes: 23 additions & 59 deletions console/src/features/graph/GraphPage.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,34 @@
import { useContext } from 'react'
import ReactFlow, { Controls, MiniMap, Node, Edge } from 'reactflow'

import 'reactflow/dist/style.css'
import { useContext, useEffect } from 'react'
import ReactFlow, { Controls, MiniMap, useNodesState, useEdgesState } from 'reactflow'
import { schemaContext } from '../../providers/schema-provider'
import { MetadataCalls } from '../../protos/xyz/block/ftl/v1/schema/schema_pb'
import { GroupNode } from './GroupNode'
import { VerbNode } from './VerbNode'
import { layoutNodes } from './create-layout'
import 'reactflow/dist/style.css'

const nodeTypes = { groupNode: GroupNode, verbNode: VerbNode }

export default function GraphPage() {
const schema = useContext(schemaContext)
const [nodes, setNodes, onNodesChange] = useNodesState([])
const [edges, setEdges, onEdgesChange] = useEdgesState([])

const nodes: Node[] = []
const edges: Edge[] = []
let x = 0
schema.forEach(module => {
const verbs = module.schema?.decls.filter(decl => decl.value.case === 'verb')
nodes.push({
id: module.schema?.name ?? '',
position: { x: x, y: 0 },
data: { label: module.schema?.name },
connectable: false,
style: {
backgroundColor: 'rgba(79, 70, 229, 0.4)',
width: 190,
height: (verbs?.length ?? 1) * 50 + 50,
},
})
let y = 40
module.schema?.decls
.filter(decl => decl.value.case === 'verb')
.forEach(verb => {
const calls = verb?.value.value?.metadata
.filter(meta => meta.value.case === 'calls')
.map(meta => meta.value.value as MetadataCalls)

nodes.push({
id: `${module.schema?.name}-${verb.value.value?.name}`,
position: { x: x + 20, y: y },
connectable: false,
data: { label: verb.value.value?.name },
// parent: module.schema?.name,
style: {
backgroundColor: 'rgb(79, 70, 229)',
},
})

calls?.map(call =>
call.calls.forEach(call => {
edges.push({
id: `${module.schema?.name}-${verb.value.value?.name}-${call.module}-${call.name}`,
source: `${module.schema?.name}-${verb.value.value?.name}`,
target: `${call.module}-${call.name}`,
style: { stroke: 'rgb(251 113 133)' },
animated: true,
})
call.name
call.module
}),
)

y += 50
})
x += 300
})
useEffect(() => {
const { nodes, edges } = layoutNodes(schema)
setNodes(nodes)
setEdges(edges)
}, [schema, setEdges, setNodes])

return (
<div style={{ width: '100vw', height: '90vh' }}>
<ReactFlow nodes={nodes} edges={edges} fitView>
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
fitView
>
<Controls />
<MiniMap />
</ReactFlow>
Expand Down
9 changes: 9 additions & 0 deletions console/src/features/graph/GroupNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function GroupNode({ data }) {
return (
<>
<div className="h-full bg-indigo-800 rounded-md">
<div className="flex justify-center text-xs text-gray-100 pt-2">{data.title}</div>
</div>
</>
)
}
27 changes: 27 additions & 0 deletions console/src/features/graph/VerbNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Handle, Position } from 'reactflow'

export function VerbNode({ data }) {
return (
<>
<Handle
type="target"
position={Position.Top}
style={{ border: 0 }}
className="bg-indigo-600"
isConnectable={true}
/>

<div className="grid h-full w-full bg-indigo-600 rounded-md">
<div className="place-self-center text-xs text-gray-100">{data.title}</div>
</div>

<Handle
type="source"
position={Position.Bottom}
style={{ border: 0 }}
className="bg-indigo-600"
isConnectable={true}
/>
</>
)
}
64 changes: 64 additions & 0 deletions console/src/features/graph/create-layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Edge, Node } from 'reactflow'
import { PullSchemaResponse } from '../../protos/xyz/block/ftl/v1/ftl_pb'
import { MetadataCalls } from '../../protos/xyz/block/ftl/v1/schema/schema_pb'

const groupWidth = 200

export function layoutNodes(schema: PullSchemaResponse[]) {
let x = 0
const nodes: Node[] = []
const edges: Edge[] = []
schema.forEach(module => {
const verbs = module.schema?.decls.filter(decl => decl.value.case === 'verb')
nodes.push({
id: module.schema?.name ?? '',
position: { x: x, y: 0 },
data: { title: module.schema?.name },
type: 'groupNode',
style: {
width: groupWidth,
height: (verbs?.length ?? 1) * 50 + 50,
zIndex: -1,
},
})
let y = 40
module.schema?.decls
.filter(decl => decl.value.case === 'verb')
.forEach(verb => {
const calls = verb?.value.value?.metadata
.filter(meta => meta.value.case === 'calls')
.map(meta => meta.value.value as MetadataCalls)

nodes.push({
id: `${module.schema?.name}-${verb.value.value?.name}`,
position: { x: 20, y: y },
connectable: false,
data: { title: verb.value.value?.name },
type: 'verbNode',
parentNode: module.schema?.name,
style: {
width: groupWidth - 40,
height: 40,
},
})

calls?.map(call =>
call.calls.forEach(call => {
edges.push({
id: `${module.schema?.name}-${verb.value.value?.name}-${call.module}-${call.name}`,
source: `${module.schema?.name}-${verb.value.value?.name}`,
target: `${call.module}-${call.name}`,
style: { stroke: 'rgb(251 113 133)' },
animated: true,
})
call.name
call.module
}),
)

y += 50
})
x += 300
})
return { nodes, edges }
}

0 comments on commit c75c0cc

Please sign in to comment.