Files
OpenFlare/docs/superpowers/specs/2026-07-19-waf-editor-node-label-drag-design.md
T
ryan 4166cc9861 docs(waf): 规格 — 规则编辑器节点命名与拖放添加
确认仅前端消费已有 label,节点库改为拖到画布落点,不做备注。
2026-07-19 10:57:28 +08:00

123 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WAF 规则编辑器:节点命名与拖放添加
日期:2026-07-19
范围:`/waf/rules/editor` 前端交互与类型对齐
状态:已确认,待实现
## 背景
当前 WAF 规则流图编辑器有两处体验问题:
1. 画布节点只显示类型固定名称(如「IP 匹配」),无法自定义命名,复杂规则难以区分。
2. 节点库通过点击添加,新节点落在固定偏移位置(`x: 240, y: 140 + n*24`),无法在目标位置放置。
后端 `RuleNode` 已具备 `label` 字段(`json:"label,omitempty"`),前端类型与 UI 尚未消费。
## 目标
1. 用户可为可编辑节点自定义**显示名称**(`label`),画布与属性栏一致展示。
2. 从节点库**拖放到画布**,在鼠标松手处生成节点;**取消点击固定位置添加**。
3. 不做备注字段、不做拖到连线中插入、不改后端 schema / `schema_version`。
## 非目标
- 节点备注 / note / remark
- 拖到边自动拆边插入
- 系统节点 `start` / `allow` 可改名
- 后端校验、编译或运行时语义变更
- 侧栏式节点库大改版
## 数据模型
### 后端(已有,不改)
```go
type RuleNode struct {
ID string `json:"id"`
Type RuleNodeType `json:"type"`
Label string `json:"label,omitempty"`
Position RulePosition `json:"position"`
Config json.RawMessage `json:"config"`
}
```
`label` 为空则 omit;现有大小限制与图校验保持不变。
### 前端
`WAFRuleNode` 各变体增加可选字段:
```ts
label?: string;
```
- 保存时:空字符串不写入或写 `undefined`,与 `omitempty` 对齐。
- 显示时:`label?.trim() || typeDefaultLabel`。
- 新建节点:不设 `label`(显示类型默认名)。
- `start` / `allow`:属性栏仍为「系统节点无需配置」,不提供改名输入;若历史数据带 `label`,画布仍可按上述规则显示,但不提供编辑入口。
## UI 行为
### 画布节点(`rule-node.tsx`)
| 区域 | 行为 |
|------|------|
| 主标题 | `label` 去空白后非空则用 `label`,否则用类型默认中文名 |
| 副标题 | 仍显示 `rule.id`(mono 小字) |
| 图标 / handle | 不变 |
### 属性栏(`node-properties.tsx`)
对非系统节点(`ip_match` | `geo_match` | `pow` | `block`),在类型专属配置**之上**增加:
- 字段标签:`显示名称`
- 控件:`Input`,受控绑定 `node.label ?? ''`
- 变更:`onChange({ ...node, label: value })`;清空时写 `''` 或去掉字段(实现任选其一,保存序列化时不落空 label)
系统节点保持现有文案。
### 节点库与添加(`node-library.tsx` + `rule-flow-canvas.tsx`)
1. 节点库项设为 `draggable`,`dragstart` 写入节点类型(如 `application/openflare-waf-node` 或等价自定义 MIME + `text/plain` 回退)。
2. 移除 `onClick` → `onAdd(type)` 的点击添加路径。
3. React Flow 画布容器:
- `onDragOver`:`preventDefault`,允许 drop
- `onDrop`:读取类型 → `screenToFlowPosition({ x: clientX, y: clientY })` → 创建节点(默认 config 逻辑与现有 `addNode` 相同,但 `position` 为落点)
4. 落点后选中新节点,清除边选中(与现有一致)。
5. 工具栏仍在画布左上角浮动区域,仅改为拖源,不改为侧栏。
## 实现落点(文件)
| 文件 | 变更 |
|------|------|
| `frontend/lib/services/openflare/types.ts` | `WAFRuleNode` 增加 `label?` |
| `frontend/app/(main)/waf/rules/editor/components/rule-node.tsx` | 标题显示逻辑 |
| `frontend/app/(main)/waf/rules/editor/components/node-properties.tsx` | 「显示名称」字段 |
| `frontend/app/(main)/waf/rules/editor/components/node-library.tsx` | 拖放源,去掉点击添加 |
| `frontend/app/(main)/waf/rules/editor/components/rule-flow-canvas.tsx` | drop 落点创建;`addNode` 接受 position |
| 相关 `*.test.tsx` / `*.test.ts` | label 展示/编辑、拖放 payload、落点 |
可选:若序列化路径有显式字段白名单,确认 `label` 会进入保存 payload。
## 错误与边界
- 未知 / 非法 drag type:忽略 drop。
- 落在画布外:不创建。
- 超长 `label`:依赖后端既有图大小/字段限制;前端可不设硬上限,或与常见 Input 一致(如 64–128 字符)——实现阶段若后端有明确上限则对齐。
- Undo/脏检查:`label` 与 `position` 变更走现有 `onGraphChange` 路径,不新增独立历史机制。
## 测试要点
1. 有 `label` 的节点主标题为自定义名;无 `label` 为类型默认名。
2. 属性栏修改 `label` 后 graph 节点更新且画布同步。
3. 节点库项可拖;drop 后节点 `position` 接近 flow 坐标(允许测试中 mock `screenToFlowPosition`)。
4. 不再通过点击节点库按钮创建节点(无 click-add 行为)。
5. 系统节点属性栏仍无「显示名称」。
## 验收标准
- [ ] 可编辑节点可命名,保存再打开名称仍在。
- [ ] 画布显示自定义名(空则类型名)。
- [ ] 仅拖放添加,松手位置为节点位置。
- [ ] 无后端 API / schema 变更;`make code-check` 与相关 vitest 通过。