fix(studio,timeline,list): 表单设计器解析对象翻译;timeline 认它自己配置的日期字段 (#3134, #3129) - #3175
Merged
Conversation
) ObjectFormDesigner read `entry.def.label` / `group.label` straight off the object draft, so a fully translated object still rendered its English source labels on the layout canvas while every other surface resolved the project's object translations. Route field cards (and the drag overlay) through `fieldLabel()` and section headers through `sectionLabel()` — the same resolver ObjectForm and RecordDetailView use — with the authored metadata label as the fallback. StudioDesignSurface passes the object's API name explicitly so the lookup root survives an unnamed draft body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
… nesting (#3129) `dateField` is the pre-#2231 alias for `startDateField`. `@object-ui/types` declares it on the nested config and both ObjectView read-sites resolve it, but ObjectTimeline read it only off the flat prop and ListView only out of `options.timeline` — including in the capability gate. A view authored as `timeline: { dateField: … }` therefore fell through to the caller's default (`created_at` / `due_date`), which the projection does not request, so every record bucketed into "No date" with the configured date still in the row. Also drops the reproduction scratch in favour of two real regression suites. The pre-existing ObjectTimeline test stubs out `./renderer` and asserts only item titles, so the date binding had no behavioural coverage at all — which is how an all-"No date" timeline shipped green. The new plugin-timeline suite renders through the real renderer and reads the bucket headers; the plugin-list suite spies on the registry to pin the forwarded binding and the $select. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
… type-check `ObjectTimelineProps` does not declare `data` (the component reads it off the rest args), so the regression suite has to apply it untyped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
|
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.
修复本批次两个渲染缺陷:#3134(Studio 表单布局设计器不解析对象翻译)与 #3129(timeline 不按配置的日期字段分桶)。
#3134 —— 表单布局设计器未解析对象字段/分组翻译
根因(与 issue 原文一致)
issue 的归因是对的,且定位精确。
ObjectFormDesigner自称是"最终用户表单的预览",但它直接读原始草稿元数据:entry.def.labelg.label || g.keyactiveEntry.def.label而同一对象的其他所有表面(
ObjectForm、RecordDetailView、数据视图)都先走项目的对象翻译。于是一个已完整翻译的对象,在布局画布上显示Opportunity Name/Basic Information,点开一层却是商机名称/基本信息。改动
三处显示点改走
useSafeFieldLabel()—— 与运行态表单同一个解析器:fieldLabel()解析字段卡片与拖拽浮层,sectionLabel()解析分组标题,无翻译时回落到作者写的元数据 label。查找根是对象 API 名:StudioDesignSurface现在显式传objectName={current.name},草稿体尚未命名时也能解析,并保留draft.name作为回落。用
useSafeFieldLabel(而非useObjectLabel)是因为设计器也会在无I18nProvider的测试/预览里挂载,这时它退化成恒等回落。#3129 —— timeline 不按配置的日期字段分桶
issue 说该视图声明了
timeline.startDateField: "start_date",问题"isolated to the timeline path"。这条路径实测是好的。 我按三层做了复现:ObjectTimeline单体timeline.startDateField+ 扁平startDateFieldListView出参$select投影$select含start_date,绑定正确ListView→ 真实ObjectTimeline组合Later,非No date也就是说:声明
timeline.startDateField时,渲染路径本来就是对的。照 issue 原文去改渲染器会改错地方。实测复现到的真正缺陷
把四种产品实际接受的书写形态逐一跑出来,第四种复现了报告的症状:
$selectview.timeline.startDateField(spec)start_dateLater✅view.options.timeline.startDateField(app-shell 产出)start_dateLater✅view.options.timeline.dateField(legacy 别名)start_dateLater✅view.timeline.dateField(spec 嵌套 + legacy 键)start_dateNo date❌dateField是startDateField的 #2231 前遗留别名。它并非野生形态:@object-ui/types的ListViewTimelineConfig明确在嵌套配置上声明了它,app-shell 与 plugin-view 两个ObjectView读取点也都解析它。真正驱动时间轴的两个读取点却不解析:ObjectTimeline只在扁平 prop(schema.dateField)上认这个别名,嵌套的schema.timeline上不认;ListView只从options.timeline里取,不从 spec 正典的schema.timeline取 —— 能力门禁(capability gate)也有同一个缺口,所以这种视图可能连 Timeline 选项都不会被提供。于是形态 D 一路穿透到调用方的默认值(
created_at/due_date)。该字段通常不在投影里,每行都取不到值,dateBucket()收到undefined→ 全部落进 No date,而配置的日期就原封不动躺在行里。这同时解释了 issue 里那句"metadata-only 地把两个日期字段加进投影,行为没变":投影里本来就有正确字段,渲染器读的是另一个键 —— 加字段当然没用。这个吻合度是本次归因的主要证据。
改动
两个读取点在它们已经用于
options.timeline.dateField的同一优先级位置解析该别名;spec 键在两者同时存在时仍然胜出。能力门禁补同一个缺口。ObjectTimeline的schema.timeline类型从TimelineConfig收敛到ListViewTimelineConfig—— 即 types 包一直声明、而渲染器一直没读的那个形状。仍未证实的部分(如实标注)
若 HotCRM 已发布的
campaign_timeline确实带的是startDateField而非dateField,那么本 PR 修的就是一个同症状的相邻缺陷,而非该视图的直接病因;那种情况下剩余嫌疑是viewDef.timeline根本没走到 app-shell 的ObjectView(它随后把轴钉死在自己的'due_date'默认值上,crm_campaign 没有该字段,症状完全一致)。我没有跑过 HotCRM 实例,也未取得该视图已发布的 JSON(请求挂载 hotcrm 仓库被拒绝),所以这一支属于未实测。要坐实它,需要crm_campaign/view/campaign_timeline的已发布视图定义。验证证据
全部为本分支当前代码的真实运行输出,非誊抄。
pnpm type-check—— 全绿:Tasks: 78 successful, 78 total。受影响包的测试套件:
(app-shell 运行中打印的
DOMException [NetworkError] ... localhost:3000是既有噪音:部分用例故意打不可达地址,252 个文件全通过。)#3129 修复前后的分桶实测(同一套探针,仅回退渲染器改动):
回归测试撤销后的失败条数
两处都验证过"撤掉修复后必须变红":
ObjectFormDesigner.tsx+StudioDesignSurface.tsx:Tests 3 failed | 7 passed (10),即新增 4 条里失败 3 条。第 4 条(无翻译时回落到元数据 label)本就该两边都通过,是有意的对照。ObjectTimeline.tsx+ListView.tsx:Tests 3 failed | 5 passed (8),即失败 3 条(plugin-timeline 1 条:嵌套别名分桶;plugin-list 2 条:转发的绑定、能力门禁)。顺带说明:这两个缺陷当初为什么能带着绿灯发布
ObjectTimeline.test.tsx把./renderer替换成只渲染item.title的桩件,因此它那条"uses spec-compliant startDateField property"用例,无论日期绑定有没有解析成功都会通过 —— 日期只存在于真实渲染器输出的分桶表头里。ListView.test.tsx的 timeline 用例则只断言视图切换器里出现了 Timeline 选项,从未检查转发下去的绑定。所以"整条时间轴全部落进 No date"这件事在既有测试下是完全不可见的。新增的两套回归测试因此刻意不 mock 渲染器:plugin-timeline 那套读真实渲染器输出的分桶表头,plugin-list 那套用注册表 spy 钉住转发的绑定与
$select。边界
未移除/重命名任何可作者化的 spec key,未改公开导出,无协议破坏性变更。
dateField仍是既有的 deprecated 别名 —— 本 PR 只是让它在两种嵌套下解析一致,spec 键始终优先。Generated by Claude Code