Animate workflow editor side panels
This commit is contained in:
@@ -165,7 +165,11 @@ export function WorkflowEditor({
|
|||||||
const [flowInstance, setFlowInstance] = useState<ReactFlowInstance<WorkflowFlowNode, WorkflowFlowEdge> | null>(null)
|
const [flowInstance, setFlowInstance] = useState<ReactFlowInstance<WorkflowFlowNode, WorkflowFlowEdge> | null>(null)
|
||||||
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null)
|
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null)
|
||||||
const [nodeLibraryCollapsed, setNodeLibraryCollapsed] = useState(false)
|
const [nodeLibraryCollapsed, setNodeLibraryCollapsed] = useState(false)
|
||||||
|
const [nodeLibraryRendered, setNodeLibraryRendered] = useState(true)
|
||||||
|
const [nodeLibraryVisible, setNodeLibraryVisible] = useState(true)
|
||||||
const [pendingNodeDrag, setPendingNodeDrag] = useState<PendingNodeDrag | null>(null)
|
const [pendingNodeDrag, setPendingNodeDrag] = useState<PendingNodeDrag | null>(null)
|
||||||
|
const [propertyPanelNode, setPropertyPanelNode] = useState<WorkflowFlowNode | null>(null)
|
||||||
|
const [propertyPanelVisible, setPropertyPanelVisible] = useState(false)
|
||||||
const canvasRef = useRef<HTMLElement | null>(null)
|
const canvasRef = useRef<HTMLElement | null>(null)
|
||||||
const pendingNodeDragRef = useRef<PendingNodeDrag | null>(null)
|
const pendingNodeDragRef = useRef<PendingNodeDrag | null>(null)
|
||||||
const suppressNextClickRef = useRef(false)
|
const suppressNextClickRef = useRef(false)
|
||||||
@@ -182,13 +186,13 @@ export function WorkflowEditor({
|
|||||||
() => enrichNodesForRender(nodes, nodeSpecs),
|
() => enrichNodesForRender(nodes, nodeSpecs),
|
||||||
[nodes, nodeSpecs]
|
[nodes, nodeSpecs]
|
||||||
)
|
)
|
||||||
const selectedNodeSpec = useMemo(
|
const propertyPanelNodeSpec = useMemo(
|
||||||
() => getNodeSpec(nodeSpecs, selectedNode?.data.nodeType ?? ""),
|
() => getNodeSpec(nodeSpecs, propertyPanelNode?.data.nodeType ?? ""),
|
||||||
[nodeSpecs, selectedNode]
|
[nodeSpecs, propertyPanelNode]
|
||||||
)
|
)
|
||||||
const availableVariables = useMemo(
|
const propertyPanelAvailableVariables = useMemo(
|
||||||
() => (selectedNode ? getAvailableVariables(draft, selectedNode.id, nodeSpecs) : []),
|
() => (propertyPanelNode ? getAvailableVariables(draft, propertyPanelNode.id, nodeSpecs) : []),
|
||||||
[draft, nodeSpecs, selectedNode]
|
[draft, nodeSpecs, propertyPanelNode]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -199,6 +203,30 @@ export function WorkflowEditor({
|
|||||||
onDefinitionChange(toApiDefinition(draft) as AIWorkflowDefinition)
|
onDefinitionChange(toApiDefinition(draft) as AIWorkflowDefinition)
|
||||||
}, [draft, onDefinitionChange])
|
}, [draft, onDefinitionChange])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!nodeLibraryCollapsed) {
|
||||||
|
setNodeLibraryRendered(true)
|
||||||
|
window.setTimeout(() => setNodeLibraryVisible(true), 0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setNodeLibraryVisible(false)
|
||||||
|
const timer = window.setTimeout(() => setNodeLibraryRendered(false), 220)
|
||||||
|
return () => window.clearTimeout(timer)
|
||||||
|
}, [nodeLibraryCollapsed])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedNode) {
|
||||||
|
setPropertyPanelNode(selectedNode)
|
||||||
|
window.setTimeout(() => setPropertyPanelVisible(true), 0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setPropertyPanelVisible(false)
|
||||||
|
const timer = window.setTimeout(() => setPropertyPanelNode(null), 220)
|
||||||
|
return () => window.clearTimeout(timer)
|
||||||
|
}, [selectedNode])
|
||||||
|
|
||||||
const onConnect = useCallback(
|
const onConnect = useCallback(
|
||||||
(connection: Connection) => {
|
(connection: Connection) => {
|
||||||
if (!connection.source || !connection.target) {
|
if (!connection.source || !connection.target) {
|
||||||
@@ -338,10 +366,17 @@ export function WorkflowEditor({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ResizablePanelGroup orientation="horizontal" className="h-full min-h-0">
|
<ResizablePanelGroup orientation="horizontal" className="h-full min-h-0">
|
||||||
{!nodeLibraryCollapsed ? (
|
{nodeLibraryRendered ? (
|
||||||
<>
|
<>
|
||||||
<ResizablePanel defaultSize="18%" minSize="12%" maxSize="34%" className="min-h-0">
|
<ResizablePanel defaultSize="18%" minSize="12%" maxSize="34%" className="min-h-0">
|
||||||
<aside className="h-full min-h-0 bg-muted/20">
|
<aside
|
||||||
|
className={[
|
||||||
|
"h-full min-h-0 bg-muted/20 transition-all duration-200 ease-out",
|
||||||
|
nodeLibraryVisible
|
||||||
|
? "translate-x-0 opacity-100"
|
||||||
|
: "-translate-x-3 opacity-0",
|
||||||
|
].join(" ")}
|
||||||
|
>
|
||||||
<ScrollArea className="h-full min-h-0">
|
<ScrollArea className="h-full min-h-0">
|
||||||
<div className="p-3">
|
<div className="p-3">
|
||||||
<div className="mb-3 flex items-center justify-between gap-2">
|
<div className="mb-3 flex items-center justify-between gap-2">
|
||||||
@@ -445,13 +480,20 @@ export function WorkflowEditor({
|
|||||||
<MiniMap pannable zoomable />
|
<MiniMap pannable zoomable />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<WorkflowValidationBadge errors={validation.errors} valid={validation.valid} />
|
<WorkflowValidationBadge errors={validation.errors} valid={validation.valid} />
|
||||||
{selectedNode ? (
|
{propertyPanelNode ? (
|
||||||
<aside className="absolute top-3 right-3 z-30 h-[calc(100%-1.5rem)] w-[min(380px,calc(100%-1.5rem))] overflow-hidden rounded-md border bg-background shadow-lg">
|
<aside
|
||||||
|
className={[
|
||||||
|
"absolute top-3 right-3 z-30 h-[calc(100%-1.5rem)] w-[min(380px,calc(100%-1.5rem))] overflow-hidden rounded-md border bg-background shadow-lg transition-all duration-200 ease-out",
|
||||||
|
propertyPanelVisible
|
||||||
|
? "translate-x-0 scale-100 opacity-100"
|
||||||
|
: "translate-x-3 scale-[0.98] opacity-0",
|
||||||
|
].join(" ")}
|
||||||
|
>
|
||||||
<ScrollArea className="h-full min-h-0">
|
<ScrollArea className="h-full min-h-0">
|
||||||
<NodeConfigPanel
|
<NodeConfigPanel
|
||||||
node={selectedNode}
|
node={propertyPanelNode}
|
||||||
nodeSpec={selectedNodeSpec}
|
nodeSpec={propertyPanelNodeSpec}
|
||||||
availableVariables={availableVariables}
|
availableVariables={propertyPanelAvailableVariables}
|
||||||
onChange={updateNodeData}
|
onChange={updateNodeData}
|
||||||
/>
|
/>
|
||||||
{!validation.valid ? (
|
{!validation.valid ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user