Skip to content

fix(plugin-detail,app-shell,components): record page round 2 — related OFF draws no column or rail, one segmented panel control in the header row, three columns in a 1440 window with the sidebar - #27473

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-27055-v3-patch-27241
Oct 29, 2026

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #27055
Fixes #27241

Clause-②: no
Metadata-protocol: none

Round 2 of the record page v3 (epic #26676), on main after #27310: the three rulings of #27241, the #27069 fence half of #27055, and a standing 「恢复默认顺序」 entry. Maintainer, 2026-10-28, verbatim: 「是:三栏阈值改成 1440 窗口(含侧栏)即三栏;开关改进头部动作行,关联 OFF 就没有栏」.

What changes

A1 — the related switch decides whether the column exists. recordPageArrangementFor sets relatedRail to switches.related && !columns.includes('related'), and RecordPageColumns draws the related column only when the arrangement places it. Related OFF: no related column and no rail toggle, in both column tiers. Related ON with no room (two-column tier): the rail toggle, which opens the column. With both switches off the page is the details column alone.

A2 — one segmented control at the end of the header's action row. PanelToggles (@object-ui/components) is now one segmented control, an icon and a label per segment (Timeline with the activity glyph, Related column with the right-panel glyph). The console's record view hands it to page:header through a new host slot, PageHeaderTrailingContext. PageHeaderActions draws it as the last segment of its role=toolbar row, after ⋯, behind a vertical hairline. It is drawn in both column tiers, and not in the tabbed tier or in the drawer. The toolbar gained max-w-full, so on a narrow header the segment wraps onto its own line, right-aligned, instead of running past the page (measured at a 1024 px window; see screenshot 08). The crumb row keeps only the ways back (origin link, 「Collapse to drawer」) and has no child without one, so empty:hidden removes it. Tooltip keycaps and aria-keyshortcuts are unchanged. The chord matcher accepts code Period / Comma, or key . / > and , / <.

A3 — thresholds. Measured on the console from this branch (HotCRM contact, sidebar expanded): the sidebar is 255 px plus its 1 px border, and [data-record-page-root] is 1184 px in a 1440 window, 1024 px in 1280 and 768 px in 1024. The constants are 1440 − 256 − 64 = 1120 and 1024 − 256 − 8 = 760, with the derivation in their docblock. The #26758 tier pins move to 1120 / 760, plus a pin on the three windows the thresholds serve. e2e/live/record-history-display.spec.ts opens the tab strip, so its viewport moves from 1200 to 1000, which keeps the record view under the new two-column floor.

B — the #27069 fence half.

C — standing 「恢复默认顺序」. resolveRelatedArrangement now reports rearranged: the shown order differs from the default, or a card is hidden. The column foot, which is the same line as 「已隐藏 N 张 · 显示」 and appears in both the related column and the tabbed tier's Related tab, then offers 「Restore default order」 (new key detail.relatedRestoreDefaultOrder, ten packs). It writes the new edit restore-default-arrangement: order: [], hidden: [], basedOn set to the current default's hash, seen: {}. Collapsed state is kept. The stored shape {v,order,collapsed,hidden,basedOn,seen} is unchanged. RelatedDefaultChangedHint is unchanged.

Not touched: packages/spec/**, navigation-overlay.tsx, recordDrawerStack.tsx.

Screenshots

HotCRM contact record page. The console runs on vite from this branch; the backend is objectstack dev --fresh --seed-admin from hotcrm 1f3f8880; headless Chromium. The images are on the never-merged branch claude/issue-27055-evidence-20261029.

  1. 1440 window, sidebar expanded: three columns, the segmented control in the header row · header row close up
  2. Related OFF: details and timeline, no rail toggle
  3. Timeline OFF: details and related, the timeline folded at the related column's foot
  4. A card moved: Restore default order at the column foot · foot line close up. Clicking it put the default order back; stored value {"order":[],"collapsed":[],"hidden":[],"basedOn":"e40133ac","v":1}.
  5. 1024 window, sidebar expanded: two columns, related ON, the rail toggle · related OFF: no rail toggle; the segmented control wraps
  6. Dark theme header row, timeline off and related on

Tests

Head `9c82d929a8`. The build and type-check closure was rebuilt first (`pnpm --workspace-concurrency=2 --filter '@object-ui/console^...' build`, VERDICT command-exit 0, 72 of 127 projects, then `@object-ui/i18n`, `components` and `plugin-detail` again after the edits). Every run went through `scripts/pm/os-verify-lock.sh`, UNLOCKED (declared below).

  • `@object-ui/plugin-detail` whole package: `Test Files 334 passed | 1 skipped (335)`, `Tests 3058 passed | 18 skipped`.
  • `@object-ui/components` whole package, on the final head: `Test Files 449 passed | 1 skipped (450)`, `Tests 4338 passed | 24 skipped`.
  • `@object-ui/i18n` whole package: `Test Files 89 passed (89)`, `Tests 1373 passed | 13 skipped`.
  • `@object-ui/app-shell` `src/views/`: `Test Files 1262 passed (1262)`, `Tests 11874 passed | 1 skipped`. This includes `panelToggles-27052`, `recordPageTiers-26678` and the new `relatedListsOrder-27241`.
  • The changed and new files were re-run on the final head after the last edits: 7 files / 65 tests in app-shell, and 3 files / 11 tests in the components header suite.
  • Type-check, each script echoed (`tsc --noEmit && tsc -p tsconfig.test.json`), exit 0 with 0 `error TS`: components, plugin-detail, app-shell, i18n.
  • eslint on the changed files of the four packages: 0 errors.
  • ui `check:new-line-citations` reported 0 new citations, and ui `check:spec-symbols` exited 0.
  • `ui/e2e/record-header-title-width.spec.ts` ran locally under a throwaway config with no webServer (the spec uses `page.setContent`), with the installed `chromium_headless_shell-1234` given as `executablePath`: `14 passed (1.8s)`. The config was deleted after the run.

Reverse verification

Each new pin was run against its mutation through `node scripts/ablation-replace.mjs`. The tool's own verdict was `ok mutation landed` (anchor 1 → 0, blob moved), and it restored with `git diff HEAD empty` and the HEAD blob matching. All runs were vitest on the aliased `src`, so no dist step applies.

  1. Related OFF keeps the rail (`relatedRail: !columns.includes('related')`): 7 failed (arrangement, `RecordPageColumns` and app-shell pins).
  2. The header row drops the trailing segment: 10 failed (the components slot pin and the app-shell toggles file). The first attempt was refused by the tool as a no-op, because the replacement text already existed in the file. It was re-run with a distinct replacement.
  3. The chord matcher reads `code` only: 1 failed (the code-less event pin).
  4. Three-column floor back to 1280: 2 failed. The first run failed at import, with `@objectstack/spec/data` not found while the gate battery was running beside it. That run is not counted as a measurement, and the re-run is the reading.
  5. Two-column floor back to 1024: 3 failed.
  6. `deriveRelatedLists` drops `relatedLists`: 1 failed (the mounted order pin).
  7. `bodyTablePlacement` places nothing: 5 failed.
  8. The foot line never offers the restore: 2 failed.
  9. `restore-default-arrangement` keeps `hidden`: 2 failed.
  10. The pressed tint back to `bg-muted`: 1 failed.

`git diff HEAD` was empty after the ten runs.

Gates

Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `9c82d929a8`. The change set is 38 paths against merge base `3bfb357aa3`, which derives 34 commands. Each command's exit code was written before any pipe. `--ran` reports `Run reconciliation — 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN`.

33 commands exited 0. `pnpm --dir ui exec vitest run scripts/` exited 1, with `Test Files 2 failed | 167 passed | 2 skipped (171)` and `Tests 3 failed | 4898 passed`. All three failures are known host gaps on this macOS box, the same three as in rounds 0 and 1 of #27310. Two are the bash 3.2 `mapfile: command not found` in `select-affected-tests-wiring.test.ts`. The third is the `check-i18n-dead-keys` 「on the real tree」 case, which times out. These three are NOT MEASURED locally, and CI reads them.

Declared narrowing — verification ran UNLOCKED. scripts/pm/os-verify-lock.sh
could not take the shared verify lock on this host: no usable flock. The shared
verify lock is declared Linux-only (flock is util-linux, and a stock macOS does
not ship it), so every build and test command in this PR was run directly, without the lock —
a declared narrowing, not a silent one. No serialization guarantee held for these
runs, nor for any sibling agent in this container while they ran.

Acceptance notes

  • text-accent vs text-accent-foreground. The ruling names bg-accent + text-accent and describes the result as 「accent 浅底深字」. In both console themes, text-accent is the same pale HSL as bg-accent (light: --accent 240 18% 94%, measured on the page). The literal pair would draw invisible text. The on segment is therefore bg-accent + text-accent-foreground, which is the light-tint, dark-text pair the ruling describes. An off segment is text-muted-foreground. This is flagged for the seat in the report.
  • Wrapping on a narrow header. At a 1024 px window (768 px record page) the header's actions plus the segmented control are wider than the header. The toolbar now wraps inside the header (max-w-full), and the segment ends its own line. Before this, the toolbar overflowed and a click scrolled the page sideways. e2e/record-header-title-width.spec.ts ran locally: 14 passed.
  • A group naming a side card. Per the ruling, bodyTablePlacement places body tables only. A field group whose relatedList names a relationship that is not a body table (not 'primary', not an inline-edited master_detail) places nothing, and the card stays in the related column. Before this, such a group drew nothing either.
  • main gained 7 commits since the base 3bfb357aa3, none touching a changed path. GitHub reports no conflict, and no merge was made.

Generated by Claude Code

hotlong and others added 5 commits October 29, 2026 14:51
…related OFF has no rail, one segmented panel control in the header row, 1120/760 container thresholds, relatedLists order and field-group placement, a standing restore-default-order entry

Claude-Session: https://claude.ai/code/session_cdb7a717def74e719988f089fbaa18ff
Co-authored-by: Claude <noreply@anthropic.com>
…e trailing panel switches never overflow a narrow record page

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 #27473 ← #27055 round 2 + #27241 · epic PM session_cdb7a717-def7-4e71-9988-f089fbaa18ff · 2026-10-29T08:34Z

Verdict: ACCEPT — ordinary queue landing (governed register: 0 of 38 paths; packages/spec untouched; +958 / −159, under the 3000-line threshold). The round-2 report on #27055 (comment 6491778760) is read and accepted as filed; the round-2 Claim: naming this branch is 6491819758 (posted after the PR opened, which is why the closing-target claim guard was red on its first run and re-run).

Checklist, judged on GitHub, on the branch and on the seat's console preview:

Landing: ready + auto-merge in this stroke on the maintainer's standing authorization for this epic (verbatim, 2026-10-28: 「授权你用车队身份给 #26758 翻 ready 并挂 auto-merge(squash),后续本 epic 的 PR 复核 ACCEPT 后同样处理」); the queue decides the rest. After MERGED both cards close by the Fixes lines and the seat clears pm:dispatched on each.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 29, 2026 08:36
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 29, 2026 08:36
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit 273137d Oct 29, 2026
56 of 57 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-27055-v3-patch-27241 branch October 29, 2026 08:53
This was referenced Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment