Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

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

Closed

Description

@objectstack-fleet

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)

  1. packages/app-shell/src/layout/ConsoleLayout.tsx line 188: the main inset is !p-0 overflow-y-auto overflow-x-hidden, the page's scroll container today.
  2. packages/app-shell/src/views/ObjectView.tsx line 3886: the page root h-full flex flex-col bg-background min-w-0 overflow-hidden; lines 4167, 4178, 4225: flex-1 overflow-hidden relative wrappers around the list; ListView mounted at 3744.
  3. packages/plugin-list/src/ListView.tsx line 4933: the list root flex flex-col h-full … overflow-hidden; line 5634: the view body flex-1 min-h-0 … overflow-hidden; the 21 records footer after it.
  4. packages/components/src/renderers/complex/data-table.tsx line 2883: TableHeader className="sticky top-0 bg-background z-10"; the table's own box and its horizontal scroll are what this card bounds; frozenColumns and measuredStickyLefts (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

  1. Desktop (lg and 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-1 through the wrappers, overflow-auto on the table's box), so the table scrolls inside the page; the app bar, page header, view row and toolbar stay put; the existing sticky top-0 header now sticks; the list footer stays visible below the box. The main inset no longer scrolls on this page (its scrollTop stays 0).
  2. 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: 1 as the console's default for the grid when the host passes none); a right-edge shadow shows while scrollLeft + clientWidth < scrollWidth and none at the end.
  3. 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 has overflow-y: auto and 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 records footer keep their y; the console main's scrollTop reads 0. At 1024: the Full Name column and the actions column stay in place while scrolling sideways; a right-edge shadow is visible at scrollLeft 0 and absent at the far right.
  • pnpm test from 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

  1. added
    enhancementNew feature or request
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    and removed on Oct 15, 2026
  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12463-list-inpage-scroll
    Worktree: objectui-issue-12463
    Domain: domain:ui
    Seat: domain:ui#2
    File 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, :4225 at a8e5b73; ⛔ not the ViewTabBar rows, the header actions or the toolbar handlers), packages/plugin-list/src/ListView.tsx (the list root and view body wrappers, :4933 and :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 grid frozenColumns default 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/objectui reads 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 card
    Thread-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 main again", a merge, never a rebase): objectui#12440 (this seat, ListView.tsx toolbar row and ObjectView.tsx ViewTabBar rows), seat 1's objectui#12418 (ObjectView.tsx handlers at :2381, :2748, :3432, :3755), seat 1's objectui#12462 (ObjectView.tsx list_toolbar actions, ListView.tsx bulk bar :1902–:1957), and objectui#12427's PR #12443 (ObjectView.tsx page-header actions). This seat lands its own two in whichever order they turn green and merges main into the second. ConsoleLayout.tsx and data-table.tsx have no in-flight claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    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)"]
    }

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12479 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-15T11:54Z

    Reviewed 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.

    • Shape: the PR is a draft against main. Its body opens Fixes objectstack-ai/objectui#12463, the only closing keyword, followed by Clause-②: no. The governed sweep reads NOT governed, 6 files.
    • The premise, measured and partly disproved:
      • In a Chromium harness (the real AppShell, ListView, object-grid and data-table, 50 rows), main already scrolls the rows inside the table box under a sticky header when no banner is shown.
      • The first column (frozenColumns, 1 by default in object-grid) and the row-actions column were already pinned.
      • The real defect needs a banner above the route (the draft-preview bar, the unpublished-app bar, or a banner notification). The h-full list 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.
    • Fix 1, ConsoleLayout:
      • From lg up the inset is a flex column.
      • The banners sit in one shrink-0 box.
      • All route content sits in one block route slot, console-route (h-full lg:min-h-0). That slot is the only inset child allowed below its content height.
    • Patch round: the seat's review found that the first head's lg:[&>*]:min-h-0 forced 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 the h-full RouteFader, 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:
      • List page: inset scrollTop 0, the table box scrolls, the footer is in view at y 767.
      • Natural-height page (2000 px content plus a sticky top-0 bar): the page root keeps its full height (2100), and the sticky bar stays at the inset top after scrolling 1200.
      • Phone (390 wide): unchanged.
      • A pin refuses a child-variant class on the inset; re-adding it turns the pin red.
    • Fix 2, data-table: a pointer-events-none right-edge shadow is drawn beside the scroll box while scrollLeft + 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.
    • The dev's open question, ruled by the seat (A, not re-rulable): the bound stays in the shell for every self-bounded page (kanban and calendar pages with a banner stop overflowing too); no view-type seam.
    • Untouched: ObjectView.tsx and ListView.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, so Clause-②: no holds.
    • Changeset: @object-ui/app-shell: minor, @object-ui/components: minor.
    • Evidence: 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 components complex/ renderers and plugin-list/ (1626 tests). The battery exits 0.
    • Acceptance note (not filed): the browser acceptance on the HotCRM Leads list at 1440×800 and 1024 is the maintainer's, against the prototype on tracking: console list page and shell layout refresh after the 2026-10-15 prototype — parent of #12423, #12427, #12440 and #12429, with the items not yet carded objectstack#25945. The harness is a faithful stand-in, not the full console.
    • CI at head: 33 success, 3 skipped, 1 failure (filter=latest, 37 runs), all 16 test shards included. The one red is the advisory Spec Main Shape Gate. Its annotations name only packages/types/src/layout.ts (PageNodeSchema.kind, objectui#12464, being fixed by this seat), a file this PR does not touch. It is red on main too. The workflow's header says it is advisory and does not subscribe to merge_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

  5. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-15T12:08Z


    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:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions