Repository navigation
console list page: on desktop the table scrolls inside the page under a sticky header while the app bar, page header, view row and footer stay put; at 1024 the first and the actions column stick and a right-edge shadow says more columns follow #12463
Description
Filing gate ③, on the maintainer's word (chat, 2026-10-15, session session_019YFzJp4o8Ck4NsT1toC4UP, seat account os-bill): after the post-merge screenshots the maintainer said 「和你的设计图差距还是比较大,后续还有哪些任务你给我具体解释一下」, the seat listed the remaining gaps, and the maintainer answered 「同意开卡」. The design is the main and laptop boards of the reference page https://claude.ai/artifact/JCzrzHxTxzD4EEKCTtDaNA (main-1440.png, laptop-1024.png; the designer's notes: 「桌面端表格在页内滚动,表头吸顶」 and 「表格超出时横向滚动,首列与操作列 sticky,右缘滚动阴影提示还有列」).
Parent: objectstack-ai/objectstack#25945. Blocks nothing; nothing blocks it. Shares ListView.tsx with #12440 (the toolbar row) and the selection-bar card: this card touches the root and body wrappers (lines 4933 and 5634) and the data-table's scroll box, different regions; dispatchable in parallel; the second to land merges main again.
Reader who acts: the domain:ui lane's next dispatch, one dev round across @object-ui/app-shell, @object-ui/plugin-list and @object-ui/components, size M.
Dedupe (MCP search_issues, scope objectstack-ai/objectui, all states, read 2026-10-15T08:58Z): "list table scrolls inside the page sticky header pinned footer desktop page scroll sticky first column scroll shadow" → 0; the two sibling queries in the same run returned 16 and 3 hits, so the channel was live. None is this card.
The problem
On the Leads list at 1440×1000 the console's main area is the scroll container (ConsoleLayout's SidebarInset, overflow-y-auto): scrolling the rows moves the page header, the view row and the toolbar away, and the record-count footer sits at the end of the content. The design keeps the chrome in place and scrolls the table inside the page, with the table header sticky under the toolbar and the footer (record count) pinned at the bottom; at 1024 the table scrolls sideways with the first column and the actions column sticky and a shadow at the right edge while more columns remain. The data-table's header already declares sticky top-0 (it sticks only inside a scrolling box that is the table's own); the wrappers above it are overflow-hidden without a bounded height chain, so there is no such box.
Readings (objectui origin/main a8e5b73, read 2026-10-15T08:58Z)
packages/app-shell/src/layout/ConsoleLayout.tsxline 188: the main inset is!p-0 overflow-y-auto overflow-x-hidden, the page's scroll container today.packages/app-shell/src/views/ObjectView.tsxline 3886: the page rooth-full flex flex-col bg-background min-w-0 overflow-hidden; lines 4167, 4178, 4225:flex-1 overflow-hidden relativewrappers around the list;ListViewmounted at 3744.packages/plugin-list/src/ListView.tsxline 4933: the list rootflex flex-col h-full … overflow-hidden; line 5634: the view bodyflex-1 min-h-0 … overflow-hidden; the21 recordsfooter after it.packages/components/src/renderers/complex/data-table.tsxline 2883:TableHeader className="sticky top-0 bg-background z-10"; the table's own box and its horizontal scroll are what this card bounds;frozenColumnsandmeasuredStickyLefts(the sticky-left machinery) exist from feat(list): Filter · Sort · Display · Search toolbar, width-fitted view tabs, one leading row cell, one-row page header #12436's leading-cell work.
What to build
- Desktop (
lgand up), grid view: the chain from the main inset down to the data-table's box gives the table a bounded height (min-h-0/flex-1through the wrappers,overflow-autoon the table's box), so the table scrolls inside the page; the app bar, page header, view row and toolbar stay put; the existingsticky top-0header now sticks; the list footer stays visible below the box. The main inset no longer scrolls on this page (itsscrollTopstays 0). - Horizontal: when columns exceed the width, the table box scrolls sideways; the leading cell plus the first data column, and the actions column, are sticky (the existing frozen-column machinery,
frozenColumns: 1as the console's default for the grid when the host passes none); a right-edge shadow shows whilescrollLeft + clientWidth < scrollWidthand none at the end. - Other visualizations (kanban, calendar, gallery, …) keep their own scrolling as today; the phone keeps today's page scroll.
Acceptance
ListView/ data-table test: with 50 rows in a 600 px tall host, the table's box hasoverflow-y: autoand the rows scroll inside it while the toolbar row's bounding box does not move; the footer's record count is in the DOM below the box and visible.- Browser reading by the landing seat at 1440×800 on the HotCRM Leads list (21 rows): scrolling over the rows moves only the rows; the app bar, page header, view row, toolbar and
21 recordsfooter keep their y; the console main'sscrollTopreads 0. At 1024: the Full Name column and the actions column stay in place while scrolling sideways; a right-edge shadow is visible atscrollLeft0 and absent at the far right. pnpm testfrom the repo root green on the affected files; a changeset (minor) for each published package touched.
Out of scope
- Row virtualization; column widths; the other visualizations' scrolling; the phone.
Attribution: written by the domain:ui seat in session session_019YFzJp4o8Ck4NsT1toC4UP (account os-bill) on the maintainer's words quoted above.
Activity
objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 1
Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12463-list-inpage-scrollWorktree:
objectui-issue-12463Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/layout/ConsoleLayout.tsx(the main inset's overflow,:188, only as far as the list page needs),packages/app-shell/src/views/ObjectView.tsx(the page root and the list wrappers' height chain,:3886,:4167,:4178,:4225ata8e5b73; ⛔ not theViewTabBarrows, the header actions or the toolbar handlers),packages/plugin-list/src/ListView.tsx(the list root and view body wrappers,:4933and:5634; ⛔ not the toolbar row or the bulk bar),packages/components/src/renderers/complex/data-table.tsx(the table's scroll box, the sticky first and actions columns, the right-edge shadow), the console's gridfrozenColumnsdefault where the host passes the grid its props, the tests beside each, and one.changeset/12463-*.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate)Clause-②: no (no new prop or key is planned; if one lands on a published component's props, the dev measures it and the line is corrected to yes)
Responsibility:
n/a — not a defect cardThread-read: none
Serial constraints cleared: hot files shared with in-flight cards, each in a different region, which the card's own filing note declares parallel ("the second to land merges
mainagain", a merge, never a rebase): objectui#12440 (this seat,ListView.tsxtoolbar row andObjectView.tsxViewTabBarrows), seat 1's objectui#12418 (ObjectView.tsxhandlers at:2381,:2748,:3432,:3755), seat 1's objectui#12462 (ObjectView.tsxlist_toolbaractions,ListView.tsxbulk bar:1902–:1957), and objectui#12427's PR #12443 (ObjectView.tsxpage-header actions). This seat lands its own two in whichever order they turn green and mergesmaininto the second.ConsoleLayout.tsxanddata-table.tsxhave no in-flight claim.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 12463,
"status": "done",
"branch": "claude/issue-12463-list-inpage-scroll",
"pr": "#12479",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "Premise partly disproved, then fixed where it holds. Browser reading (Chromium, scratch harness: real AppShell + ObjectView wrapper classes + real ListView/object-grid/data-table, 50 rows; no backend in this container, so not the full console): with no banner, origin/main already scrolls the rows inside the data-table box under a sticky thead, footer in view, inset scrollTop 0; frozenColumns already defaults to 1 in object-grid and the actions column is already auto-pinned right (A1 and A2 disproved). The real defect: with any banner above the route (draft-preview, unpublished-app, notification), the h-full list page is 100% of the inset plus the banner, so the inset scrolls as a second scroller and the footer sits below the fold. Fix 1, ConsoleLayout: from lg up the inset is lg:flex lg:flex-col lg:[&>*]:min-h-0, with the banners in one shrink-0 box. Natural-height pages (search results, marketplace) keep the same inset scroll height; the phone stays block. Fix 2, data-table: a pointer-events-none right-edge shadow overlay beside the scroll box, shown while scrollLeft+clientWidth is less than scrollWidth, at the seam before the right-pinned columns and clear of the scrollbars. It replaces the static inset shadow, which the cells painted over. ObjectView.tsx and ListView.tsx are unchanged. Consequence to weigh: a kanban or calendar page with a banner also stops overflowing the inset by the banner height; the views' own scrolling is untouched.",
"tests": "Head fe579e9 (after merging origin/main d25585c): vitest packages/app-shell/src/layout/ + packages/components/src/renderers/complex/tests/ + ListView.inPageScroll-12463 = 99 files / 705 tests passed (lock VERDICT command-exit 0). Before the merge: components/src/renderers/complex/ + plugin-list/ = 160 files / 1626 passed; the 32 tests outside src/layout that mount ConsoleLayout + 2 ObjectView tests = 34 / 316 passed. New pins: data-table-scroll-shadow-12463 (4), ListView.inPageScroll-12463 (2), ConsoleLayout.inPageScroll-12463 (3). Ablation on committed HEAD via objectstack ablation-replace.mjs (anchor 1->0, blob moved, restored blob == HEAD, git diff HEAD empty; no dist involved, vitest aliases src): end-of-scroll condition mutated -> shadow test red (1 failed / 3 passed); inset lg classes removed -> ConsoleLayout test red (1 failed / 2 passed). type-check components/plugin-list/app-shell after the closure build: exit 0. Browser before/after table is in the PR body. NOT MEASURED: full packages/app-shell/src/views/ (~930 files, over the foreground cap; no file under it changed), declared to CI. NOT MEASURED: HotCRM Leads browser acceptance at 1440x800/1024, left to the landing seat.",
"gates": "phantom-deps 0, self-import 0, unreferenced-sources 0, doc-example-readers 0, handler-key-reads 0, side-effects-array 0, element-data-source-declaration 0, spec-symbols 0, action-forward-parity 0, designer-field-key-parity 0, icon-record-names 0, i18n-keys 0, i18n-drift 0, i18n-designer-parity 0, control-bytes 0, new-line-citations 0, check-changeset-fixed 0, check-changeset-presence 0, check-changeset-no-major 0, spec-floors 1 (known red on main, objectui#12334). Lint narrowed to the 5 changed files (eslint --no-inline-config --format json, 5 files): 1 error + 39 warnings in data-table.tsx, the same counts as the base blob linted the same way (pre-existing react-hooks/static-components, far above the edit); 3 pre-existing warnings in ConsoleLayout.tsx; 0 in the new tests. Repo-wide pnpm lint belongs to CI. CI: in_progress (not awaited).",
"line_budget": "n/a (no skills/** touched)",
"deviations": "Changed ConsoleLayout's children region (one shrink-0 wrapper div around the three banners) in addition to the inset className. Same file, needed so the banners do not shrink in the new flex column. No browser reading of the real console: no backend is installed in this container, so the readings come from a faithful scratch harness, deleted afterwards. No labels written: objectui has no label gate, and the dispatch named none.",
"files_changed": [".changeset/12463-list-inpage-scroll.md", "packages/app-shell/src/layout/ConsoleLayout.tsx", "packages/app-shell/src/layout/tests/ConsoleLayout.inPageScroll-12463.test.tsx", "packages/components/src/renderers/complex/data-table.tsx", "packages/components/src/renderers/complex/tests/data-table-scroll-shadow-12463.test.tsx", "packages/plugin-list/src/tests/ListView.inPageScroll-12463.test.tsx"],
"mcp_calls": "0",
"api_writes": "2 relay strokes: fleet-write pr_create (POST /repos/objectstack-ai/objectui/pulls draft + POST issues/12479/assignees), fleet-write comment (POST /repos//issues/12463/comments); plus git pushes of the branch (not REST)",
"open_questions": [
{ "question": "Should the banner-height page overflow fix also apply to kanban, calendar and other non-grid pages? It does today, because it lives in the shell.", "options": ["A keep: the shell bounds every self-bounded page below the banners; the views' own scrolling is unchanged", "B scope it to the grid view: needs ObjectView to signal its view type to the shell, a new seam"], "recommendation": "A. It fixes the same footer-below-the-fold defect on every bounded page and adds no new seam. B adds a host signal with no demand for it, which the startup-scope axis argues against." }
],
"out_of_scope_findings": ["carrier: none (承接者:无) · noted, not filed: the card's 'Readings' were class-name inferences; a browser reading shows the table already self-scrolls without a banner (recorded in PR Acceptance notes)"]
}
objectstack-fleet commentedon Oct 15, 2026
Review: ACCEPT — objectui PR #12479 ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T11:54ZReviewed on GitHub at head
cdd1668, against the card's "What to build" and Acceptance, the design targets in the card body, and the claim (6189779375), not against the dev's report.main. Its body opensFixes objectstack-ai/objectui#12463, the only closing keyword, followed byClause-②: no. The governed sweep reads NOT governed, 6 files.AppShell,ListView,object-gridanddata-table, 50 rows),mainalready scrolls the rows inside the table box under a sticky header when no banner is shown.frozenColumns, 1 by default inobject-grid) and the row-actions column were already pinned.h-fulllist page then took 100% of the inset on top of the banner, so the inset scrolled as a second scroller and the record-count footer sat below the fold.ConsoleLayout:lgup the inset is a flex column.shrink-0box.console-route(h-full lg:min-h-0). That slot is the only inset child allowed below its content height.lg:[&>*]:min-h-0forced every inset child shrinkable, which squeezes a natural-height page root to the viewport. The dev measured that removing it outright reopens the defect, because the inset's real child is theh-fullRouteFader, whose automatic minimum height is its own 100%. The class therefore moved to the one route slot. The harness readings at 1440×800 with a 40 px banner:scrollTop0, the table box scrolls, the footer is in view at y 767.sticky top-0bar): the page root keeps its full height (2100), and the sticky bar stays at the inset top after scrolling 1200.data-table: apointer-events-noneright-edge shadow is drawn beside the scroll box whilescrollLeft + clientWidth < scrollWidth, at the seam before the right-pinned columns and clear of the scrollbars. It is gone at the far right and absent in a grouped sub-table. It replaces the static inset shadow, which the cells' backgrounds covered. Mutating the end-of-scroll condition turns its pin red.ObjectView.tsxandListView.tsx, so this PR is disjoint from PR feat(list): view tabs share the list toolbar row — ListView toolbarLeading host prop (objectui#12440) #12473 and PR feat(app-shell): a list's sort, column layout, filters and tab order are the user's own, not the shared view's (objectui#12418) #12471 on those hot files. No prop, schema key, export or language-pack key is added, soClause-②: noholds.@object-ui/app-shell: minor,@object-ui/components: minor.src/layout/plus the 3 new pins give 517/517 under the lock. The app-shell type-check exits 0. The earlier head's runs covered the componentscomplex/renderers andplugin-list/(1626 tests). The battery exits 0.filter=latest, 37 runs), all 16 test shards included. The one red is the advisorySpec Main Shape Gate. Its annotations name onlypackages/types/src/layout.ts(PageNodeSchema.kind, objectui#12464, being fixed by this seat), a file this PR does not touch. It is red onmaintoo. The workflow's header says it is advisory and does not subscribe tomerge_group, so it is not in the queue's required set; this comment is the record.Next:
pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-15T12:08Zmainc950345. The card closedcompletedby the PR'sFixes objectstack-ai/objectui#12463, which is the only closing keyword. No other card closed with it.origin/main, all 6 files the PR touches are blob-identical to the accepted headcdd1668. They areConsoleLayout.tsx,data-table.tsx, the three console list page: on desktop the table scrolls inside the page under a sticky header while the app bar, page header, view row and footer stay put; at 1024 the first and the actions column stick and a right-edge shadow says more columns follow #12463 pin files and.changeset/12463-list-inpage-scroll.md.pm:dispatchedis removed in the same stroke as this comment.Generated by Claude Code
feat(console): list table scrolls inside the page below banners; data…