Uh oh!
There was an error while loading. Please reload this page.
fix(app-shell)!: converge flow node geometry to spec FlowNode.position (#3172) - #3294
Merged
Merged
Conversation
…on` (#3172) The flow designer wrote node geometry as its own `ui: { x, y }` while `@objectstack/spec` has modelled the same object as `FlowNode.position` all along. Since objectstack#4001 the spec's node schema is `.strict()`, so `ui` is an `unrecognized_keys` error: dragging a node made the flow fail live client validation and be rejected on save with a 422. Converging the spelling is therefore a behaviour fix, not a rename. - All three write paths (drag / add-at-point / insert-on-edge) emit `position: { x, y }`. - The canvas migrates on write: `withCanonicalGeometry` lifts a stored `ui` onto `position` and strips the key at the canvas's input boundary, so every patch it emits is `ui`-free — including patches unrelated to geometry. - Reading stays backwards-compatible: `manualPosition()` prefers `position` and falls back to a legacy `ui`, keeping the "x and y both finite" predicate. - The geometry type is derived from the spec by reference (`FlowNodePosition`), the shape-copy in `FlowPreview.tsx` is gone, and `spec-symbol-parity.test.ts` gains a positive parity pin plus a runtime assertion that the spec rejects the retired spelling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 12:56
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
这是什么
按维护者裁决(2026-08-03)与 PM 审计报告,把流程设计器的节点几何收敛到 spec 已声明的
FlowNode.position,退役 objectui 本地拼写ui: {x, y}。改动面全部落在@object-ui/app-shell;packages/spec、objectstack 仓、plugin-designer、types/react/components/fields(#3233 在飞)零改动。它同时是一个行为修复,不只是改名。 spec 17 的
FlowNodeSchema自 objectstack#4001 起是.strict(),ui会产出unrecognized_keys:客户端实时校验飘红、服务端保存 422。也就是说今天在设计器里拖一个节点,这份 flow 就存不进去。审计里这条是静态推导,本 PR 把它跑成了断言(见下「实机验证」)。触点清销(对照审计的 5 文件 ~15 处)
写侧 3 处 —— 一律产出
position,永不写ui:FlowCanvas.tsxpersistPosition(拖拽落点)FlowCanvas.tsxaddNode(带at的新增)FlowCanvas.tsxinsertOnEdge(边上插入)读侧 2 处 ——
position优先、ui仅作遗留回退,保留「x/y 同时有限」判据:flow-canvas-layout.tshasManualPosition(现委托给新的单一读点manualPosition())flow-canvas-layout.ts布局覆盖(positions.set(...),同时去掉了n.ui!.x!那对非空断言)类型 3 处 —— 几何按引用派生自 spec,不再手写形状:
FlowNodeUI→FlowNodePosition = NonNullable< SpecFlowNode['position'] >(import type,仍是零运行时依赖)FlowDesignerNode挂载position?: FlowNodePosition;ui?: LegacyFlowNodeUI保留但标@deprecated只读FlowPreview.tsx:52的形状拷贝消灭,改type FlowNode = FlowDesignerNode(与它早已这么做的 edge 对齐)夹具 / 文档:
flow-canvas-layout.test.ts两条夹具改position,并新增一条同点位的 legacyui夹具(兼容读继续被覆盖)README.md布局段落改写;FlowCanvas.tsx头注释改写minor,按 AGENTS.md「changeset 不声明 major,破坏性语义写正文」)不变量与证明
position—— 三条写路径各一条回归测试。ui-free —— 抬升点选在画布输入边界(FlowCanvas用withCanonicalGeometry(storedNodes)归一后再useMemo),而不是塞进persistPosition。理由:FlowCanvas有 5 条会重发nodes数组的 patch 路径(拖拽、新增、边插入、revise loop、删除),只补写侧会漏掉后两条——它们不写几何,却会把遗留ui原样带回 draft,闸门照样 422。归一在入口,则任何现有或将来的 patch 都从已规范化的数组构造,结构上不可能再发出ui。测试里专门有一条「删除节点也ui-free」钉住这一点。manualPosition()是唯一读点:position优先、ui回退;一条测试把两种拼写各布一次局并比对整张 map 相等。spec-symbol-parity.test.ts新增正向 parity(编译期:与NonNullable< SpecFlowNode['position'] >互等、input 与 parsed 一致、x/y 均必填、半个坐标不可表示;运行期:spec 仍拼作position且拒收ui)。既有的FlowCanvasNode/FlowCanvasEdge反向防撞 pin 原样保留。FlowDesignerNode带[k: string]: unknown,编译器抓不到漏掉的ui读写点,因此收工做了全仓 grep:写形态ui: { x|y|... }在生产代码中零命中(仅剩注释与故意造遗留数据的测试夹具);读形态ui?.x/ui.y零命中,唯一的node.ui读点就是manualPosition()里那条有文档的遗留回退。验证
pnpm exec vitest run三个受影响文件 → 80 passed;app-shell 全量 → 266 files / 2311 passed / 1 skipped。turbo run type-check --filter=@object-ui/app-shell通过(含tsconfig.typetests.json,编译期断言真的被编译);lint 0 errors(新增告警仅_legacy解构丢弃一处,与本包既有_-前缀写法一致)。persistPosition改回写ui→ 2 红;绕过入口归一 → 5 红;删掉 legacy 读回退 → 9 红;抬升时不删ui键 → 10 红;破坏同引用返回 → 1 红;把 spec 拒收断言喂合法节点 → 1 红;把FlowNodePosition改成{ x: number; y?: number }→ typetests 4 处TS2344报红。还原后 80/80 绿。实机验证(浏览器,无后端)
用仓内
verify技能的 preview gallery(Playwright 驱动,console dev server 起在自选端口 5197,用完按 PID 关掉,临时插桩已git checkout还原):把 flow 样本的find节点临时种成ui: {x: 520, y: 40},实测:left: 520px / top: 40px(兼容读活着)。start后,真实 patch 载荷为[{"id":"start","position":{"x":290,"y":88}},{"id":"find","position":{"x":520,"y":40}}, …],JSON.stringify(patch).includes('"ui"') === false—— 遗留节点在同一个 patch 里自愈了。position又被读了回来,不是靠自动布局巧合)。FlowSchema.safeParse(draft).success === true;把同一份 draft 换回ui拼写则REJECTED,issue 正是审计里那条{"code":"unrecognized_keys","keys":["ui"],"path":["nodes",0]}。审计中「今天拖一个节点就存不进去」的静态推导由此变成执行过的证据。未实机覆盖的部分:真实后端
POST /metadata的 422 未走真机(本次验证不带后端),但服务端用的就是同一份FlowSchema,上面的safeParse即该链路的判定函数;真实环境存量数据的规模仓内无法回答(仓内 examples/fixtures 既无ui也无position),不过因为 strict 闸门,带ui的行今天本就写不进去,存量面大概率接近空集。范围外发现
无(本次没有踩到与本单无关的缺陷,故未新开 issue)。
Closes#3172
Generated by Claude Code