Repository navigation
Closed
Labels
area:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchdomain:uiDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpriority:p1High: required for production / M2High: required for production / M2
Description
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Filed from the record-page epic #26676 as a sub-issue (the maintainer, 2026-10-29: 「另立两张 ui 卡:侧栏窄窗自动折叠、…」; earlier, looking at Attio on a narrow pane: 「窄屏幕左侧菜单自动折叠,点击弹出,这个你也可以参考」). It is console shell work, not record-page anatomy; it makes #27545's default split fit on common laptop windows.
Source (main 273137d227)
ui/packages/app-shell/src/layout/ConsoleLayout.tsxusesuseIsMobile();ui/packages/components/src/ui/sidebar.tsxis the shadcn Sidebar withcollapsible: "offcanvas" | "icon" | "none"(defaultoffcanvas), a Sheet below the mobile breakpoint, and a resizable rail (200–480 px, remembered inlocalStorage) above it. Between the mobile breakpoint and any width the sidebar stays expanded, so a 1280 px window leaves 1024 px of content — below what the split (list ≥ 440 + pane 720 = 1160) needs, which Record drawer v4: a bounded peek over the list — md cap instead of the field-count bucket, no dim overlay, the list stays readable and clickable, ⤢ maximizes in place at the same URL; the full page is reached only from the row ↗ and the header ⋯ #27545 then handles by falling back to the overlay drawer.- Attio collapses its sidebar to a single icon on narrow windows and expands it as an overlay on click; Twenty keeps a collapsible rail.
Target
- Auto-collapse below a window width of 1100 px: the sidebar renders as the icon rail (
collapsible="icon", the existing--sidebar-width-icon), the content area takes the rest; above 1100 px the sidebar behaves as today. The threshold is one named constant beside the record page's 1120 / 760 ones, not a magic number. - Click to expand as an overlay: clicking the rail (or the sidebar toggle,
⌘Bas today) expands the full sidebar OVER the content, not pushing it; choosing a navigation item, clicking outside, or Esc collapses it again. Hover alone does not expand. - Reader override, remembered: a reader who expands the sidebar and pins it (the existing toggle in the expanded state) keeps it expanded below 1100 px for that browser; stored where the rail width is stored today. The mobile Sheet below 768 px is unchanged.
- No metadata key; no spec change; the app's navigation items are untouched.
File surface
ui/packages/app-shell/src/layout/ConsoleLayout.tsx, ui/packages/app-shell/src/components/UnifiedSidebar.tsx (rail rendering of groups and items with tooltips), ui/packages/components/src/ui/sidebar.tsx (overlay expand mode), ui/packages/components/src/hooks/use-mobile.ts (a second breakpoint hook beside it), i18n for the tooltips, tests beside, changeset; ⛔ packages/spec/**.
Acceptance
- Tests: at 1280 px the sidebar mounts as the icon rail and the content width is the window minus the rail; a rail click expands an overlay that does not change the content width; a navigation choice / outside click / Esc collapses it; the pinned override persists across a reload; at 1440 px nothing changes; at 700 px the Sheet still mounts.
- Screenshots at 1280 (rail, overlay expanded) and 1440 (unchanged) on HotCRM, on a never-merged evidence branch.
- The epic seat verifies in the console preview before ACCEPT (maintainer: 「车队开发完后你审核效果」).
Metadata
Metadata
Assignees
Labels
area:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchdomain:uiDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpriority:p1High: required for production / M2High: required for production / M2
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Claim: PM loop round 1
Session:
session_01Utp6CbDAucNyQ4UtzCJKyhAccount:
os-billBranch:
claude/project-thread-oakpit(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27593Domain:
domain:uiSeat:
domain:ui#4File surface: app-shell
ConsoleLayout.tsx,UnifiedSidebar.tsx; a new breakpoint hook besidecomponents/src/hooks/use-mobile.ts; the overlay expand built OUTSIDEcomponents/src/ui/**(ui/AGENTS.md #7 No-Touch — a wrapper incomponents/src/custom/or in app-shell; stop and report before anysrc/ui/**edit);@object-ui/i18npacks for rail tooltips; tests beside; root.changeset/; ⛔packages/spec/**(stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT(dispatch-gates --tieronfec60e00: no path-derived mandate),effort: xhighClause-②: yes (widening)
Metadata-protocol: none
Responsibility: below 1100 px the sidebar mounts as the icon rail and expands as an overlay on click (nav choice / outside click / Esc collapses), a pinned reader override persists, ≥1100 px and the mobile Sheet unchanged; tests + screenshots on a never-merged evidence branch; the epic seat re-measures in the console preview before ACCEPT
Thread-read: none
Premise: holds
Serial constraints cleared: maintainer 2026-10-30 01:47Z/01:49Z dispatch-now (temporary concurrency raise); no open PR on ConsoleLayout/UnifiedSidebar known — re-check before push
Dispatched 2026-10-30T01:51Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CaPpqK4cmqg5XJnjsj
os-dev-report
{ "issue": 27593, "status": "done", "branch": "claude/project-thread-oakpit", "pr": "https://github.com/objectstack-ai/objectstack/pull/27893", "session": "session_01Utp6CaPpqK4cmqg5XJnjsj (card thread, mode:thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh)", "premise_still_valid": true, "summary": "Premise true on main ddab8b99: at 1280 px the expanded console sidebar (256 px) left 1024 px of content, under the split's 1160. Corrections measured on main: no resizable 200-480 px rail exists (the only remembered state is the primitive's sidebar_state open/closed cookie); the sidebar was already collapsible=icon with rail tooltips; useResponsiveSidebar already collapsed it once between 768 and 1023 px and wrote that into the cookie; no pin toggle existed. Now: below CONSOLE_SIDEBAR_RAIL_BELOW_WIDTH (1160 + 256 = 1416, derived) and above the phone breakpoint the sidebar mounts as the icon rail; a rail-background click, the app bar trigger or Cmd/Ctrl+B expands it over the content (panel z-40, a display:contents frame keeps the in-flow gap at rail width, content box unmoved); navigation, an outside press or an unhandled Esc folds it; 'Keep sidebar open' (workspace preference console.sidebar.keepOpen, one new i18n key sidebar.keepOpen in ten packs) keeps the wide-window sidebar on a narrow window; the wide-window open state is stashed (os:console-sidebar:wide-open) and handed back, so the fold no longer overwrites it. New components export useIsViewportBelow (Clause-2 yes, widening). No edit under components/src/ui/**.", "files_changed": [ ".changeset/27593-console-sidebar-narrow-rail.md", "ui/packages/app-shell/src/chrome/KeyboardShortcutsDialog.wiredOnly-11674.test.tsx", "ui/packages/app-shell/src/hooks/__tests__/useResponsiveSidebar.test.tsx", "ui/packages/app-shell/src/hooks/useResponsiveSidebar.ts", "ui/packages/app-shell/src/layout/ConsoleLayout.tsx", "ui/packages/app-shell/src/layout/UnifiedSidebar.tsx", "ui/packages/app-shell/src/layout/__tests__/UnifiedSidebar.railOverlay-27593.test.tsx", "ui/packages/app-shell/src/layout/__tests__/consoleSidebarRail.width-27593.test.tsx", "ui/packages/app-shell/src/layout/__tests__/consoleTopBar.height-12639.test.ts", "ui/packages/app-shell/src/layout/consoleSidebarRail.ts", "ui/packages/components/src/hooks/__tests__/use-viewport-below.test.tsx", "ui/packages/components/src/hooks/use-viewport-below.tsx", "ui/packages/components/src/index.ts", "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts" ], "tests": "New/rewritten 4 files: Test Files 4 passed (4), Tests 24 passed (24), lock VERDICT command-exit 0. Every existing file naming UnifiedSidebar / ConsoleLayout / useResponsiveSidebar / LocalizedSidebarTrigger / sidebar_state (135) + packages/i18n/ on 48346663: 2 failed | 223 passed (225) files; the 2 were the pins this PR updates (KeyboardShortcutsDialog.wiredOnly-11674, consoleTopBar.height-12639), 17/17 after the update. On merged head bc7935f4 after rebuilding i18n + components: type-check components + app-shell (tsc --noEmit + tsconfig.test.json) exit 0; 4 new files + 2 pins + LocalizedSidebarTrigger.appBar-12429 + packages/i18n/: Test Files 98 passed (98), Tests 1428 passed | 13 skipped, VERDICT command-exit 0. Ablations via scripts/ablation-replace.mjs (anchor 1 -> 0, restored, git diff HEAD empty): frame gap class removed 1 failed | 17 passed; stash write removed 5 failed | 13 passed; inside-press check removed 1 failed | 17 passed. Browser (Chromium, examples/app-crm Contacts, branch fdb717ea): 1280 load rail gap 48 / content 48+1232; overlay panel 256 z 40, content 48+1232; 1440 unchanged 256+1184; 700 phone drawer. Evidence branch claude/issue-27593-evidence @ b86187c2, folder evidence/27593/.", "gates": "dispatch-gates --commands on bc7935f4: 35 derived, each recorded as `<command> :: exit 0` (all 35 exit 0, check-sdui-manifest and its --self-test included); --ran reconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. check:i18n-drift / check:i18n-keys / check:i18n-dead-keys exit 0; check:new-line-citations 0 new, exit 0. CI families: see PR check-runs.", "line_budget": "n/a — no ledgered file touched", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "deviations": [ "Threshold 1416 px (derived: split 1160 + sidebar 256), not the card's Target-1 1100 px: Target 1 contradicts Acceptance 1 (1280 folds, 1440 unchanged) and the title; agreed with the seat before implementing, written as a deviation in the PR's Acceptance notes for the epic seat to confirm at the preview.", "Two GitHub MCP reads (mcp__github__issue_read get + get_comments on 27593) made before reading this order, which forbids MCP; the card and comments were then read through REST. No MCP write.", "Commit 645bb025 is titled test(console) but also carries the railOverlay prop / enabled option that gate the overlay to ConsoleLayout; the branch fails force-push criterion 1, so history is left as is.", "Harness post-PR assignee/reviewer step skipped per the maintainer's routing rule; relay read-back shows no assignees.", "Screenshots taken on examples/app-crm (Contacts), not HotCRM: this container reaches only this repository." ], "mcp_calls": "4 — mcp__github__issue_read x2 (reads, see deviations); mcp__claude-code-remote__get_session x1 (session id lookup); mcp__claude-code-remote__subscribe_pr_activity x1 (PR 27893 event subscription, not a GitHub write)", "api_writes": "2 — relay pr_create (repository_dispatch -> POST /repos/objectstack-ai/objectstack/pulls, draft, read-back identical 12833 bytes, assignees none); this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/27593/comments). git pushes (designated branch, evidence branch) not counted.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — plugin-detail recordPageColumns.ts docblock derives its 1120 / 760 container floors from window examples with the sidebar expanded; the tiers are container-measured so they follow the fold, but the docblock's window arithmetic is now stale at 1280-1415 px. dedupe words: record page columns docblock window width sidebar expanded" ] }Report taken 2026-10-30T02:52Z.
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
This card is claimed by ui seat 4 and is not waiting in the queue. Its PR is #27893: green, NOT governed and
mergeable_stateclean. The PR had stayed draft only for the epic seat's preview check. The maintainer ruled at 10:39Z that the seat accepts and merges on its own. ACCEPT → PR #27893 comment 6520805116 · 2026-10-30T10:40Z. The PR is now marked ready with automerge on, and the card closes when it merges.Generated by Claude Code