diff --git a/frontend/packages/core/src/pages/playground/components/ModelCardNode.tsx b/frontend/packages/core/src/pages/playground/components/ModelCardNode.tsx index e5fd28c0..ae84a13f 100644 --- a/frontend/packages/core/src/pages/playground/components/ModelCardNode.tsx +++ b/frontend/packages/core/src/pages/playground/components/ModelCardNode.tsx @@ -1,12 +1,13 @@ import { Icon } from '@iconify/react' import { Handle, Position } from '@xyflow/react' -import React from 'react' +import React, { useCallback, useState } from 'react' import { ModelCardStatus } from './types' interface ModelCardData { title: string status: ModelCardStatus defaultModel: string + onDragStart?: () => void } type ModelCardNodeData = ModelCardData & { @@ -15,11 +16,49 @@ type ModelCardNodeData = ModelCardData & { } export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) => { + const [isHovered, setIsHovered] = useState(false) const { title, status, defaultModel } = data + + const onDragHandleMouseDown = useCallback((event: React.MouseEvent) => { + // Prevent event propagation to allow dragging + event.stopPropagation() + + // Create a new drag event + const dragEvent = new MouseEvent('mousedown', { + clientX: event.clientX, + clientY: event.clientY, + bubbles: true + }) + // Find the node element and dispatch the event + const nodeElement = event.currentTarget.closest('.react-flow__node') + if (nodeElement) { + // Use the global `document` object if it exists + nodeElement.dispatchEvent(dragEvent) + } + }, []) + return ( -
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > + + {/* Drag Handle - Only visible on hover */} +
+
+ +
+
+
@@ -29,7 +68,15 @@ export const ModelCardNode: React.FC<{ data: ModelCardNodeData }> = ({ data }) = className={`text-xl ${status === 'success' ? 'text-green-500' : 'text-red-500'}`} />
- + + {/* Action buttons */} +
+ console.log('Settings', data.id)} + /> +
{defaultModel}
diff --git a/frontend/packages/core/src/pages/playground/index.tsx b/frontend/packages/core/src/pages/playground/index.tsx index 7f3dad25..81e4547e 100644 --- a/frontend/packages/core/src/pages/playground/index.tsx +++ b/frontend/packages/core/src/pages/playground/index.tsx @@ -213,6 +213,66 @@ const Playground = () => { const onConnect = useCallback((params: any) => setEdges((eds) => addEdge(params, eds)), [setEdges]) + const onNodeDrag = useCallback( + (_: any, node: any) => { + // Update positions of connected nodes during drag + setNodes((nds) => { + return nds.map((n) => { + if (n.type === 'keyStatus' && n.id === `${node.id}-keys`) { + return { + ...n, + position: { + x: 750, + y: node.position.y + } + } + } + return n + }) + }) + }, + [setNodes] + ) + + const onNodeDragStop = useCallback( + (_: any, node: any) => { + // Reorder nodes based on vertical position + setNodes((nds) => { + const modelNodes = nds.filter((n) => n.type === 'modelCard') + const sortedNodes = [...modelNodes].sort((a, b) => a.position.y - b.position.y) + + return nds.map((n) => { + if (n.type === 'modelCard') { + const index = sortedNodes.findIndex((sn) => sn.id === n.id) + return { + ...n, + position: { + x: 400, + y: 50 + index * 120 + } + } + } + if (n.type === 'keyStatus') { + const modelId = n.id.replace('-keys', '') + const modelNode = sortedNodes.find((mn) => mn.id === modelId) + if (modelNode) { + const index = sortedNodes.findIndex((sn) => sn.id === modelId) + return { + ...n, + position: { + x: 750, + y: 50 + index * 120 + } + } + } + } + return n + }) + }) + }, + [setNodes] + ) + return (
{ onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} + onNodeDrag={onNodeDrag} + onNodeDragStop={onNodeDragStop} nodeTypes={nodeTypes} defaultEdgeOptions={{ type: 'step', @@ -228,7 +290,7 @@ const Playground = () => { animated: true }} fitView - nodesDraggable={false} + nodesDraggable={true} nodesConnectable={false} zoomOnScroll={false} zoomOnPinch={false}