TraceStudio-dev/docs/web1.0/FEATURE_UPDATE_v0.2.0.md

498 lines
12 KiB
Markdown
Raw Normal View History

2026-01-07 19:34:45 +08:00
# 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<string, TreeNode>` 构建高效树索引
- 递归渲染函数 `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 (
<div style={{ marginLeft: depth > 0 ? 12 : 0 }}>
{/* 目录标题 */}
{/* 叶子节点 */}
{/* 递归渲染子目录 */}
</div>
)
}
```
### 右键菜单状态管理
```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 && (
<div style={{
borderTop: '1px solid rgba(148,163,184,0.15)',
background: 'rgba(0,0,0,0.2)',
maxHeight: 300,
overflow: 'auto'
}}>
{/* 预览内容 */}
</div>
)}
```
---
## 📝 使用指南
### 配置多层级分类
**步骤 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 中添加预览按钮
<button onClick={async () => {
const result = await fetchPreview(nodeId)
updateNodeData(nodeId, {
preview: {
type: 'table',
columns: result.columns,
data: result.data.slice(0, 100) // 限制数据量
}
})
}}>
👁️ 预览数据
</button>
```
---
## 🧪 测试建议
### 测试 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