From c10da2062c706116bbc3a7c5dec3cd92adb5b142 Mon Sep 17 00:00:00 2001 From: mlogclub Date: Mon, 22 Jun 2026 22:49:41 +0800 Subject: [PATCH] Add collapsible node library panel --- .../_components/workflow-editor.tsx | 129 +++++++++++++----- 1 file changed, 96 insertions(+), 33 deletions(-) diff --git a/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx b/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx index 46b5ee7..f4c8d73 100644 --- a/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx +++ b/web/app/dashboard/ai-workflows/_components/workflow-editor.tsx @@ -20,10 +20,17 @@ import { type NodeProps, type ReactFlowInstance, } from "@xyflow/react" -import { AlertCircleIcon, CheckCircle2Icon } from "lucide-react" +import { + AlertCircleIcon, + CheckCircle2Icon, + PanelLeftCloseIcon, + PanelLeftOpenIcon, +} from "lucide-react" import { useCallback, useEffect, useMemo, useRef, useState } from "react" +import type { PanelImperativeHandle } from "react-resizable-panels" import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" import { ScrollArea } from "@/components/ui/scroll-area" import { Popover, @@ -158,7 +165,9 @@ export function WorkflowEditor({ ) const [flowInstance, setFlowInstance] = useState | null>(null) const [selectedNodeId, setSelectedNodeId] = useState(null) + const [nodeLibraryCollapsed, setNodeLibraryCollapsed] = useState(false) const [pendingNodeDrag, setPendingNodeDrag] = useState(null) + const nodeLibraryPanelRef = useRef(null) const canvasRef = useRef(null) const pendingNodeDragRef = useRef(null) const suppressNextClickRef = useRef(false) @@ -247,6 +256,23 @@ export function WorkflowEditor({ }) } + const toggleNodeLibrary = () => { + const panel = nodeLibraryPanelRef.current + if (!panel) { + setNodeLibraryCollapsed((current) => !current) + return + } + + if (panel.isCollapsed()) { + panel.expand() + setNodeLibraryCollapsed(false) + return + } + + panel.collapse() + setNodeLibraryCollapsed(true) + } + const dropNodeOnCanvas = useCallback( (spec: AIWorkflowNodeSpec, x: number, y: number) => { if (!flowInstance || !canvasRef.current) { @@ -331,42 +357,67 @@ export function WorkflowEditor({ return ( - - + + + )} @@ -378,6 +429,18 @@ export function WorkflowEditor({ pendingNodeDrag?.active ? "ring-2 ring-primary/30" : "", ].join(" ")} > + {nodeLibraryCollapsed ? ( + + ) : null}