Skip to content

Record open: the drawer is the default and the split pane retires — the list keeps its full width, and a record opens only as the drawer or the page #28915

Closed

Description

@objectstack-fleet

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

Filed by the record-page epic seat under epic #26676, on the maintainer's ruling. Code readings below are on main 9a9823d921. No domain:* label is set: triage routes this card.

Ruling

The maintainer, 2026-11-02: 「默认应该是普通列表,右侧弹出。drawer」 and 「默认改抽屉,分屏彻底退役,只留抽屉和整页,立卡。」

This supersedes #27545 Target item 1 ("Split is the default") and the split half of item 2, written on the 2026-10-29 final design. The other #27545 items stand: the non-modal drawer, ⤢ maximizing in place, and the full page from ↗ and ⋯.

Why

  • Observed. Opening a record narrows the list. At 1440 px a lead list keeps three columns. In a narrower window it turns into card rows.
  • No metadata pull. split already left NavigationModeSchema, so no author can declare it. ui/packages/app-shell/src/views/ObjectView.tsx:780 still turns a declared or default drawer into split unless the reader chose the drawer. HotCRM's task, opportunity and case views declare mode: 'drawer' and get a split pane.
  • The scenario is already covered. The drawer draws no dimming overlay and is non-modal, so the list stays visible, a click on another row swaps the record, and the 「1 / 13」 stepper works.

Reading: the split surface

  • ui/packages/app-shell/src/utils/recordOpenPreference.ts: the type at line 55, the default at line 61, and the decode at line 78.
  • ui/packages/app-shell/src/views/ObjectView.tsx:780: the mapping from drawer to split.
  • ui/packages/components/src/custom/navigation-overlay.tsx: the 'split' mode, RECORD_SPLIT_MIN_CONTENT_PX, useSplitEscape and paneBeside.
  • ui/packages/components/src/custom/record-list-face.tsx, with its readers in plugin-grid/src/ObjectGrid.tsx and plugin-list/src/ListView.tsx: the narrowed list face.
  • ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx (lines 74, 84, 343–355) and the list.recordOpenSplit key in the i18n packs.
  • content/docs/frontend/plugins/plugin-view.mdx, around line 520.

Target

  1. A record opened from a list opens in the drawer by default. The list keeps its full width underneath.
  2. RecordOpenPreference is 'drawer' | 'page'. A stored split is an unknown value and reads as the default, with no compatibility read (startup posture).
  3. The split mode and its code go: the mapping at ObjectView.tsx:780, the overlay's split face and width floor, the narrowed list face if nothing else reads it, and the i18n key in every pack.
  4. The Display menu's 「打开记录」 offers 抽屉 and 整页.
  5. These stay: the non-modal drawer, a row click swapping the record, the stepper, drag-to-resize, ⤢ maximizing in place, and the modal sheet for a drawer with no list.
  6. No metadata change: navigation.mode keeps its values.

Premise to verify first

ui/packages/app-shell/src/layout/consoleSidebarRail.ts:50 derives the sidebar's auto-fold width from split content (1160 + 256 = 1416, #27593). Read whether anything other than the split pane needs that fold. Do not change it on assumption: name the reading in the PR. If the fold has no remaining reason, report it as a follow-up finding for the maintainer, because #27593 was a separate ruling.

Acceptance

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: priority:p2 · domain:ui · pm:queue · 2026-11-02T05:08Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Claim: PM loop round 10 · 2026-11-02T05:21Z
    Session: session_01QsR2jRrZ9h4h6RnBzGnhgi (card thread, os-dev); dispatched by seat session session_01QsR2jR7ZFkpqmm4U8S1f9y
    Account: zhuangjianguo
    Branch: claude/project-thread-o2b23t (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-28915
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: recordOpenPreference.ts, ObjectView.tsx (the drawer→split mapping), components navigation-overlay.tsx, record-list-face.tsx and custom/index.ts, their readers in ObjectGrid.tsx and ListView.tsx, ViewSettingsPopover.tsx, the list.recordOpenSplit i18n key in every pack, content/docs/frontend/plugins/plugin-view.mdx, the tests of all of these, and a changeset; consoleSidebarRail.ts read-only (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: default
    Clause-②: yes (narrowing)
    Metadata-protocol: none
    Responsibility: opening a record narrows the list to a split pane, so a lead list keeps three columns at 1440 px and turns into card rows in a narrower window | the drawer is non-modal and already keeps the list, the row swap and the stepper | every user who opens a record from a list
    Thread-read: 6569566361
    Premise: holds (at origin/main 8bb2417a, ObjectView.tsx:779 maps drawer to split unless the reader chose the drawer, and navigation-overlay.tsx:589 draws the split face)
    Serial constraints cleared: none in flight on these files (every open PR checked); domain:ui#1 holds #28950 (ViewSettingsPopover.tsx) until this PR is up


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jRrZ9h4h6RnBzGnhgi
    os-dev-report

    {
      "issue": 28915,
      "status": "done",
      "branch": "claude/project-thread-o2b23t",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29108",
      "head": "2255b429",
      "session": "session_01QsR2jRrZ9h4h6RnBzGnhgi",
      "premise_still_valid": true,
      "summary": "A record opened from a list now opens in the non-modal drawer over the full-width list by default; the split pane, its narrowed list face (three columns or compact cards) and the Split choice in the Display menu's Open records control are retired. RecordOpenPreference is drawer | page and a stored split reads as the default with no compatibility read. Seven @object-ui/components exports leave (RECORD_SPLIT_MIN_CONTENT_PX, RecordListFaceProvider, useRecordListFace, recordListFaceFor, RECORD_LIST_CARD_FACE_BELOW_PX, RECORD_LIST_NARROW_COLUMN_COUNT, RecordListFace) under a BREAKING changeset with FROM-TO lines and an ADR-0087 runtime-export-retired disposition; list.recordOpenSplit leaves all ten packs. The #27545 tests are converted to the drawer (4 renamed), not deleted.",
      "claim_lines": [
        "Clause-②: yes (narrowing)",
        "Metadata-protocol: none",
        "Skills-docs: follow-up owed — skills/objectstack-ui/rules/record-page.md, skills/objectstack-ui/evals/record-page.json"
      ],
      "tests": "At 407e38cf, ui vitest --maxWorkers=2 under os-verify-lock: plugin-list whole suite 179/179 files 1725 tests; plugin-grid ObjectGrid set + components/plugin-detail/plugin-view set 207/207 files 1692 tests; app-shell ObjectView set 141/141 files 1314 tests (527 files, all VERDICT command-exit 0). At 4b3e19eb: the 54 test files touched against the base, 377 tests green. At 2255b429 after the second main merge: 29 files 228 tests green (touched tests, plugin-list Display-menu and record-count tests, main's new ListView.restoreViewDefaults-28948 and data-table row-action tests). turbo type-check components, i18n, plugin-grid, plugin-list, plugin-detail, plugin-view, app-shell, console 78/78 exit 0 at 407e38cf; plugin-list + components 51/51 at 2255b429. ui eslint (Lint UI config) on the 41 touched ts/tsx files: 0 errors. Ablation: decode mutated to map a stored split to page via ablation-replace.mjs, recordOpenPreference.test.ts went red (1 failed); restored, git diff HEAD empty.",
      "gates": "dispatch-gates --commands derived 67; all 67 run, exit 0 each, --ran reconciliation 67 run 0 NOT-MEASURED (at 407e38cf). check:skill-examples first exit 3 (client-react not built), exit 0 after the full build. check:type-check-debt under the verify lock exit 0. node scripts/check-sdui-manifest.mjs exit 0. PR-body gates with GITHUB_EVENT_PATH on the sent body: check-changeset-no-major 0, check-adr-0087-registration 0, check-closing-keyword-parity 0, check-partof-closing-keyword 0. CI check-runs on #29108: not yet concluded at report time (in_progress).",
      "dogfood_battery": "4b3e19eb · VERDICT command-exit 0 on each of four locked legs (pnpm --filter @objectstack/dogfood exec vitest run --shard=K/4) · Test Files 384 passed + 3 skipped of 387 · Tests 3166 passed + 28 skipped · no failures. Ran as shards because one foreground call is capped at 600 s (see deviations).",
      "screenshots": "/mnt/project-files/issue-28915/shots/ — 12 PNGs, before and after, 1440 and 1000 px, sidebar open (pinned at 1000 px), examples/app-crm Accounts: list, Display menu Open records, record open. Before at 1440: split pane with the list narrowed to three columns; before at 1000: drawer (split fell back for want of width); after: drawer over the full-width list at both widths; Display menu Split/Drawer/Full page before, Drawer/Full page after. The console rendered in English, so the 打开记录 control reads Open records.",
      "mcp_calls": "0",
      "api_writes": "2 — fleet-write relay pr_create (run 41407687829, read-back byte-identical, no assignees) and this os-dev-report comment via post-stamped; plus git pushes to the branch",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: b · reach: named producer ui/packages/app-shell/src/layout/consoleSidebarRail.ts · evidence: CONSOLE_SIDEBAR_RAIL_BELOW_WIDTH = RECORD_SPLIT_MIN_CONTENT_WIDTH (440 + 720) + 256 = 1416 px is derived only from split content; with split retired the threshold has no remaining reason, while the fold itself keeps one (#27593 maintainer quote 窄屏幕左侧菜单自动折叠,点击弹出, original target near 1100 px) · dedupe words: sidebar rail fold threshold 1416 split-derived",
        "class: c · reach: named producer · stale split-pane comments outside the declared surface: record-top-bar.tsx:11, data-table.tsx:3735, plugin-detail RecordPageColumns.tsx:135/237, useRecordPageTier.ts:31, synth/recordPageColumns.ts:16/93/110, react useNavigationOverlay.ts:278, plugin-view ObjectView.tsx:590/1193, RecordDetailView.tsx:943/1003, objectViewOpenAsPage.tsx:15, appObjectScope.ts:45, ObjectGrid.tsx:3202 · dedupe words: stale split pane comments",
        "class: c · reach: named producer @object-ui/i18n · the console.objectView.recordCount key family is now read by no source file, and common.closePanel is no longer read by the overlay · dedupe words: unread i18n keys recordCount closePanel",
        "class: c · reach: named producer skills/objectstack-ui · rules/record-page.md:48 and evals/record-page.json:24 still describe split as the default Open records choice · dedupe words: skills record-page split default",
        "carrier: seat · noted, not filed"
      ],
      "deviations": [
        "content/docs/ui/views.mdx (one paragraph on Open records) edited outside the declared file surface: a bounded in-place fix of the same claim; the seat amends the claim surface",
        "test files outside the listed surface touched because they drove the split mode: plugin-detail RecordPageColumns.enlargedEscapeInPane-27524, app-shell RecordDetailView.topBar-27524, ObjectView.recordCountFooter-10636, objectListTitle-27950, titleViewSwitcher-27594, viewRefusal-12112, phoneRecordPage-27058; four test files renamed from split to drawer names",
        "dogfood battery ran as four vitest --shard legs under the lock, not one pnpm --filter @objectstack/dogfood test call, because a foreground call is capped at 600 s and the brief requires foreground posture; the four legs cover all 387 files",
        "the derived gate sweep ran at 407e38cf, before two clean main merges; the touched tests and type-check were re-run at the final head",
        "screenshots: a temporary console Vite dev server against examples/app-crm (objectstack dev --seed-admin --fresh); the before state came from git restore of the 21 ui src files to the base in the worktree, then restored to HEAD; both servers stopped and git status clean afterwards"
      ],
      "line_budget": "48 files, +1169 / -1488 = 2657 changed lines without rename detection (46 files, +854 / -1173 = 2027 with renames); under the 3000-line size check",
      "files_changed": [
        ".changeset/28915-record-open-drawer-default.md",
        "content/docs/frontend/plugins/plugin-view.mdx",
        "content/docs/ui/views.mdx",
        "ui/packages/app-shell/src/utils/recordOpenPreference.test.ts",
        "ui/packages/app-shell/src/utils/recordOpenPreference.ts",
        "ui/packages/app-shell/src/views/ObjectView.objectListTitle-27950.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.phoneRecordPage-27058.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.recordCountFooter-10636.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.recordDrawer-27545.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.recordOpenDisplay-26681.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.recordOpenPreference-26677.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.titleViewSwitcher-27594.test.tsx",
        "ui/packages/app-shell/src/views/ObjectView.tsx",
        "ui/packages/app-shell/src/views/ObjectView.viewRefusal-12112.test.tsx",
        "ui/packages/app-shell/src/views/RecordDetailView.topBar-27524.test.tsx",
        "ui/packages/app-shell/src/views/objectViewRecordNavigation.ts",
        "ui/packages/app-shell/src/views/objectViewRecordOverlay.tsx",
        "ui/packages/app-shell/src/views/recordDrawerStack.tsx",
        "ui/packages/components/src/__tests__/chrome-i18n-no-provider-fallback.test.tsx",
        "ui/packages/components/src/__tests__/navigation-overlay-close-i18n.test.tsx",
        "ui/packages/components/src/__tests__/navigation-overlay-drawer-27545.test.tsx",
        "ui/packages/components/src/__tests__/navigation-overlay-field-escape-28156.test.tsx",
        "ui/packages/components/src/__tests__/navigation-overlay-split-27545.test.tsx",
        "ui/packages/components/src/__tests__/record-list-face-27545.test.tsx",
        "ui/packages/components/src/__tests__/record-top-bar-27524.test.tsx",
        "ui/packages/components/src/custom/index.ts",
        "ui/packages/components/src/custom/navigation-overlay.tsx",
        "ui/packages/components/src/custom/record-list-face.tsx",
        "ui/packages/i18n/src/locales/ar.ts",
        "ui/packages/i18n/src/locales/de.ts",
        "ui/packages/i18n/src/locales/en.ts",
        "ui/packages/i18n/src/locales/es.ts",
        "ui/packages/i18n/src/locales/fr.ts",
        "ui/packages/i18n/src/locales/ja.ts",
        "ui/packages/i18n/src/locales/ko.ts",
        "ui/packages/i18n/src/locales/pt.ts",
        "ui/packages/i18n/src/locales/ru.ts",
        "ui/packages/i18n/src/locales/zh.ts",
        "ui/packages/plugin-detail/src/__tests__/RecordPageColumns.enlargedEscapeInPane-27524.test.tsx",
        "ui/packages/plugin-grid/src/ObjectGrid.tsx",
        "ui/packages/plugin-grid/src/__tests__/ObjectGrid.recordDrawerList-27545.test.tsx",
        "ui/packages/plugin-grid/src/__tests__/ObjectGrid.recordPaneFace-27545.test.tsx",
        "ui/packages/plugin-list/src/ListView.tsx",
        "ui/packages/plugin-list/src/__tests__/ListView.recordDrawerCount-27545.test.tsx",
        "ui/packages/plugin-list/src/__tests__/ViewSettingsPopover.recordOpen-26681.test.tsx",
        "ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx"
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Seat review · 2026-11-02T08:06Z · PR #29108 at aaa5cdb7: contract review (TIER_DEFAULT) PASS 6572157203 and ACCEPT 6572168862. It goes to the merge queue now. Findings filed: #29109 and #29110.


    Generated by Claude Code

  7. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Landed · 2026-11-02T09:20Z · PR #29108 merged through the merge queue as ea150b7f. Records: contract review (TIER_DEFAULT) PASS 6572157203 and ACCEPT 6572168862, both at aaa5cdb7.

    probe before (ea150b7f~1) now (origin/main)
    DEFAULT_RECORD_OPEN_PREFERENCE: RecordOpenPreference = 'drawer' in app-shell/src/utils/recordOpenPreference.ts 0 1
    RecordOpenPreference = 'split' | 'drawer' | 'page' in the same file 1 0
    RecordListFaceProvider in components/src/custom/index.ts (one of the seven retired exports) 1 0
    recordOpenSplit in i18n/src/locales/en.ts 1 0

    The card closed through Fixes. pm:dispatched comes off with this note. Follow-ups are now orderable: #29109 (domain:ui#1, sidebar fold threshold) and #29110 (domain:ui#3, skills record-page). domain:ui#1's #28950 and #29074, and domain:ui#4's #29175, merge main now.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:uiDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions