fix(flow-designer): read approver value sources off the schema instead of mirroring them (framework#3508 follow-up) - #2910
Merged
Conversation
…d of mirroring them (framework#3508 follow-up) The approver Value picker decided WHERE its candidates live from a local table hand-mirrored from the spec's `APPROVER_VALUE_BINDINGS`. That mirror is what made framework#3508 possible: `xRef.map` names a picker KIND and nothing more, so this package had to choose a data source itself — and chose the metadata REGISTRY, which lists no `sys_user` / `sys_team` / `sys_business_unit` / `sys_position` rows. Candidates were always empty and the control degraded to a raw-id text box. The spec now publishes the contract as `xRef.sources`. `json-schema-to-fields` carries it through — validating each entry and dropping any that could not drive a picker (a `data` source with no committed column would query nothing, which is the failure this ends) — and the new `recordLookupFor()` prefers it over the local table. A new approver type can no longer leave a stale mirror here. Presentation deliberately does NOT move: display field, people-picker opt-in and row subtitles stay local, so the spec ships the data contract and not the look. The local table stays as the fallback for a server that predates the annotation, and a `data` source for a kind with no local presentation entry still renders a lookup labelled by its committed column rather than degrading a resolvable reference to free text. Sources are keyed by the DISCRIMINATOR, not the picker kind: `role` and `org_membership_level` share one kind but are separate enum members upstream. Also corrects the approver `type` options comment in `flow-node-config.ts`. That list is the OFFLINE fallback — `FlowNodeInspector` renders `serverFields ?? fieldsForNodeType(...)`, so against a real backend the engine-published configSchema wins — which is why the "indirect bindings lead, `user` last" order stated only there never reached the live picker (it followed the spec enum, `user` first). The ordering now lives in the spec's `ApproverType` enum; the comment says which list is authoritative. Tests: 9 new cases (published source wins; fallback when absent; non-data sources stay off the record path; presentation stays local; discriminator keying) plus 2 for the schema reader. app-shell 800 pass, type-check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BVRVgSvmyCwmDfTmKmCZoH
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 free
to 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.
配套 framework objectstack#3817(spec 侧新增
xRef.sources)。需与之一起看:本 PR 消费那份注解。问题
审批人 Value 选择器自己决定候选从哪来,靠的是一份手工镜像 spec
APPROVER_VALUE_BINDINGS的本地常量KIND_TO_RECORD_LOOKUP。这份镜像正是 framework#3508 得以发生的原因:
xRef.map只说了渲染哪种 picker('team'),没说这个 picker 背后是什么,于是本包只能自己挑一个数据源 —— 挑成了元数据注册表GET /api/v1/meta/:type,而它列不出sys_user/sys_team/sys_business_unit/sys_position的记录。候选恒空,控件退化成手敲 id 的文本框。镜像修好了,但镜像本身还在:下一个新增的审批人类型照样可能悄悄落后。
改动
spec 现在把数据契约作为
xRef.sources发出来(逐类型:{ source: 'data', object, valueField }、闭合枚举内联、或非 picker 标记)。json-schema-to-fields把它读进FlowReferenceSpec.sources,逐条校验:无法驱动 picker 的条目直接丢弃(比如data源缺valueField—— 那会查出一个什么都问不到的 picker,正是本次要终结的失败)。recordLookupFor():服务端发布的 source 优先,本地表退为兜底。type)取,不是按 picker kind ——role与org_membership_level共用一个 kind,但在上游是两个枚举成员。没有移走的是表现层:显示哪个字段、要不要开 PeoplePicker、行副标题写什么,仍是本包的决定。spec 出数据契约,不出长相。
两处刻意的保守:
datasource 但本包没有对应表现条目时,仍然渲染 lookup(标签退回提交列),而不是把一个明明可解析的引用降级成自由文本。顺带纠正一处误导注释
flow-node-config.ts里审批人type的 options 是离线兜底 ——FlowNodeInspector渲染的是serverFields ?? fieldsForNodeType(...),接了真后端就走引擎发布的 configSchema,这份列表根本不读。所以 #2834 只写在那里的「间接绑定优先、
user垫底」从未生效:实测线上下拉是 spec 枚举顺序,User排第一,正好相反。顺序已改到 spec 的ApproverType枚举(objectstack#3817),注释也改成说清哪份才算数。测试
FlowReferenceField.sources.test.tsx(9 例):发布的 source 胜出本地表;缺失时回退;enum/auto/unsupported不走记录路径;表现层仍来自本地;判别值 keying 能区分role与org_membership_level;无表现条目的datasource 仍出 lookup。json-schema-to-fields.test.ts+2:sources透传且丢弃不可用条目;老服务端不产生该字段。app-shell全量 800 通过(118 文件);pnpm --filter @object-ui/app-shell type-check干净。依赖顺序
本 PR 对老服务端安全(
sources缺失即回退),可先合;但要真正生效,需要 objectstack#3817 发布后的后端提供xRef.sources。🤖 Generated with Claude Code
https://claude.ai/code/session_01BVRVgSvmyCwmDfTmKmCZoH
Generated by Claude Code