Skip to content

feat(plugin-detail,app-shell,components): record page v3 layout - #27310

Merged
os-zhuang merged 16 commits into
mainfrom
claude/issue-27055-record-page-v3-layout
Oct 29, 2026
Merged

os-zhuang merged 16 commits into
mainfrom
claude/issue-27055-record-page-v3-layout

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #27055 — this lands the record page v3 layout. The two fenced read points stay for #27069: the related cards' default order (primary first, then derived order, without reading relatedLists) and the body tables' placement (after the first field group, without a fieldGroups placement entry).

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:没有指定页面的对象,记录页换成 v3 布局。详情区无边框,空区段折成一行。时间线合成一条流,带「全部/活动/讨论/变更」筛选。关联区是紧凑卡片,读者可拖动、折叠、隐藏,还能 ⤢ 原地放大。主从子表直接嵌在详情里。
  • 为什么改:执行 console record page v3: frameless detail sections, one merged timeline (discussion + activity + field changes), compact related cards, header 1 primary + 2 secondary + ⋯ — the synthesized default page, drawn from the object's roles; the dead BuildPageOptions hints go #27055 已批准的 v3 设计。删掉了 ADR-0085 判死的页面开关和 rightRail 插槽,把三处重复的历史、动态、讨论入口并成一个。
  • 风险与回滚:只改渲染层,作者写的元数据不变。BuildPageOptions 删字段属于 TS 层面的破坏性变更,控制台内部没有调用方传这些字段。回滚就是 revert 本 PR。读者的卡片排列存在已有的 workspacePreference 里,回滚后不会被读取,没有副作用。
  • 先看:ui/packages/app-shell/src/views/RecordDetailView.tsx(放大的 URL 往返、排列偏好、字段变更并入时间线),ui/packages/plugin-detail/src/synth/relatedArrangement.ts(排列合并规则),ui/packages/plugin-detail/src/RecordPageColumns.tsx(三栏模板和放大视图)。
  • 两分钟验证:打开下方证据分支里的 contact-1440-three-columns.png,应看到「详情|时间线|关联卡片」三栏,时间线里有一条灰色的字段变更行和两条评论。
  • 需要你做的:人工评审并合并。本 PR 改动 5828 行,超过 3000 行的人工合并线。

What changes

The synthesized default record page (an object with no assigned record page) takes the v3 layout. Authored pages are untouched apart from the shared header and the renderer faces noted below.

  • Header. One filled primary action, two outline actions, the rest in ⋯. Refresh is the first item of ⋯ (no separate ⟳ button). Up to six highlights, as an equal grid.
  • Details. Frameless sections in one to three columns. All-empty sections fold into one line at the foot. The created / updated / owner / id line closes the details column.
  • Timeline. One stream merging comments, sys_activity rows and audit field changes, newest first. The composer is on top, the chips are All / Activity / Discussion / Changes, system entries are one muted line, and a "View all N →" button shows the rest. The History tab, the Activity tab and the discussion footer are retired on this page.
  • Related column. Compact cards (title, count, +, ⤢, up to three rows of name plus one chip, no table header, no View All footer) in a fixed 320 px column. The columns are 1.25fr : 1fr : 320px.
  • Reader arrangement. Drag (desktop), Move up / Move down / Collapse / Hide from the card menu, and "N hidden · Show" at the foot. It is stored in the console: one workspace-preference module (record open mode, drawer width, timeline / related column toggles) read per user × object, with a shared panel-toggle toolbar on the record page — defaults derived from the object, never metadata #27052 workspace preference under record.related.arrangement, scope object:<name>. The value is { v, order, collapsed, hidden, basedOn, seen }. A default-order change shows "Default order updated · Restore default". A new relationship lands after its nearest default neighbour with a "New" badge for 48 hours. The tabbed tier's Related tab follows the same arrangement.
  • Enlarge in place. ⤢ opens the list full width under ?related=<object>.<field>. Esc or ‹ Back returns.
  • Body tables. A master_detail FK declaring inlineEdit, or relatedList: 'primary', is drawn as a table after the first field group. It opens on ten rows with a totals line and has ⤢.
  • Tabbed tier (drawer, narrow widths): Details / Timeline / Related / (Approvals). Timeline is second for an object whose timeline is on by default (console: one workspace-preference module (record open mode, drawer width, timeline / related column toggles) read per user × object, with a shared panel-toggle toolbar on the record page — defaults derived from the object, never metadata #27052's derivation), last otherwise. Attachments sit in Related.
  • BuildPageOptions loses hideHighlights, hidePath, showReferenceRail, hideReferenceRail, hideRelatedTab, relatedLayout, recordChrome, showActivity, history and slots.rightRail (TypeScript-only break, named in the changeset with its ADR-0087 marker).

Fence read points for #27069:

  • Default order. synthParts related ordering in RecordDetailView.tsx, commented as the fence.
  • Body-table placement. bodyTablePlacement in buildDefaultPageSchema.ts, commented as the fence.

Tests

  • New suites cover the face, the arrangement merge rules, the card stack (drag, menu, collapse, hide, enlarge, tabbed tier), body tables, body-table placement, and the timeline stream including its newest-first window. A last suite pins the retired hints as compile errors.
  • Existing pins moved with the page: History and discussion-footer reads now open the Timeline tab, the header menu has Refresh first, the highlight cap is six, and the meta line sits in the details column.
Suite (local, under the verify lock) Result
@object-ui/plugin-detail 331 files: 329 passed, 1 skipped, 2 failed on the first run and passed on rerun after the pin fixes
@object-ui/components 446 passed, 1 skipped
@object-ui/app-shell 1858 files: 1856 passed, 1 skipped, 1 failed on the first run and passed on rerun after the fix
console approvalRequestsDataSource.recordPage passed
type-check components / plugin-detail / app-shell clean

Acceptance notes

Verification

  • Gates. Every gate dispatch-gates.mjs --changed derives for this diff ran on the final tree. The --ran reconciliation verdict is below.
  • Console type-check. It fails locally only on plugin packages outside the build closure (plugin-gantt, plugin-map, plugin-markdown, plugin-timeline, plugin-tree have no dist here). No error is in a file this PR touches. CI builds the full graph.
  • Browser. Checked in a real browser against the app-crm example on a fresh database. The console dev server ran from this branch.
Gate reconciliation (66 derived, 66 run, all exit 0)
Run reconciliation — 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN.
dispatch-gates --ran: 66 derived famil(ies) accounted for — 66 run, 0 NOT-MEASURED
changed lines: 5828 (+4516 / -1312; 78 files) vs the human-merge threshold 3000: OVER

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm

claude added 12 commits October 28, 2026 11:56
…s and the rightRail slot

The default record page is drawn from the object's semantic roles alone
(ADR-0085): hideHighlights, hidePath, showReferenceRail, hideReferenceRail,
hideRelatedTab, relatedLayout, recordChrome and slots.rightRail had no console
caller and are removed from the options type, its sub-builders and the docs.
The synthesized page now has one region; record:reference_rail stays for
authored pages.

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…ess sections, empty-sections line, highlight grid, meta line, refresh in the header ⋯

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…arrangement (drag, collapse, hide, merge rules)

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…sed by ?related=object.field

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
… the first field section

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…eded tab pins updated

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…ader's arrangement

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…tests follow the v3 page

The timeline stream is newest first, so its page is the head of the
merged stream, not the tail the shared feed window keeps. Its chips wrap
in a narrow card. The Timeline tab label localizes through the packs.
Record-page tests that read the discussion footer or the History tab now
open the Timeline tab.

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
…rameless heading

Claude-Session: https://claude.ai/code/session_01Q4EjjN14dHBs3CJce73zNm
Co-authored-by: Claude <noreply@anthropic.com>
Conflicts:
- ui/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts: main
  retired the `slots.tabs` slot (#27219) while this branch rewrote the
  `discussion` slot to the timeline stream and deleted `rightRail`; the
  resolution keeps main's no-tabs-slot doc and branch, this branch's
  timeline-stream `discussion` doc, and no `rightRail`.
- ui/packages/app-shell/src/views/RecordDetailView.tsx: the
  `@object-ui/plugin-detail` import line takes the union of main's queue
  claim imports (#27264) and this branch's timeline/arrangement imports.

Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff
Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling labels Oct 28, 2026
hotlong and others added 2 commits October 29, 2026 00:43
…etirement on main made dead

main retired `slots.tabs` (#27219) and pins the stray-slot case itself
("reads no `tabs` slot"); this branch's case that a `discussion` slot
beside an authored `tabs` slot stays under the strip pins a path that no
longer exists. The timeline-stream `discussion` slot stays pinned by
"discussion slot overrides even when hideDiscussion is true".

Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff
Co-Authored-By: Claude <noreply@anthropic.com>
…nch tripped

- useRelatedArrangement reads the 48 h 「新」 clock once per mount
  (useState initializer) instead of Date.now() in render; every edit still
  stamps its own time in the handler (react-hooks purity).
- RelatedCardStack-27055's tabbed-tier probe reports the scope through a
  callback prop instead of reassigning an outer variable from a component.
- RecordMetaFooter's OWNER_FIELD is SystemFieldName.OWNER_ID from
  @objectstack/spec/system, backing its "canonical" claim
  (check:spec-symbols).
- RelatedList formats body-table totals and the compact card's date chip
  in useDisplayLocale(), not the machine locale (machineLocaleCensus-9909).
- residue-namespaces-3546 pins RelatedList's three `detail.add`
  affordances (picker title, compact +, full list Add).
- record-header-title-width re-anchors page:header's tail on
  PageHeaderActions' toolbar now that refresh lives in ⋯, with a mobile
  tail of one inline action plus ⋯.

Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff
Co-Authored-By: Claude <noreply@anthropic.com>
RecordDetailView.auditDisplayLocale-10442 stopped reading `screen` when
the stream windowing commit moved its assertion; object-ui/no-unused-imports
is an error in app-shell's lint.

Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff
Co-Authored-By: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

席位核对 · PR #27310 ← #27055 · epic PM session_cdb7a717-def7-4e71-9988-f089fbaa18ff · 2026-10-28T18:46Z

Verdict: ACCEPT — terminal four-piece, awaiting a human merge. Not governed by path (0 of 78 paths in the governed register; packages/spec untouched) but over the human-merge line: 5844 changed lines (+4524 / −1320, 80 files) against 3000 (check-governed-merges.mjs --pr 27310). No seat flips it ready, enqueues it or arms auto-merge until an account in GOVERNED_APPROVERS has APPROVED it; then this seat lands it through the queue. needs-user-decision on the PR, the final 维护者速读 as the next comment, review requested from the two authorized accounts.

What the seat read and accepts as built (head 349cd56; the cloud report on the card is comment 6473997555):

  • Targets 1–10 on the synthesized page: header 1 primary + 2 outline + ⋯ (refresh moved into ⋯), up to 6 highlights; frameless 1–3 column sections, the empty-sections line, the created / updated / owner / id line at the details foot; one timeline stream (comments + sys_activity + audit field changes, chips 全部 / 活动 / 讨论 / 变更, composer on top, compact system lines, 「查看全部 N 条 →」) replacing the History tab and the discussion footer; compact related cards in a 320 px column (1.25fr : 1fr : 320px), reader drag / 上移 / 下移 / 折叠 / 隐藏 stored in console: one workspace-preference module (record open mode, drawer width, timeline / related column toggles) read per user × object, with a shared panel-toggle toolbar on the record page — defaults derived from the object, never metadata #27052's workspacePreference as record.related.arrangement ({ v, order, collapsed, hidden, basedOn, seen }, every merge rule on the card pinned in relatedArrangement-27055.test.ts, 20 cases); ⤢ enlarges in place through ?related=OBJECT.FIELD with Esc / ‹ back; master_detail + inlineEdit or relatedList: 'primary' lists as body tables after the first field group; tabs 详情 / 时间线 / 关联 / (审批); BuildPageOptions dead hints and slots.rightRail deleted (TS-only break named in the changeset).
  • Seat walk-through on the console preview (this branch built on the seat's review worktree, HotCRM contact at a 1440 viewport, icon sidebar): three columns drawn; ⤢ opens the full-width list at ?related=crm_lead.duplicate_of_contact with the header kept and returns on Esc; the card ⋯ menu offers 放大 / 上移 / 下移 / 折叠 / 隐藏; hiding draws 「已隐藏 1 张 · 显示」; 下移 reorders; 折叠 collapses to the title row; timeline off folds the stream into the related column's foot; card titles and their menus' accessible names agree one to one. Screenshots in the seat's session notes and on the evidence branch claude/issue-27055-evidence-20261028 @ 4016ed1172.
  • Fences, as dispatched (spec: an object declares the business order of its related lists — relatedLists: ['task', 'event', …], an ordered list of child relationships like highlightFields is of fields; unlisted ones follow the derived order; a name that matches no inbound relationship is refused #27069 landed after this session started and it did not read the seat addendum): the related cards' default order is read at RecordDetailView synthParts (primary first, then the derived order; relatedLists not read) and the body-table placement at bodyTablePlacement in buildDefaultPageSchema.ts (after the first field group; no fieldGroups entry). Both are named read points.
  • Tests and gates (cloud run): plugin-detail 328 / 331 files with the two stale pins this change moved re-pinned, components 446 files, app-shell 1856 files with three authored-page cases re-pinned; red-before-fix evidence for the stream window (oldest-20 → newest-first); components / plugin-detail / app-shell type-check 0 errors; 66 / 66 derived commands exit 0 with the --ran reconciliation. CI: head 349cd5625c — 55 success / 8 skipped / 0 failure (1 cancelled: the Plan Test Core shards run superseded by the next push); every required context green, Test UI 16 / 16 shards, Build & E2E UI, Type Check UI, Lint UI.

Carried to the patch round that follows landing (one local round under this claim, together with #27241 and the #27069 fence half; not a REWORK — none changes the diff the maintainer is asked to approve):

  1. Record page: the related switch decides whether the column exists, the panel toggles move into the header action row, and a 1440 px window with the sidebar is three columns #27241 (maintainer rulings of 2026-10-28, seat addendum 6468579228): related OFF ⇒ no column and no rail; the panel toggles as one segmented control in the header action row; a 1440 px window with the sidebar open is three columns.
  2. The spec: an object declares the business order of its related lists — relatedLists: ['task', 'event', …], an ordered list of child relationships like highlightFields is of fields; unlisted ones follow the derived order; a name that matches no inbound relationship is refused #27069 fence half: read relatedLists for the default order and the field group's relatedList placement entry for body tables.
  3. 「恢复默认顺序」 is drawn only as the hint when the author's default changed (RelatedDefaultChangedHint); the card asks for it whenever the reader has dragged — add the standing entry (column foot beside 「已隐藏 N 张」, or the card ⋯).
  4. Acceptance notes agreed: body-table totals as a summary line; body-table collapse per view; the enlarged list keeps the list page's View All; refresh in ⋯; the 1440 three-column screenshot with the sidebar collapsed (the tier threshold is Record page: the related switch decides whether the column exists, the panel toggles move into the header action row, and a 1440 px window with the sidebar is three columns #27241's item 3).

Out-of-scope findings filed: #27312 (the .describe() of relatedList: 'primary' and enable.trackHistory still narrate the v2 page). HotCRM's lead / account / opportunity / case keep their authored kind: full pages, so this layout reaches contacts, tasks, products and the rest of HotCRM only — the epic parent carries the hotcrm follow-up.

Deviations recorded: the cloud session ran on the seat's model until the maintainer switched it; its pushes and the fleet's PR-open / reopen events fired no PR workflow here (reopen tried at 16:12Z), so a local os-dev round merges origin/main and pushes with a user token to put the final head under CI — patch round 0 (report 6476103358) merged origin/main d4427aedcf (three conflict hunks resolved toward both sides, one dead tabs-slot pin removed after #27219), patch round 1 (report 6477355363) fixed the six branch-inherent CI reds the first real run surfaced — a render-time Date.now() moved to a mount-time read, OWNER_FIELD backed by SystemFieldName.OWNER_ID, the detail.add residue pin raised to the three real affordances, body-table totals and the compact date chip routed through useDisplayLocale, the header-width e2e re-anchored on the toolbar row, one unused test import — no functional change beyond the 48 h badge clock being read at mount; the head this review names is the one after those rounds; the cloud report comment carries no seat signature line (written before #27263 landed).


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

维护者速读(终稿) · PR #27310 ← #27055 记录页 v3 布局 · 2026-10-28T18:47Z


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

Brief-claimed-by: session_01Utp6CbQLcy8yg6vhJVXXi8 · batch #425 · 2026-10-29T01:35Z

Director seat, summon #54 (ledger objectstack#12708). Presented to the maintainer in batch #425 as item 2 of 4 — over the 3000-line human-merge line (5844 changed lines, +4524 / −1320, 80 files; 0 governed paths), terminal four-piece.

Four-item check before presenting (read 2026-10-29T01:35Z):

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP

Finding for this PR, from the os-dev-report of PR #27352 (#27312, which rewrites the spec describes to this PR's v3 page and lands after it). ⛔ Not a review and not a claim.

On this PR's head, ui/content/docs/guide/slotted-pages.md:130-132 (a file this PR already edits) still says the default tab strip is Details, then one tab per relatedList: 'primary' list, then a shared Related tab, then History, and that promoting a child table to its own tab is a one-word change. On the v3 page as PR #27352 measured it, a primary list is a body table inside the details column with no tab of its own, and field changes join the timeline stream under its Changes filter, with no History tab. If that reading is right, the paragraph becomes false when this PR lands.

Merged via the queue into main with commit eef8373 Oct 29, 2026
69 of 70 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-27055-record-page-v3-layout branch October 29, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants