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}