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

5.1 KiB
Raw Blame History

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 可改名
  • 后端校验、编译或运行时语义变更
  • 侧栏式节点库大改版

数据模型

后端(已有,不改)

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 各变体增加可选字段:

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 通过。