|
|
|
@ -1,4 +1,4 @@ |
|
|
|
import { useState, useEffect, useCallback } from 'react'; |
|
|
|
import { useState, useEffect } from 'react'; |
|
|
|
import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle } from '@/components/ui/drawer'; |
|
|
|
import ReactFlow, { |
|
|
|
Node, |
|
|
|
@ -13,23 +13,7 @@ import ReactFlow, { |
|
|
|
} from 'reactflow'; |
|
|
|
import { testcaseService, TestCaseFlowDetail } from '@/services/testcaseService'; |
|
|
|
import 'reactflow/dist/style.css'; |
|
|
|
import { |
|
|
|
Play, |
|
|
|
Square, |
|
|
|
GitBranch, |
|
|
|
Smartphone, |
|
|
|
Wifi, |
|
|
|
WifiOff, |
|
|
|
Phone, |
|
|
|
PhoneCall, |
|
|
|
PhoneOff, |
|
|
|
Network, |
|
|
|
Activity, |
|
|
|
Signal, |
|
|
|
SignalHigh, |
|
|
|
SignalLow, |
|
|
|
Settings |
|
|
|
} from 'lucide-react'; |
|
|
|
import { Settings } from 'lucide-react'; |
|
|
|
|
|
|
|
interface TestCaseDetailDrawerProps { |
|
|
|
testCaseId: string | null; |
|
|
|
@ -37,281 +21,45 @@ interface TestCaseDetailDrawerProps { |
|
|
|
onOpenChange: (open: boolean) => void; |
|
|
|
} |
|
|
|
|
|
|
|
// 自定义节点组件 - 与 ReactFlowDesigner 完全一致
|
|
|
|
// 简化的自定义节点组件
|
|
|
|
const TestStepNode = ({ data, selected }: { data: any; selected?: boolean }) => { |
|
|
|
console.log('TestStepNode 接收到的数据:', data); |
|
|
|
console.log('TestStepNode selected:', selected); |
|
|
|
|
|
|
|
const getIconComponent = (iconName: string) => { |
|
|
|
// 根据图标名称返回对应的图标组件
|
|
|
|
switch (iconName) { |
|
|
|
case 'play-circle': return <Play className="h-4 w-4" />; |
|
|
|
case 'stop-circle': return <Square className="h-4 w-4" />; |
|
|
|
case 'git-branch': return <GitBranch className="h-4 w-4" />; |
|
|
|
case 'settings': return <Settings className="h-4 w-4" />; |
|
|
|
case 'smartphone': return <Smartphone className="h-4 w-4" />; |
|
|
|
case 'wifi': return <Wifi className="h-4 w-4" />; |
|
|
|
case 'wifi-off': return <WifiOff className="h-4 w-4" />; |
|
|
|
case 'phone': return <Phone className="h-4 w-4" />; |
|
|
|
case 'phone-call': return <PhoneCall className="h-4 w-4" />; |
|
|
|
case 'phone-off': return <PhoneOff className="h-4 w-4" />; |
|
|
|
case 'network': return <Network className="h-4 w-4" />; |
|
|
|
case 'activity': return <Activity className="h-4 w-4" />; |
|
|
|
case 'signal': return <Signal className="h-4 w-4" />; |
|
|
|
case 'signal-high': return <SignalHigh className="h-4 w-4" />; |
|
|
|
case 'signal-low': return <SignalLow className="h-4 w-4" />; |
|
|
|
default: return <Settings className="h-4 w-4" />; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const getNodeStyle = (stepType: number) => { |
|
|
|
switch (stepType) { |
|
|
|
case 1: // 开始步骤 - 圆形
|
|
|
|
return { |
|
|
|
shape: 'rounded-full', |
|
|
|
bgColor: 'bg-blue-50 dark:bg-blue-900/30', |
|
|
|
textColor: 'text-blue-600 dark:text-blue-400', |
|
|
|
borderColor: 'border-blue-200 dark:border-blue-600/50', |
|
|
|
hoverBorderColor: 'hover:border-blue-300 dark:hover:border-blue-500' |
|
|
|
}; |
|
|
|
case 2: // 结束步骤 - 圆形
|
|
|
|
return { |
|
|
|
shape: 'rounded-full', |
|
|
|
bgColor: 'bg-red-50 dark:bg-red-900/30', |
|
|
|
textColor: 'text-red-600 dark:text-red-400', |
|
|
|
borderColor: 'border-red-200 dark:border-red-600/50', |
|
|
|
hoverBorderColor: 'hover:border-red-300 dark:hover:border-red-500' |
|
|
|
}; |
|
|
|
case 3: // 处理步骤 - 矩形
|
|
|
|
return { |
|
|
|
shape: 'rounded-md', |
|
|
|
bgColor: 'bg-green-50 dark:bg-green-900/30', |
|
|
|
textColor: 'text-green-600 dark:text-green-400', |
|
|
|
borderColor: 'border-green-200 dark:border-green-600/50', |
|
|
|
hoverBorderColor: 'hover:border-green-300 dark:hover:border-green-500' |
|
|
|
}; |
|
|
|
case 4: // 判断步骤 - 菱形
|
|
|
|
return { |
|
|
|
shape: 'transform rotate-45', |
|
|
|
bgColor: 'bg-purple-50 dark:bg-purple-900/30', |
|
|
|
textColor: 'text-purple-600 dark:text-purple-400', |
|
|
|
borderColor: 'border-purple-200 dark:border-purple-600/50', |
|
|
|
hoverBorderColor: 'hover:border-purple-300 dark:hover:border-purple-500' |
|
|
|
}; |
|
|
|
default: |
|
|
|
return { |
|
|
|
shape: 'rounded-md', |
|
|
|
bgColor: 'bg-gray-50 dark:bg-gray-800', |
|
|
|
textColor: 'text-gray-600 dark:text-gray-400', |
|
|
|
borderColor: 'border-gray-200 dark:border-gray-700', |
|
|
|
hoverBorderColor: 'hover:border-gray-300 dark:hover:border-gray-600' |
|
|
|
}; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const getIconBgColor = (iconName: string) => { |
|
|
|
// 设备相关图标 - 蓝色
|
|
|
|
const deviceIcons = ['smartphone', 'phone', 'phone-call', 'phone-off', 'wifi', 'wifi-off', 'signal', 'signal-high', 'signal-low']; |
|
|
|
// 网络相关图标 - 绿色
|
|
|
|
const networkIcons = ['network', 'activity']; |
|
|
|
// 控制相关图标 - 橙色
|
|
|
|
const controlIcons = ['play-circle', 'stop-circle']; |
|
|
|
// 配置相关图标 - 紫色
|
|
|
|
const configIcons = ['settings', 'git-branch']; |
|
|
|
|
|
|
|
if (deviceIcons.includes(iconName)) { |
|
|
|
return 'bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400'; |
|
|
|
} else if (networkIcons.includes(iconName)) { |
|
|
|
return 'bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400'; |
|
|
|
} else if (controlIcons.includes(iconName)) { |
|
|
|
return 'bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400'; |
|
|
|
} else if (configIcons.includes(iconName)) { |
|
|
|
return 'bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400'; |
|
|
|
case 1: return { bgColor: 'bg-blue-50', borderColor: 'border-blue-200' }; |
|
|
|
case 2: return { bgColor: 'bg-red-50', borderColor: 'border-red-200' }; |
|
|
|
case 3: return { bgColor: 'bg-green-50', borderColor: 'border-green-200' }; |
|
|
|
case 4: return { bgColor: 'bg-purple-50', borderColor: 'border-purple-200' }; |
|
|
|
default: return { bgColor: 'bg-gray-50', borderColor: 'border-gray-200' }; |
|
|
|
} |
|
|
|
|
|
|
|
return 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400'; |
|
|
|
}; |
|
|
|
|
|
|
|
const nodeStyle = getNodeStyle(data.stepType); |
|
|
|
|
|
|
|
return ( |
|
|
|
<div className={`group relative transition-all duration-200`}> |
|
|
|
{/* 开始和结束步骤使用圆形 */} |
|
|
|
{(data.stepType === 1 || data.stepType === 2) && ( |
|
|
|
<div |
|
|
|
className={`px-2 py-1 ${nodeStyle.shape} ${nodeStyle.bgColor} border ${nodeStyle.borderColor} ${ |
|
|
|
selected ? 'ring-2 ring-blue-500' : '' |
|
|
|
}`}
|
|
|
|
> |
|
|
|
<div className="flex items-center space-x-1"> |
|
|
|
<div className={`flex-shrink-0 w-3 h-3 rounded-lg ${getIconBgColor(data.icon || 'settings')} flex items-center justify-center`}> |
|
|
|
{getIconComponent(data.icon || 'settings')} |
|
|
|
</div> |
|
|
|
<div className="flex-1 min-w-0"> |
|
|
|
<div className="font-medium text-sm text-gray-900 dark:text-gray-100 break-words"> |
|
|
|
{data.stepName} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
<div className={`px-3 py-2 rounded-md border ${nodeStyle.bgColor} ${nodeStyle.borderColor} ${selected ? 'ring-2 ring-blue-500' : ''}`}> |
|
|
|
<div className="flex items-center space-x-2"> |
|
|
|
<Settings className="h-4 w-4 text-gray-600" /> |
|
|
|
<span className="text-sm font-medium text-gray-900">{data.stepName}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
{/* 处理步骤使用矩形 */} |
|
|
|
{data.stepType === 3 && ( |
|
|
|
<div |
|
|
|
className={`px-2 py-1 ${nodeStyle.shape} ${nodeStyle.bgColor} border ${nodeStyle.borderColor} ${ |
|
|
|
selected ? 'ring-2 ring-blue-500' : '' |
|
|
|
}`}
|
|
|
|
> |
|
|
|
<div className="flex items-center space-x-1"> |
|
|
|
<div className={`flex-shrink-0 w-3 h-3 rounded-lg ${getIconBgColor(data.icon || 'settings')} flex items-center justify-center`}> |
|
|
|
{getIconComponent(data.icon || 'settings')} |
|
|
|
</div> |
|
|
|
<div className="flex-1 min-w-0"> |
|
|
|
<div className="font-medium text-sm text-gray-900 dark:text-gray-100 break-words"> |
|
|
|
{data.stepName} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
|
|
|
|
{/* 判断步骤使用菱形 */} |
|
|
|
{data.stepType === 4 && ( |
|
|
|
<div |
|
|
|
className={`px-2 py-1 ${nodeStyle.shape} ${nodeStyle.bgColor} border ${nodeStyle.borderColor} ${ |
|
|
|
selected ? 'ring-2 ring-blue-500' : '' |
|
|
|
}`}
|
|
|
|
> |
|
|
|
<div className="flex items-center space-x-1"> |
|
|
|
<div className={`flex-shrink-0 w-3 h-3 rounded-lg ${getIconBgColor(data.icon || 'settings')} flex items-center justify-center`}> |
|
|
|
{getIconComponent(data.icon || 'settings')} |
|
|
|
</div> |
|
|
|
<div className="flex-1 min-w-0"> |
|
|
|
<div className="font-medium text-sm text-gray-900 dark:text-gray-100 break-words"> |
|
|
|
{data.stepName} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
|
|
|
|
{/* 连接点 - 根据节点类型显示不同的连接点 */} |
|
|
|
{/* 开始节点 (type=1) - 只有输出连接点 */} |
|
|
|
{data.stepType === 1 && ( |
|
|
|
<> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Right} |
|
|
|
id="right" |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full hover:bg-green-600" |
|
|
|
style={{ right: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Bottom} |
|
|
|
id="bottom" |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full hover:bg-green-600" |
|
|
|
style={{ bottom: -6 }} |
|
|
|
/> |
|
|
|
</> |
|
|
|
)} |
|
|
|
|
|
|
|
{/* 结束节点 (type=2) - 只有输入连接点 */} |
|
|
|
{data.stepType === 2 && ( |
|
|
|
<> |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Top} |
|
|
|
id="top" |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full hover:bg-blue-600" |
|
|
|
style={{ top: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Left} |
|
|
|
id="left" |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full hover:bg-blue-600" |
|
|
|
style={{ left: -6 }} |
|
|
|
/> |
|
|
|
</> |
|
|
|
)} |
|
|
|
|
|
|
|
{/* 处理节点 (type=3) - 有输入和输出连接点 */} |
|
|
|
{data.stepType === 3 && ( |
|
|
|
<> |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Top} |
|
|
|
id="top" |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full hover:bg-blue-600" |
|
|
|
style={{ top: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Right} |
|
|
|
id="right" |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full hover:bg-green-600" |
|
|
|
style={{ right: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Bottom} |
|
|
|
id="bottom" |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full hover:bg-green-600" |
|
|
|
style={{ bottom: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Left} |
|
|
|
id="left" |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full hover:bg-blue-600" |
|
|
|
style={{ left: -6 }} |
|
|
|
/> |
|
|
|
</> |
|
|
|
)} |
|
|
|
|
|
|
|
{/* 判断节点 (type=4) - 有输入和输出连接点 */} |
|
|
|
{data.stepType === 4 && ( |
|
|
|
<> |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Top} |
|
|
|
id="top" |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full hover:bg-blue-600" |
|
|
|
style={{ top: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Right} |
|
|
|
id="right" |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full hover:bg-green-600" |
|
|
|
style={{ right: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Bottom} |
|
|
|
id="bottom" |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full hover:bg-green-600" |
|
|
|
style={{ bottom: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Left} |
|
|
|
id="left" |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full hover:bg-blue-600" |
|
|
|
style={{ left: -6 }} |
|
|
|
/> |
|
|
|
</> |
|
|
|
)} |
|
|
|
{/* 连接点 */} |
|
|
|
<Handle |
|
|
|
type="target" |
|
|
|
position={Position.Top} |
|
|
|
className="w-3 h-3 bg-blue-500 border-2 border-white rounded-full" |
|
|
|
style={{ top: -6 }} |
|
|
|
/> |
|
|
|
<Handle |
|
|
|
type="source" |
|
|
|
position={Position.Bottom} |
|
|
|
className="w-3 h-3 bg-green-500 border-2 border-white rounded-full" |
|
|
|
style={{ bottom: -6 }} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
// 节点类型定义
|
|
|
|
const nodeTypes = { |
|
|
|
testStep: TestStepNode, |
|
|
|
}; |
|
|
|
const nodeTypes = { testStep: TestStepNode }; |
|
|
|
|
|
|
|
function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseDetailDrawerProps) { |
|
|
|
const [selectedTestCase, setSelectedTestCase] = useState<TestCaseFlowDetail | null>(null); |
|
|
|
@ -325,7 +73,6 @@ function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseD |
|
|
|
if (open && testCaseId) { |
|
|
|
loadTestCaseDetail(testCaseId); |
|
|
|
} else { |
|
|
|
// 关闭抽屉时清理状态
|
|
|
|
setSelectedTestCase(null); |
|
|
|
setError(null); |
|
|
|
setNodes([]); |
|
|
|
@ -340,76 +87,40 @@ function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseD |
|
|
|
const result = await testcaseService.getTestCaseFlowById(id); |
|
|
|
if (result.isSuccess && result.data) { |
|
|
|
setSelectedTestCase(result.data.testCaseFlow); |
|
|
|
// 转换节点和连线为ReactFlow格式
|
|
|
|
const flowData = getReactFlowData(result.data.testCaseFlow); |
|
|
|
setNodes(flowData.nodes); |
|
|
|
setEdges(flowData.edges); |
|
|
|
// 延迟执行 fitView,确保节点已渲染
|
|
|
|
setTimeout(() => { |
|
|
|
fitView({ padding: 0.1 }); |
|
|
|
}, 100); |
|
|
|
setTimeout(() => fitView({ padding: 0.1 }), 100); |
|
|
|
} else { |
|
|
|
setError('加载测试用例详情失败'); |
|
|
|
console.error('加载测试用例详情失败:', result.errorMessages); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
setError('加载测试用例详情出错'); |
|
|
|
console.error('加载测试用例详情出错:', error); |
|
|
|
} finally { |
|
|
|
setFlowLoading(false); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 转换节点和连线为ReactFlow格式
|
|
|
|
const getReactFlowData = (testCase: TestCaseFlowDetail) => { |
|
|
|
console.log('原始节点数据:', testCase.nodes); |
|
|
|
console.log('原始连线数据:', testCase.edges); |
|
|
|
|
|
|
|
const flowNodes: Node[] = testCase.nodes.map(node => { |
|
|
|
console.log('处理节点:', node); |
|
|
|
console.log('节点数据:', node.data); |
|
|
|
console.log('节点位置:', node.position); |
|
|
|
|
|
|
|
// 检查数据字段是否存在,如果不存在则使用默认值
|
|
|
|
const nodeData = { |
|
|
|
const flowNodes: Node[] = testCase.nodes.map(node => ({ |
|
|
|
id: node.id, |
|
|
|
type: 'testStep', |
|
|
|
position: node.position, |
|
|
|
data: { |
|
|
|
stepId: node.data?.stepId || node.id, |
|
|
|
stepName: node.data?.stepName || 'Unknown', |
|
|
|
stepType: node.data?.stepType || 3, |
|
|
|
stepTypeName: node.data?.stepTypeName || '处理步骤', |
|
|
|
description: node.data?.description || '', |
|
|
|
icon: node.data?.icon || 'settings' |
|
|
|
}; |
|
|
|
|
|
|
|
console.log('处理后的节点数据:', nodeData); |
|
|
|
|
|
|
|
return { |
|
|
|
id: node.id, |
|
|
|
type: 'testStep', // 使用自定义节点类型
|
|
|
|
position: node.position, |
|
|
|
data: nodeData, |
|
|
|
width: node.width || 150, |
|
|
|
height: node.height || 50, |
|
|
|
selected: node.selected || false, |
|
|
|
positionAbsolute: node.positionAbsolute, |
|
|
|
dragging: node.dragging || false |
|
|
|
}; |
|
|
|
}); |
|
|
|
} |
|
|
|
})); |
|
|
|
|
|
|
|
const flowEdges: Edge[] = testCase.edges.map(edge => { |
|
|
|
console.log('处理连线:', edge); |
|
|
|
|
|
|
|
return { |
|
|
|
id: edge.id, |
|
|
|
source: edge.source, |
|
|
|
sourceHandle: edge.sourceHandle || null, |
|
|
|
target: edge.target, |
|
|
|
targetHandle: edge.targetHandle || null, |
|
|
|
type: edge.type || 'smoothstep', |
|
|
|
animated: edge.animated || false, |
|
|
|
style: edge.style || { stroke: '#333', strokeWidth: 2 }, |
|
|
|
data: edge.data || {} |
|
|
|
}; |
|
|
|
}); |
|
|
|
const flowEdges: Edge[] = testCase.edges.map(edge => ({ |
|
|
|
id: edge.id, |
|
|
|
source: edge.source, |
|
|
|
target: edge.target, |
|
|
|
type: 'smoothstep', |
|
|
|
style: { stroke: '#3b82f6', strokeWidth: 2 } |
|
|
|
})); |
|
|
|
|
|
|
|
return { nodes: flowNodes, edges: flowEdges }; |
|
|
|
}; |
|
|
|
@ -434,11 +145,6 @@ function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseD |
|
|
|
) : error ? ( |
|
|
|
<div className="flex items-center justify-center h-full"> |
|
|
|
<div className="text-center"> |
|
|
|
<div className="text-red-500 mb-2"> |
|
|
|
<svg className="w-8 h-8 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" /> |
|
|
|
</svg> |
|
|
|
</div> |
|
|
|
<p className="text-gray-600">{error}</p> |
|
|
|
<button |
|
|
|
onClick={() => testCaseId && loadTestCaseDetail(testCaseId)} |
|
|
|
@ -449,7 +155,7 @@ function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseD |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) : selectedTestCase ? ( |
|
|
|
<div className="h-full border rounded-lg"> |
|
|
|
<div className="h-full border rounded-lg bg-gray-50"> |
|
|
|
<ReactFlow |
|
|
|
nodes={nodes} |
|
|
|
edges={edges} |
|
|
|
@ -457,7 +163,7 @@ function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseD |
|
|
|
fitView |
|
|
|
className="bg-gray-50" |
|
|
|
defaultViewport={{ x: 0, y: 0, zoom: 1.5 }} |
|
|
|
minZoom={1} |
|
|
|
minZoom={0.5} |
|
|
|
maxZoom={2} |
|
|
|
style={{ width: '100%', height: '100%' }} |
|
|
|
snapToGrid={true} |
|
|
|
@ -465,6 +171,11 @@ function TestCaseDetailDrawerInner({ testCaseId, open, onOpenChange }: TestCaseD |
|
|
|
> |
|
|
|
<Controls /> |
|
|
|
<Background /> |
|
|
|
<MiniMap |
|
|
|
nodeColor="#3b82f6" |
|
|
|
maskColor="rgba(0, 0, 0, 0.1)" |
|
|
|
style={{ width: 150, height: 100 }} |
|
|
|
/> |
|
|
|
</ReactFlow> |
|
|
|
</div> |
|
|
|
) : ( |
|
|
|
|