Skip to content

Commit

Permalink
feat(ui): Add vertical tree + horizontal layout + canvas controls
Browse files Browse the repository at this point in the history
  • Loading branch information
daryllimyt committed Jun 16, 2024
1 parent 25be946 commit e3cb820
Showing 1 changed file with 73 additions and 2 deletions.
75 changes: 73 additions & 2 deletions frontend/src/components/workspace/canvas/canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ReactFlow, {
Edge,
MarkerType,
NodeChange,
Panel,
ReactFlowInstance,
useEdgesState,
useNodesState,
Expand All @@ -20,14 +21,17 @@ import "reactflow/dist/style.css"

import { useParams } from "next/navigation"
import { useWorkflow } from "@/providers/workflow"
import Dagre, { type GraphLabel, type Label } from "@dagrejs/dagre"
import { MoveHorizontalIcon, MoveVerticalIcon } from "lucide-react"

import { Workflow } from "@/types/schemas"
import {
createAction,
deleteAction,
fetchWorkflow,
updateWorkflowGraphObject,
} from "@/lib/workflow"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { useToast } from "@/components/ui/use-toast"
import triggerNode, {
TriggerNodeData,
Expand All @@ -39,6 +43,42 @@ import udfNode, {
UDFNodeType,
} from "@/components/workspace/canvas/udf-node"

const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}))

/**
* Taken from https://reactflow.dev/learn/layouting/layouting#dagre
* @param nodes
* @param edges
* @param options
* @returns
*/
const getLayoutedElements = (
nodes: Node[],
edges: Edge[],
options: GraphLabel
) => {
g.setGraph({ ...options, ranksep: 75, nodesep: 100 })

edges.forEach((edge) => g.setEdge(edge.source, edge.target))
nodes.forEach((node) => g.setNode(node.id, node as Label))

Dagre.layout(g)
console.log(nodes)

return {
nodes: nodes.map((node) => {
const position = g.node(node.id)
// We are shifting the dagre node position (anchor=center center) to the top left
// so it matches the React Flow node anchor point (top left).
const x = position.x - node.width! / 2
const y = position.y - node.height! / 2

return { ...node, position: { x, y } }
}),
edges,
}
}

export type NodeTypename = "udf" | "trigger"
export type NodeType = UDFNodeType | TriggerNodeType
export type NodeData = UDFNodeData | TriggerNodeData
Expand Down Expand Up @@ -294,6 +334,15 @@ export function WorkflowCanvas() {
[nodes, setNodes]
)

const onLayout = useCallback(
(direction: "TB" | "LR") => {
const layouted = getLayoutedElements(nodes, edges, { rankdir: direction })
setNodes([...layouted.nodes])
setEdges([...layouted.edges])
},
[nodes, edges]
)

// Saving react flow instance state
useEffect(() => {
if (workflowId && reactFlowInstance) {
Expand Down Expand Up @@ -332,7 +381,29 @@ export function WorkflowCanvas() {
deleteKeyCode={["Backspace", "Delete"]}
>
<Background />
<Controls />
<Controls className="rounded-sm" />
<Panel position="bottom-right" className="flex items-center gap-1">
<Badge
variant="outline"
className="select-none bg-background text-xs font-extralight hover:cursor-default"
>
Layout
</Badge>
<Button
variant="outline"
className="m-0 size-6 p-0 text-xs"
onClick={() => onLayout("TB")}
>
<MoveVerticalIcon className="size-3" strokeWidth={2} />
</Button>
<Button
variant="outline"
className="m-0 size-6 p-0 text-xs"
onClick={() => onLayout("LR")}
>
<MoveHorizontalIcon className="size-3" strokeWidth={2} />
</Button>
</Panel>
</ReactFlow>
</div>
)
Expand Down

0 comments on commit e3cb820

Please sign in to comment.