# TraceStudio 功能更新文档 ## 版本记录 - **v0.2.0** - 2026-01-07 - ✨ 多层级树状分类系统 - 🖱️ 增强的右键菜单系统 - 👁️ 节点预览数据持久化 --- ## 📋 更新内容 ### 1. ✨ 多层级树状分类系统 #### 功能描述 节点面板支持类似文件树的多层级分类结构,方便组织大量算子。 **核心特性**: - 📁 支持最多 **3 级树状目录** - 🏷️ 超出 3 级的分类作为 `subCategory` 标签显示 - 🔄 递归展开/折叠,自动统计子节点数量 - 🔍 搜索时自动展开匹配节点 **示例结构**: ``` 📥 Loader (2) ▸ CSV (1) ▸ Local (1) 📥 CSV 数据加载器 📁 File (超出3级) ▸ Trace (1) 📥 UTrace 文件加载器 ⚙️ Transform (4) ▸ Filter (2) ⚙️ 行过滤器 ⚙️ 时间范围过滤 ▸ Select (1) ⚙️ 列选择器 ▸ Aggregate (1) ⚙️ 数据聚合 ``` **后端配置示例** (`server/main.py`): ```python "CSVLoader": { "function": "Loader", "category": "Loader/CSV/Local/File", # 4级分类 # 显示效果: # - Loader > CSV > Local 作为树结构 # - "File" 作为 subCategory 标签 } "FilterRows": { "function": "Transform", "category": "Transform/Filter", # 2级分类,正常显示 } ``` **技术实现**: - 文件:[web/src/components/NodePalette.tsx](../web/src/components/NodePalette.tsx) - 使用 `Map` 构建高效树索引 - 递归渲染函数 `renderTreeNode()` 处理嵌套结构 - 自动过滤空分类节点 --- ### 2. 🖱️ 增强的右键菜单系统 #### 功能描述 全面的右键菜单支持,涵盖画布、节点、连线的所有常用操作。 **菜单类型**: | 右键对象 | 菜单项 | 功能描述 | 快捷键 | |---------|-------|---------|--------| | **画布** | 💾 保存工作流 | 保存到 localStorage | - | | **画布** | 📥 导入工作流 | 从 JSON 文件导入 | - | | **画布** | 📤 导出工作流 | 导出为 JSON 文件 | - | | **画布** | 🗑️ 清空画布 | 清空所有节点和连线 | - | | **节点** | 📋 复制节点 | 复制节点到偏移位置 | - | | **节点** | ✂️ 断开所有连线 | 删除该节点的所有连线 | - | | **节点** | 🗑️ 删除节点 | 删除节点及其连线 | Delete | | **连线** | ✂️ 删除此连线 | 删除当前选中的连线 | - | | **连线** | 🗑️ 删除此接口所有连线 | 删除同一 target handle 的所有连线 | - | **交互优化**: - ✅ 鼠标左键拖拽时自动关闭右键菜单 - ✅ 点击画布自动关闭菜单 - ✅ 危险操作(清空画布)有确认提示 **技术实现**: - 文件:[web/src/components/Workspace.tsx](../web/src/components/Workspace.tsx) - React Flow 事件:`onEdgeContextMenu`, `onNodeContextMenu`, `onPaneContextMenu` - 监听拖拽开始和鼠标按下事件自动关闭菜单 **使用示例**: ```typescript // 删除同一接口的所有连线(用于清理多输入节点) case 'deleteAll': { const edge = edges.find(e => e.id === contextMenu.edgeId) if (edge) { setEdges((eds) => eds.filter((e) => !(e.target === edge.target && e.targetHandle === edge.targetHandle) )) } break } ``` --- ### 3. 👁️ 节点预览数据持久化 #### 功能描述 节点执行或预览后,预览数据会持久化显示在节点下方,无需重复加载。 **支持的预览类型**: 1. **📊 表格预览**(CSV 数据) - 显示前 5 行数据 - 显示前 4 列(超出部分显示省略) - 自动统计总行数 - 表头加粗显示 2. **🖼️ 图表预览**(图像) - 显示图表图像 - 自适应缩放(最大高度 200px) - 支持常见图片格式 **数据结构**: ```typescript interface NodeData { preview?: { type: 'table' | 'image' data: any // 表格数组或图片URL columns?: string[] // 表格列名 } } ``` **表格预览示例**: ```json { "preview": { "type": "table", "columns": ["ID", "Name", "Value", "Timestamp"], "data": [ { "ID": 1, "Name": "Item A", "Value": 100, "Timestamp": "2026-01-07" }, { "ID": 2, "Name": "Item B", "Value": 200, "Timestamp": "2026-01-07" } ] } } ``` **图表预览示例**: ```json { "preview": { "type": "image", "data": "data:image/png;base64,iVBORw0KG..." } } ``` **技术实现**: - 文件:[web/src/components/nodes/UniversalNode.tsx](../web/src/components/nodes/UniversalNode.tsx) - 预览区域使用滚动容器(最大高度 300px) - 表格使用优化的 HTML table 结构 - 图片使用 `object-fit: contain` 自适应显示 **样式特点**: - 🎨 深色主题适配 - 📏 固定宽度防止节点过宽 - 🔤 文本超出自动省略 - 📊 数据行数统计标签 --- ## 🛠️ 技术细节 ### 树状分类算法 **核心函数**: ```typescript const MAX_TREE_DEPTH = 3 // 最大树层级 function buildTree(): TreeNode { const root: TreeNode = { name: 'root', items: [], children: new Map(), expanded: true } for (const [nodeType, meta] of Object.entries(plugins)) { const categoryPath = meta.category || 'Other' const parts = categoryPath.split('/') // 限制树深度 const treeParts = parts.slice(0, MAX_TREE_DEPTH) const subCategory = parts.length > MAX_TREE_DEPTH ? parts.slice(MAX_TREE_DEPTH).join('/') : undefined // 逐级构建树 let currentNode = root for (let i = 0; i < treeParts.length; i++) { const part = treeParts[i] if (i === treeParts.length - 1) { // 叶子节点 currentNode.items.push({ type: nodeType, meta, subCategory }) } else { // 中间节点 if (!currentNode.children.has(part)) { currentNode.children.set(part, { name: part, items: [], children: new Map(), expanded: expandedPaths.has(buildPath(treeParts.slice(0, i + 1))) }) } currentNode = currentNode.children.get(part)! } } } return root } ``` **递归渲染**: ```typescript function renderTreeNode(node: TreeNode, depth: number, path: string[]): React.ReactNode { const currentPath = buildPath(path) const isExpanded = expandedPaths.has(currentPath) || search !== '' // 过滤 + 统计 const filteredItems = node.items.filter(/* ... */) const totalCount = countNodes(node) return (
0 ? 12 : 0 }}> {/* 目录标题 */} {/* 叶子节点 */} {/* 递归渲染子目录 */}
) } ``` ### 右键菜单状态管理 ```typescript const [contextMenu, setContextMenu] = useState<{ x: number y: number type: 'pane' | 'node' | 'edge' nodeId?: string edgeId?: string } | null>(null) // 自动关闭菜单的场景 const onPaneMouseDown = useCallback(() => { if (contextMenu) setContextMenu(null) }, [contextMenu]) const onNodeDragStart = useCallback(() => { if (contextMenu) setContextMenu(null) }, [contextMenu]) ``` ### 预览数据渲染 **表格优化**: - 只显示前 5 行(避免节点过长) - 只显示前 4 列(避免节点过宽) - 单元格内容超出自动省略 **响应式设计**: ```typescript const hasPreview = data.meta?.supports_preview && data.preview {hasPreview && (
{/* 预览内容 */}
)} ``` --- ## 📝 使用指南 ### 配置多层级分类 **步骤 1:修改后端配置** (`server/main.py`) ```python "MyNode": { "function": "Transform", # 节点功能 "category": "Transform/Filter/Advanced/Custom", # 4级分类 # 显示效果: # Transform > Filter > Advanced (树结构) # + "Custom" 标签 (subCategory) } ``` **步骤 2:启动服务** ```bash # 后端 conda activate tracestudio python -m uvicorn server.main:app --reload # 前端 cd web npm run dev ``` **步骤 3:查看效果** - 节点面板会自动构建树状结构 - 点击目录展开/折叠 - 使用搜索框快速定位 ### 使用右键菜单 **场景 1:批量删除连线** 1. 创建多个节点连接到同一个 Aggregator 2. 右键点击任意一条连线 3. 选择 "🗑️ 删除此接口所有连线" 4. 所有连接到该接口的连线都被删除 **场景 2:复制节点** 1. 右键点击节点 2. 选择 "📋 复制节点" 3. 新节点会出现在偏移位置(+50px) **场景 3:导出工作流** 1. 右键点击画布空白处 2. 选择 "📤 导出工作流" 3. 保存为 JSON 文件 ### 添加预览数据 **方法 1:执行节点后自动保存** ```typescript // 执行完成后更新节点数据 updateNodeData(nodeId, { preview: { type: 'table', columns: ['ID', 'Name', 'Value'], data: [ { ID: 1, Name: 'Item A', Value: 100 }, { ID: 2, Name: 'Item B', Value: 200 } ] } }) ``` **方法 2:预览按钮触发** ```typescript // Inspector 中添加预览按钮 ``` --- ## 🧪 测试建议 ### 测试 1:多层级分类 ```python # server/main.py "TestNode": { "category": "A/B/C/D/E/F" # 6级分类 } ``` 预期效果:显示 `A > B > C > TestNode + 标签 "📁 D/E/F"` ### 测试 2:右键菜单自动关闭 1. 右键打开菜单 2. 按住鼠标左键拖拽节点 3. 菜单应该自动关闭 ### 测试 3:预览数据持久化 1. 给节点添加预览数据 2. 拖动节点到其他位置 3. 预览应该一直显示 4. 刷新页面后预览应该恢复(如果已持久化到 localStorage) --- ## 🔧 配置选项 ### 树层级限制 ```typescript // web/src/components/NodePalette.tsx const MAX_TREE_DEPTH = 3 // 修改此值调整最大层级 ``` ### 预览数据限制 ```typescript // web/src/components/nodes/UniversalNode.tsx maxHeight: 300, // 预览区域最大高度 data.slice(0, 5) // 显示前5行 columns.slice(0, 4) // 显示前4列 ``` ### 右键菜单样式 ```typescript // web/src/components/Workspace.tsx background: 'rgba(10,22,40,0.95)', backdropFilter: 'blur(12px)', border: '1px solid rgba(59,130,246,0.2)', ``` --- ## 🐛 已知问题 1. **预览数据过大** - 问题:大数据集可能导致节点过大 - 解决方案:限制预览行数(当前5行) 2. **树结构过深** - 问题:超过10级的分类可能显示混乱 - 解决方案:设置合理的 MAX_TREE_DEPTH(推荐3-4级) 3. **右键菜单位置** - 问题:靠近边缘时菜单可能超出屏幕 - 待优化:自动调整菜单位置 --- ## 📊 性能优化 1. **树结构构建** - 使用 `Map` 数据结构,查找复杂度 O(1) - 递归深度限制防止栈溢出 2. **预览数据渲染** - 虚拟滚动(未来优化) - 懒加载大图片 3. **菜单交互** - 使用 `useCallback` 防止不必要的重渲染 - 事件委托优化性能 --- ## 📚 相关文件 | 文件 | 描述 | 主要改动 | |------|------|---------| | `web/src/components/NodePalette.tsx` | 节点面板 | ✅ 树状分类 | | `web/src/components/Workspace.tsx` | 画布组件 | ✅ 右键菜单 + 自动关闭 | | `web/src/components/nodes/UniversalNode.tsx` | 通用节点 | ✅ 预览数据显示 | | `server/main.py` | 后端API | ⚠️ 需配置 category | --- ## 🚀 未来计划 - [ ] 拖拽排序节点面板分类 - [ ] 预览数据支持更多格式(JSON、Markdown) - [ ] 右键菜单支持自定义操作 - [ ] 预览数据的缓存管理 - [ ] 节点分组(Group)功能 - [ ] 快捷键支持(Ctrl+C/V 复制粘贴) --- ## 📞 反馈与支持 如有问题或建议,请通过以下方式反馈: - 提交 Issue - Pull Request - 联系开发团队 **最后更新**:2026-01-07 **版本**:v0.2.0