714 lines
18 KiB
Markdown
714 lines
18 KiB
Markdown
|
|
# 🔄 节点功能与目录分离重构
|
|||
|
|
|
|||
|
|
## 📋 需求分析
|
|||
|
|
|
|||
|
|
### 原有问题
|
|||
|
|
`category` 字段承担双重职责:
|
|||
|
|
1. 表示节点功能(Loader/Transform/Visualizer)→ 用于节点颜色、图标、Handle 显示
|
|||
|
|
2. 表示目录分类 → 用于 NodePalette 树状展示
|
|||
|
|
|
|||
|
|
**冲突**:无法实现 "Loader/CSV"、"Transform/Filter" 这样的二级目录分类
|
|||
|
|
|
|||
|
|
### 解决方案
|
|||
|
|
将 `category` 和节点功能分离:
|
|||
|
|
- **`function`**: 节点功能(Loader/Transform/Visualizer)
|
|||
|
|
- **`category`**: 树状目录路径(Loader/CSV, Transform/Filter)
|
|||
|
|
|
|||
|
|
同时弃用前端的 `node.type` 属性,统一使用 `function` 字段。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 后端修改(main.py)
|
|||
|
|
|
|||
|
|
### 所有节点添加 `function` 字段
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# 修改前
|
|||
|
|
"CSVLoader": {
|
|||
|
|
"display_name": "CSV 数据加载器",
|
|||
|
|
"category": "Loader", # 既表示功能又表示目录
|
|||
|
|
"node_logic": "standard",
|
|||
|
|
# ...
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 修改后
|
|||
|
|
"CSVLoader": {
|
|||
|
|
"display_name": "CSV 数据加载器",
|
|||
|
|
"function": "Loader", # ✅ 节点功能:加载器
|
|||
|
|
"category": "Loader/CSV", # ✅ 树状目录:加载器/CSV
|
|||
|
|
"node_logic": "standard",
|
|||
|
|
# ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 元数据结构完整示例
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
{
|
|||
|
|
"CSVLoader": {
|
|||
|
|
"display_name": "CSV 数据加载器",
|
|||
|
|
"function": "Loader", # 节点功能
|
|||
|
|
"category": "Loader/CSV", # 树状目录
|
|||
|
|
"node_logic": "standard", # 节点逻辑
|
|||
|
|
"supports_preview": True,
|
|||
|
|
"inputs": [],
|
|||
|
|
"outputs": [{"name": "table", "type": "DataTable"}],
|
|||
|
|
"param_schema": {...}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"UTraceLoader": {
|
|||
|
|
"display_name": "UTrace 文件加载器",
|
|||
|
|
"function": "Loader",
|
|||
|
|
"category": "Loader/Trace", # 二级目录:Trace
|
|||
|
|
# ...
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"FilterRows": {
|
|||
|
|
"display_name": "行过滤器",
|
|||
|
|
"function": "Transform",
|
|||
|
|
"category": "Transform/Filter", # 二级目录:Filter
|
|||
|
|
# ...
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"SelectColumns": {
|
|||
|
|
"display_name": "列选择器",
|
|||
|
|
"function": "Transform",
|
|||
|
|
"category": "Transform/Select", # 二级目录:Select
|
|||
|
|
# ...
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"Aggregator": {
|
|||
|
|
"display_name": "数据聚合",
|
|||
|
|
"function": "Transform",
|
|||
|
|
"category": "Transform/Aggregate",
|
|||
|
|
"node_logic": "aggregate",
|
|||
|
|
"allow_multiple_inputs": True, # ✅ 多输入支持
|
|||
|
|
# ...
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"TimeRangeFilter": {
|
|||
|
|
"display_name": "时间范围过滤",
|
|||
|
|
"function": "Transform",
|
|||
|
|
"category": "Transform/Filter", # 与 FilterRows 共享目录
|
|||
|
|
# ...
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"ChartVisualizer": {
|
|||
|
|
"display_name": "图表可视化",
|
|||
|
|
"function": "Visualizer",
|
|||
|
|
"category": "Visualizer/Chart",
|
|||
|
|
# ...
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
"TableOutput": {
|
|||
|
|
"display_name": "表格输出",
|
|||
|
|
"function": "Visualizer",
|
|||
|
|
"category": "Visualizer/Table",
|
|||
|
|
# ...
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 完整节点清单
|
|||
|
|
|
|||
|
|
| 节点类型 | function | category | node_logic | allow_multiple_inputs |
|
|||
|
|
|----------|----------|----------|------------|----------------------|
|
|||
|
|
| CSVLoader | Loader | Loader/CSV | standard | false |
|
|||
|
|
| UTraceLoader | Loader | Loader/Trace | standard | false |
|
|||
|
|
| FilterRows | Transform | Transform/Filter | standard | false |
|
|||
|
|
| SelectColumns | Transform | Transform/Select | standard | false |
|
|||
|
|
| Aggregator | Transform | Transform/Aggregate | aggregate | ✅ true |
|
|||
|
|
| TimeRangeFilter | Transform | Transform/Filter | standard | false |
|
|||
|
|
| ChartVisualizer | Visualizer | Visualizer/Chart | standard | false |
|
|||
|
|
| TableOutput | Visualizer | Visualizer/Table | standard | false |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ✅ 前端修改
|
|||
|
|
|
|||
|
|
### 1. UniversalNode.tsx
|
|||
|
|
|
|||
|
|
#### 接口重构
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
interface UniversalNodeProps {
|
|||
|
|
data: {
|
|||
|
|
meta?: {
|
|||
|
|
category?: 'Loader' | 'Transform' | 'Visualizer' // ❌ 混用
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
interface UniversalNodeProps {
|
|||
|
|
data: {
|
|||
|
|
meta?: {
|
|||
|
|
function?: 'Loader' | 'Transform' | 'Visualizer' // ✅ 节点功能
|
|||
|
|
category?: string // ✅ 树状目录路径(如 "Loader/CSV")
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 常量重命名
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
const CATEGORY_COLORS: Record<string, string> = {
|
|||
|
|
Loader: '#3b82f6',
|
|||
|
|
Transform: '#8b5cf6',
|
|||
|
|
Visualizer: '#22c55e',
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
const FUNCTION_COLORS: Record<string, string> = {
|
|||
|
|
Loader: '#3b82f6',
|
|||
|
|
Transform: '#8b5cf6',
|
|||
|
|
Visualizer: '#22c55e',
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 组件实现
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
const category = data.meta?.category || 'Transform'
|
|||
|
|
const headerColor = CATEGORY_COLORS[category] || '#6b7280'
|
|||
|
|
const showInput = category === 'Transform' || category === 'Visualizer'
|
|||
|
|
const showOutput = category === 'Loader' || category === 'Transform'
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
const nodeFunction = data.meta?.function || 'Transform'
|
|||
|
|
const headerColor = FUNCTION_COLORS[nodeFunction] || '#6b7280'
|
|||
|
|
const showInput = nodeFunction === 'Transform' || nodeFunction === 'Visualizer'
|
|||
|
|
const showOutput = nodeFunction === 'Loader' || nodeFunction === 'Transform'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Header 显示
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
<div>{categoryIcon[category] || '🔹'}</div>
|
|||
|
|
<div>{category}</div>
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
<div>{functionIcon[nodeFunction] || '🔹'}</div>
|
|||
|
|
<div>{nodeFunction}</div> {/* 显示 Loader/Transform/Visualizer */}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. Inspector.tsx
|
|||
|
|
|
|||
|
|
#### 图标映射
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
<span>
|
|||
|
|
{node.type === 'csv' ? '📂' :
|
|||
|
|
node.type === 'transform' ? '⚙️' :
|
|||
|
|
node.type === 'output' ? '📊' : '📦'}
|
|||
|
|
</span>
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
<span>
|
|||
|
|
{node.data?.meta?.function === 'Loader' ? '📥' :
|
|||
|
|
node.data?.meta?.function === 'Transform' ? '⚙️' :
|
|||
|
|
node.data?.meta?.function === 'Visualizer' ? '📊' : '📦'}
|
|||
|
|
</span>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 标题显示
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
<h3>{node.type.toUpperCase()}</h3> {/* CSV, TRANSFORM, OUTPUT */}
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
<h3>{node.data?.meta?.display_name || 'Node'}</h3> {/* CSV 数据加载器 */}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 系统属性
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
<div>
|
|||
|
|
<label>节点类型</label>
|
|||
|
|
<input value={node.type} disabled /> {/* csv, transform, output */}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
<div>
|
|||
|
|
<label>节点功能</label>
|
|||
|
|
<input value={node.data?.meta?.function || 'Unknown'} disabled /> {/* Loader */}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label>目录分类</label>
|
|||
|
|
<input value={node.data?.meta?.category} disabled /> {/* Loader/CSV */}
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. Workspace.tsx
|
|||
|
|
|
|||
|
|
#### MiniMap 颜色映射
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
<MiniMap
|
|||
|
|
nodeColor={(node) => {
|
|||
|
|
const category = node.data?.meta?.category
|
|||
|
|
if (category === 'Loader') return '#3b82f6'
|
|||
|
|
if (category === 'Transform') return '#8b5cf6'
|
|||
|
|
if (category === 'Visualizer') return '#22c55e'
|
|||
|
|
return '#64748b'
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
<MiniMap
|
|||
|
|
nodeColor={(node) => {
|
|||
|
|
const nodeFunction = node.data?.meta?.function
|
|||
|
|
if (nodeFunction === 'Loader') return '#3b82f6'
|
|||
|
|
if (nodeFunction === 'Transform') return '#8b5cf6'
|
|||
|
|
if (nodeFunction === 'Visualizer') return '#22c55e'
|
|||
|
|
return '#64748b'
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. NodePalette.tsx
|
|||
|
|
|
|||
|
|
#### 接口更新
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
interface PluginMeta {
|
|||
|
|
display_name?: string
|
|||
|
|
category?: string // 混用
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
interface PluginMeta {
|
|||
|
|
display_name?: string
|
|||
|
|
function?: string // 节点功能
|
|||
|
|
category?: string // 树状目录
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 二级目录解析
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
const groups: Record<string, { key: string; items: Array<...> }> = {}
|
|||
|
|
for (const [k, v] of Object.entries(plugins)) {
|
|||
|
|
const cat = (v.category || 'Other').split('/')[0]
|
|||
|
|
if (!groups[cat]) groups[cat] = { key: cat, items: [] }
|
|||
|
|
groups[cat].items.push({ type: k, meta: v })
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
const groups: Record<string, {
|
|||
|
|
key: string;
|
|||
|
|
items: Array<{ type: string; meta: PluginMeta; subCategory?: string }>
|
|||
|
|
}> = {}
|
|||
|
|
|
|||
|
|
for (const [k, v] of Object.entries(plugins)) {
|
|||
|
|
const categoryPath = v.category || 'Other'
|
|||
|
|
const [mainCat, subCat] = categoryPath.split('/')
|
|||
|
|
|
|||
|
|
if (!groups[mainCat]) {
|
|||
|
|
groups[mainCat] = { key: mainCat, items: [] }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
groups[mainCat].items.push({
|
|||
|
|
type: k,
|
|||
|
|
meta: v,
|
|||
|
|
subCategory: subCat // 保存二级分类
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 算子卡片显示
|
|||
|
|
```typescript
|
|||
|
|
// 修改前
|
|||
|
|
<div>
|
|||
|
|
<span>
|
|||
|
|
{group.key === 'Loaders' ? '📂' :
|
|||
|
|
group.key === 'Transforms' ? '⚙️' : '📦'}
|
|||
|
|
</span>
|
|||
|
|
<span>{item.meta.display_name}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
// 修改后
|
|||
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|||
|
|
{/* 主行:图标 + 名称 */}
|
|||
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|||
|
|
<span>
|
|||
|
|
{item.meta.function === 'Loader' ? '📥' :
|
|||
|
|
item.meta.function === 'Transform' ? '⚙️' :
|
|||
|
|
item.meta.function === 'Visualizer' ? '📊' : '📦'}
|
|||
|
|
</span>
|
|||
|
|
<span>{item.meta.display_name}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 二级分类标签 */}
|
|||
|
|
{item.subCategory && (
|
|||
|
|
<div style={{ fontSize: 10, color: 'rgba(255,255,255,0.4)' }}>
|
|||
|
|
{item.subCategory} {/* CSV, Trace, Filter, Select */}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 视觉效果对比
|
|||
|
|
|
|||
|
|
### NodePalette 显示
|
|||
|
|
|
|||
|
|
**修改前**:
|
|||
|
|
```
|
|||
|
|
▸ Loaders (2)
|
|||
|
|
📂 CSV 数据加载器
|
|||
|
|
📂 UTrace 文件加载器
|
|||
|
|
|
|||
|
|
▸ Transforms (4)
|
|||
|
|
⚙️ 行过滤器
|
|||
|
|
⚙️ 列选择器
|
|||
|
|
⚙️ 数据聚合
|
|||
|
|
⚙️ 时间范围过滤
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后**:
|
|||
|
|
```
|
|||
|
|
▸ Loader (2)
|
|||
|
|
📥 CSV 数据加载器
|
|||
|
|
CSV ← 二级分类标签
|
|||
|
|
📥 UTrace 文件加载器
|
|||
|
|
Trace ← 二级分类标签
|
|||
|
|
|
|||
|
|
▸ Transform (4)
|
|||
|
|
⚙️ 行过滤器
|
|||
|
|
Filter ← 二级分类标签
|
|||
|
|
⚙️ 列选择器
|
|||
|
|
Select
|
|||
|
|
⚙️ 数据聚合
|
|||
|
|
Aggregate
|
|||
|
|
⚙️ 时间范围过滤
|
|||
|
|
Filter ← 相同二级目录
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Inspector 面板
|
|||
|
|
|
|||
|
|
**修改前**:
|
|||
|
|
```
|
|||
|
|
┌─ 系统信息 ────────┐
|
|||
|
|
│ 节点 ID: n_xxx │
|
|||
|
|
│ 节点类型: csv │ ← 前端类型(混乱)
|
|||
|
|
│ 分类: Loader │ ← 混用
|
|||
|
|
└──────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后**:
|
|||
|
|
```
|
|||
|
|
┌─ 系统信息 ────────────┐
|
|||
|
|
│ 节点 ID: n_xxx │
|
|||
|
|
│ 节点功能: Loader │ ← 清晰的功能标识
|
|||
|
|
│ 目录分类: Loader/CSV │ ← 完整的目录路径
|
|||
|
|
└──────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 节点本体显示
|
|||
|
|
|
|||
|
|
**修改前**:
|
|||
|
|
```
|
|||
|
|
┌─ CSV 数据加载器 ──┐
|
|||
|
|
│ Loader │ ← 显示 category
|
|||
|
|
│ file_path: ... │
|
|||
|
|
└──────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修改后**:
|
|||
|
|
```
|
|||
|
|
┌─ CSV 数据加载器 ──┐
|
|||
|
|
│ LOADER │ ← 显示 function(功能)
|
|||
|
|
│ file_path: ... │
|
|||
|
|
└──────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 数据流追踪
|
|||
|
|
|
|||
|
|
### 从后端到前端的完整流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1️⃣ 后端定义(main.py)
|
|||
|
|
↓
|
|||
|
|
GET /plugins
|
|||
|
|
↓
|
|||
|
|
{
|
|||
|
|
"CSVLoader": {
|
|||
|
|
"function": "Loader", ← 节点功能
|
|||
|
|
"category": "Loader/CSV" ← 树状目录
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
↓
|
|||
|
|
2️⃣ NodePalette 接收
|
|||
|
|
↓
|
|||
|
|
解析 category: "Loader/CSV"
|
|||
|
|
├─ mainCat: "Loader" ← 一级目录
|
|||
|
|
└─ subCat: "CSV" ← 二级目录
|
|||
|
|
↓
|
|||
|
|
显示:
|
|||
|
|
Loader (2)
|
|||
|
|
📥 CSV 数据加载器
|
|||
|
|
CSV ← subCategory 标签
|
|||
|
|
↓
|
|||
|
|
3️⃣ 拖拽到画布
|
|||
|
|
↓
|
|||
|
|
创建节点:
|
|||
|
|
{
|
|||
|
|
id: "n_xxx",
|
|||
|
|
type: "universal", ← 所有节点统一类型
|
|||
|
|
data: {
|
|||
|
|
meta: {
|
|||
|
|
function: "Loader", ← 用于功能判断
|
|||
|
|
category: "Loader/CSV" ← 用于显示目录
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
↓
|
|||
|
|
4️⃣ UniversalNode 渲染
|
|||
|
|
↓
|
|||
|
|
读取 function: "Loader"
|
|||
|
|
├─ 决定颜色:#3b82f6(蓝色)
|
|||
|
|
├─ 决定图标:📥
|
|||
|
|
├─ 决定 Handle:只显示 Output
|
|||
|
|
└─ 显示文字:LOADER
|
|||
|
|
↓
|
|||
|
|
5️⃣ Inspector 显示
|
|||
|
|
↓
|
|||
|
|
系统信息:
|
|||
|
|
- 节点功能: Loader ← function
|
|||
|
|
- 目录分类: Loader/CSV ← category
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 关键概念对比
|
|||
|
|
|
|||
|
|
### function vs category
|
|||
|
|
|
|||
|
|
| 字段 | 用途 | 值域 | 示例 | 前端使用位置 |
|
|||
|
|
|------|------|------|------|-------------|
|
|||
|
|
| **function** | 节点功能 | Loader, Transform, Visualizer | `"Loader"` | UniversalNode 颜色、图标、Handle 逻辑 |
|
|||
|
|
| **category** | 树状目录 | 任意路径(支持 / 分隔) | `"Loader/CSV"` | NodePalette 分组、Inspector 显示 |
|
|||
|
|
|
|||
|
|
### 节点类型演变
|
|||
|
|
|
|||
|
|
| 阶段 | 前端类型 | 后端类型 | 功能标识 | 目录标识 |
|
|||
|
|
|------|---------|---------|---------|---------|
|
|||
|
|
| **Phase 1** | node.type = 'csv' | N/A | ❌ 混乱 | ❌ 无 |
|
|||
|
|
| **Phase 2** | node.type = 'universal' | meta.category | ⚠️ category 混用 | ⚠️ category 混用 |
|
|||
|
|
| **Phase 3 (现在)** | node.type = 'universal' | meta.function | ✅ function | ✅ category |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🧪 测试验证
|
|||
|
|
|
|||
|
|
### 测试 1:后端 API 验证
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 访问后端
|
|||
|
|
curl http://127.0.0.1:8000/plugins
|
|||
|
|
|
|||
|
|
# 验证响应包含
|
|||
|
|
{
|
|||
|
|
"plugins": {
|
|||
|
|
"CSVLoader": {
|
|||
|
|
"function": "Loader", ✅
|
|||
|
|
"category": "Loader/CSV", ✅
|
|||
|
|
"allow_multiple_inputs": false
|
|||
|
|
},
|
|||
|
|
"Aggregator": {
|
|||
|
|
"function": "Transform",
|
|||
|
|
"category": "Transform/Aggregate",
|
|||
|
|
"allow_multiple_inputs": true ✅
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 测试 2:NodePalette 二级目录
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
操作:打开应用
|
|||
|
|
预期:左侧面板显示
|
|||
|
|
|
|||
|
|
✅ Loader (2)
|
|||
|
|
📥 CSV 数据加载器
|
|||
|
|
CSV ← 二级分类标签
|
|||
|
|
📥 UTrace 文件加载器
|
|||
|
|
Trace
|
|||
|
|
|
|||
|
|
✅ Transform (4)
|
|||
|
|
⚙️ 行过滤器
|
|||
|
|
Filter
|
|||
|
|
⚙️ 列选择器
|
|||
|
|
Select
|
|||
|
|
⚙️ 数据聚合
|
|||
|
|
Aggregate
|
|||
|
|
⚙️ 时间范围过滤
|
|||
|
|
Filter ← 相同目录共享
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 测试 3:节点功能识别
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
操作:拖拽 CSV Loader 到画布
|
|||
|
|
预期:
|
|||
|
|
1. 节点颜色:蓝色(#3b82f6) ✅
|
|||
|
|
2. 节点图标:📥 ✅
|
|||
|
|
3. Handle 显示:只有 Output ✅
|
|||
|
|
4. 节点 Header:显示 "LOADER" ✅
|
|||
|
|
|
|||
|
|
操作:拖拽 FilterRows 到画布
|
|||
|
|
预期:
|
|||
|
|
1. 节点颜色:紫色(#8b5cf6) ✅
|
|||
|
|
2. 节点图标:⚙️ ✅
|
|||
|
|
3. Handle 显示:Input + Output ✅
|
|||
|
|
4. 节点 Header:显示 "TRANSFORM" ✅
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 测试 4:Inspector 显示
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
操作:选中 CSV Loader 节点
|
|||
|
|
预期 Inspector 显示:
|
|||
|
|
|
|||
|
|
┌─ 系统信息 ─────────────┐
|
|||
|
|
│ 节点 ID: n_xxx │ ✅
|
|||
|
|
│ 节点功能: Loader │ ✅ (原来是 node.type)
|
|||
|
|
│ 目录分类: Loader/CSV │ ✅ (新增)
|
|||
|
|
└───────────────────────┘
|
|||
|
|
|
|||
|
|
┌─ 参数配置 ─────────────┐
|
|||
|
|
│ file_path: [输入框] │
|
|||
|
|
│ delimiter: [输入框] │
|
|||
|
|
└───────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 测试 5:MiniMap 颜色
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
操作:拖拽多种节点到画布
|
|||
|
|
预期 MiniMap 显示:
|
|||
|
|
- Loader 节点:蓝色 ✅
|
|||
|
|
- Transform 节点:紫色 ✅
|
|||
|
|
- Visualizer 节点:绿色 ✅
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📁 修改文件清单
|
|||
|
|
|
|||
|
|
### 后端
|
|||
|
|
1. **server/main.py**
|
|||
|
|
- ✅ 所有节点添加 `"function"` 字段
|
|||
|
|
- ✅ 修改 `"category"` 为树状路径(支持 `/` 分隔)
|
|||
|
|
- ✅ Aggregator 添加 `"allow_multiple_inputs": True`
|
|||
|
|
|
|||
|
|
### 前端
|
|||
|
|
2. **web/src/components/nodes/UniversalNode.tsx**
|
|||
|
|
- ✅ `CATEGORY_COLORS` → `FUNCTION_COLORS`
|
|||
|
|
- ✅ `meta.category` → `meta.function`
|
|||
|
|
- ✅ `categoryIcon` → `functionIcon`
|
|||
|
|
- ✅ Header 显示 `nodeFunction` 代替 `category`
|
|||
|
|
|
|||
|
|
3. **web/src/components/Inspector.tsx**
|
|||
|
|
- ✅ 图标映射:`node.type` → `node.data.meta.function`
|
|||
|
|
- ✅ 标题显示:`node.type.toUpperCase()` → `node.data.meta.display_name`
|
|||
|
|
- ✅ 系统属性:删除 `node.type`,添加 `function` 和 `category` 显示
|
|||
|
|
|
|||
|
|
4. **web/src/components/Workspace.tsx**
|
|||
|
|
- ✅ MiniMap 颜色:`meta.category` → `meta.function`
|
|||
|
|
|
|||
|
|
5. **web/src/components/NodePalette.tsx**
|
|||
|
|
- ✅ 接口添加 `function` 字段
|
|||
|
|
- ✅ 二级目录解析:`category.split('/')` → `[mainCat, subCat]`
|
|||
|
|
- ✅ 算子卡片:显示 `function` 图标 + `subCategory` 标签
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎨 设计亮点
|
|||
|
|
|
|||
|
|
### 1. 职责分离
|
|||
|
|
- **function**: 节点功能逻辑(颜色、图标、Handle)
|
|||
|
|
- **category**: UI 组织结构(树状目录、分组)
|
|||
|
|
|
|||
|
|
### 2. 可扩展性
|
|||
|
|
```python
|
|||
|
|
# 轻松添加三级目录
|
|||
|
|
"category": "Transform/Filter/Advanced"
|
|||
|
|
|
|||
|
|
# 前端自动支持
|
|||
|
|
categoryPath.split('/') → ['Transform', 'Filter', 'Advanced']
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 语义化
|
|||
|
|
```typescript
|
|||
|
|
// 修改前(混乱)
|
|||
|
|
if (node.type === 'csv') { ... } // 前端类型
|
|||
|
|
if (meta.category === 'Loader') { ... } // 既是功能又是目录
|
|||
|
|
|
|||
|
|
// 修改后(清晰)
|
|||
|
|
if (meta.function === 'Loader') { ... } // 节点功能
|
|||
|
|
if (meta.category.startsWith('Loader/')) { ... } // 目录位置
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 向后兼容
|
|||
|
|
- 前端 `node.type` 统一为 `'universal'`,不再依赖具体类型
|
|||
|
|
- 所有节点使用相同的 UniversalNode 组件
|
|||
|
|
- 元数据驱动,易于扩展
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🚀 后续增强建议
|
|||
|
|
|
|||
|
|
### 1. 动态树状目录
|
|||
|
|
```typescript
|
|||
|
|
// 支持折叠二级目录
|
|||
|
|
Loader (2)
|
|||
|
|
▸ CSV (1)
|
|||
|
|
- CSV 数据加载器
|
|||
|
|
▸ Trace (1)
|
|||
|
|
- UTrace 文件加载器
|
|||
|
|
|
|||
|
|
Transform (4)
|
|||
|
|
▸ Filter (2)
|
|||
|
|
- 行过滤器
|
|||
|
|
- 时间范围过滤
|
|||
|
|
▸ Select (1)
|
|||
|
|
▸ Aggregate (1)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 功能徽章
|
|||
|
|
```typescript
|
|||
|
|
// 节点卡片显示功能标签
|
|||
|
|
┌─ CSV 数据加载器 ────────┐
|
|||
|
|
│ [Loader] [CSV] [⚡Preview] │
|
|||
|
|
│ file_path: ... │
|
|||
|
|
└─────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 搜索增强
|
|||
|
|
```typescript
|
|||
|
|
// 支持按 function 和 category 过滤
|
|||
|
|
搜索:Loader → 显示所有 Loader 功能节点
|
|||
|
|
搜索:Filter → 显示所有 Filter 目录节点
|
|||
|
|
搜索:Loader/CSV → 显示特定路径节点
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**完成时间**:2026-01-07
|
|||
|
|
**版本**:Function & Category Separation v1.0
|
|||
|
|
**状态**:✅ 重构完成,功能与目录完全分离
|