You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Display menu: the layout row's five segments (表格 / 看板 / 日历 / 时间线 …) wrap their labels inside the 240 px popover; the row folds to icons with tooltips or the popover widens #26637
Walked on 2026-10-27 on the HotCRM opportunity list (/crm_opportunity, zh-CN, 1149 px): the Display popover's first row is now a segmented control 「布局 | 表格 | 看板 | 日历 | 时间线」 (the layouts the object offers). In the 240 px popover the five icon + label segments do not fit: 「表格」「看板」「日历」「时间线」 each break onto two lines and the row is twice its height; in en the labels are longer still.
Target
The layout row shows icons only when the segments would wrap (a measured fold, not a count), each with a tooltip and an accessible name; the active segment keeps its label.
Or the popover is 300 px wide on the list surfaces that offer four or more layouts; the card picks one and says why.
A test with five layouts asserts no segment label wraps at the popover's width.
File surface
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx (the layout row), tests beside.
Acceptance
Screenshots of the Display popover on an object with five layouts, zh-CN and en.
pnpm --filter @object-ui/plugin-list test green.
Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff from the 2026-10-27 supplementary pass on objectstack main f9867020c6 (the source console at :5180 against HotCRM 18.2.0, the maintainer's browser pane at 1149 × 507, zh-CN and en, dark and light). The maintainer asked, verbatim: 「补测的前 3 项立卡到 objectstack,只立不派。」— the first of the three (the Data pillar's 高级 dropdown) turned out to be the 2026-10-15 ruling B as designed (it flattens from a 1000 px content column), so two cards are filed.
Triage: audit line · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T12:01Z
⛔ Not a claim, ⛔ not a dispatch.
Triage: lands in the Display popover's layout row (ui/); rationale: p3 · domain:ui · area:records. Fold the segments to icons with tooltips when they would wrap, measured and not tied to a breakpoint, in every locale.
Claim: PM loop round 1
Session: session_01QsR2jTfvjNTaR29ehLk26T
Account: zhuangjianguo
Branch: claude/project-thread-vx54jd (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
Worktree: objectstack-issue-26637
Domain: domain:ui
Seat: domain:ui#4
File surface: ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx (the layout row), tests beside, one root changeset; ⛔ packages/spec/**, ⛔ widening the popover (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate; reason: the maintainer's standing rule 「只认领不需要 fable 的卡」, 2026-10-27T10:39Z), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the Display popover's layout row (plugin-list, this lane) wraps each segment label inside 240 px · the platform path that may cover it: none, the row is this component's own layout · reached by every list whose object offers four or more layouts (HotCRM opportunity, zh-CN and en)
Thread-read: 6441384848
Premise: holds (the card's walk on main f9867020c6; the layout row on origin/main 86ae47e1 has no measured fold, re-read at 2026-10-27T12:16Z)
Serial constraints cleared: #26613 (this seat) edits ListViewBlock.tsx, ListView.tsx and ListViewCompact.tsx in plugin-list, not ViewSettingsPopover.tsx; no open PR touches it (scan 2026-10-27T12:13Z)
Dispatched at 2026-10-27T12:16Z to the card thread on that branch; the order lives in the thread's opening message.
{
"issue": 26637,
"status": "done",
"branch": "claude/project-thread-vx54jd",
"pr": "#26696",
"session": "session_01QsR2jUfYgopbwA4FqJngRV",
"premise_still_valid": true,
"summary": "The Display popover's Layout row now wraps the host's layout control in a LayoutSlot (ViewSettingsPopover.tsx only) that measures the width the segments need with every label shown against the slot's own width, after every render and on resize. When they would not fit it sets data-layout-fold=icons and one class hides the words of every unselected role=tab; the selected segment keeps its label, and each tab keeps its existing aria-label and title as accessible name and tooltip (no locale key added). Measurement lifts the fold for one synchronous read so the row never oscillates; tabs no longer wrap, and the popover keeps w-80. Premise detail: the card says 240 px, main's popover is 320 px (w-80, measured in Chromium); the row still overflowed at 320 (slot 258 px zh-CN, 244 px en).",
"tests": "ecb5f58f: pnpm --filter @object-ui/plugin-list test --maxWorkers=2 under os-verify-lock: Test Files 164 passed (164), Tests 1650 passed (1650), VERDICT command-exit 0. New ViewSettingsPopover.layoutFold.test.tsx 5/5 (zh-CN walked row folds with names+titles kept and only the selected label shown; en folds; five layouts fold at popover width; same five do not fold in a 600 px slot and two layouts never fold; a row that fits again unfolds; zero width reads while folded). type-check: turbo run type-check --filter=@object-ui/plugin-list, tsc --noEmit plus tsc -p tsconfig.test.json (listFilesOnly names the new test), 49/49 tasks, exit 0. Ablations on dfbd4bf via scripts/ablation-replace.mjs (anchor 1 to 0, blob restored to HEAD, git diff HEAD empty): (1) layout rendered without LayoutSlot: 4 failed / 1 passed; (2) delete the fold-lift line before measuring: 4 failed with Maximum update depth exceeded. Chromium check (real components, console index.css compiled through @tailwindcss/postcss, which emits the fold rule): zh-CN, en, ja, de with four layouts fold to a 49 px row, selected label kept, every tab named and titled; en with Timeline picked keeps Timeline; zh-CN with two layouts keeps both labels; popover 320 px in every run. Screenshots in the project folder issue-26637/.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at ecb5f58: 34 commands, each run with exit captured before any pipe, all 34 exit 0; --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Includes pnpm --dir ui exec vitest run scripts/ (178 files passed, 2 skipped), check-sdui-manifest, check-changeset-no-major, check-closing-keyword-parity with this PR body as GITHUB_EVENT_PATH. check:partof-closing-keyword on the body: green. check:closing-target-claim needs the PR number: CI's pr-body-guards. PR check-runs at report time: 19 on ecb5f58, 17 in_progress, 2 skipped, none failed; mergeable_state blocked (draft, checks pending).",
"dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — relay stroke fw-20261027T130927Z-f1e4dd (run 40509588019): pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/26696/assignees [zhuangjianguo], read back identical 8851 bytes; then this os-dev-report comment via post-stamped. git push is not a REST write. Reviewer request on the PR not made: the platform asks for it via GitHub MCP and the order forbids MCP writes; the seat can add it.",
"open_questions": [
{
"question": "The fold reads the switcher's DOM shape (role=tab, aria-selected, words in a child span) instead of a prop, because the order keeps the fold inside the popover and ListView.tsx is held by #26613. Make it explicit later?",
"options": [
"A keep as is: the contract is written on the layout prop's doc comment; one host draws the row",
"B follow-up card: pass an icons-only flag through the layout render prop and let ViewSwitcherDropdown hide its own labels (touches ListView.tsx and ViewSwitcher.tsx)"
],
"recommendation": "A, because only ViewSwitcherDropdown fills the row today and B adds a prop with no second consumer; revisit if another host draws the row"
}
],
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: audit line · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T12:01Z⛔ Not a claim, ⛔ not a dispatch.
ui/); rationale: p3 ·domain:ui·area:records. Fold the segments to icons with tooltips when they would wrap, measured and not tied to a breakpoint, in every locale.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 1
Session:
session_01QsR2jTfvjNTaR29ehLk26TAccount:
zhuangjianguoBranch:
claude/project-thread-vx54jd(platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)Worktree:
objectstack-issue-26637Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx(the layout row), tests beside, one root changeset; ⛔packages/spec/**, ⛔ widening the popover (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT(dispatch-gates --tier: no path-derived mandate; reason: the maintainer's standing rule 「只认领不需要 fable 的卡」, 2026-10-27T10:39Z),effort: highClause-②: no
Metadata-protocol: none
Responsibility: the Display popover's layout row (plugin-list, this lane) wraps each segment label inside 240 px · the platform path that may cover it: none, the row is this component's own layout · reached by every list whose object offers four or more layouts (HotCRM opportunity, zh-CN and en)
Thread-read: 6441384848
Premise: holds (the card's walk on main
f9867020c6; the layout row on origin/main86ae47e1has no measured fold, re-read at 2026-10-27T12:16Z)Serial constraints cleared: #26613 (this seat) edits
ListViewBlock.tsx,ListView.tsxandListViewCompact.tsxin plugin-list, notViewSettingsPopover.tsx; no open PR touches it (scan 2026-10-27T12:13Z)Dispatched at 2026-10-27T12:16Z to the card thread on that branch; the order lives in the thread's opening message.
Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{
"issue": 26637,
"status": "done",
"branch": "claude/project-thread-vx54jd",
"pr": "#26696",
"session": "session_01QsR2jUfYgopbwA4FqJngRV",
"premise_still_valid": true,
"summary": "The Display popover's Layout row now wraps the host's layout control in a LayoutSlot (ViewSettingsPopover.tsx only) that measures the width the segments need with every label shown against the slot's own width, after every render and on resize. When they would not fit it sets data-layout-fold=icons and one class hides the words of every unselected role=tab; the selected segment keeps its label, and each tab keeps its existing aria-label and title as accessible name and tooltip (no locale key added). Measurement lifts the fold for one synchronous read so the row never oscillates; tabs no longer wrap, and the popover keeps w-80. Premise detail: the card says 240 px, main's popover is 320 px (w-80, measured in Chromium); the row still overflowed at 320 (slot 258 px zh-CN, 244 px en).",
"tests": "ecb5f58f: pnpm --filter @object-ui/plugin-list test --maxWorkers=2 under os-verify-lock: Test Files 164 passed (164), Tests 1650 passed (1650), VERDICT command-exit 0. New ViewSettingsPopover.layoutFold.test.tsx 5/5 (zh-CN walked row folds with names+titles kept and only the selected label shown; en folds; five layouts fold at popover width; same five do not fold in a 600 px slot and two layouts never fold; a row that fits again unfolds; zero width reads while folded). type-check: turbo run type-check --filter=@object-ui/plugin-list, tsc --noEmit plus tsc -p tsconfig.test.json (listFilesOnly names the new test), 49/49 tasks, exit 0. Ablations on dfbd4bf via scripts/ablation-replace.mjs (anchor 1 to 0, blob restored to HEAD, git diff HEAD empty): (1) layout rendered without LayoutSlot: 4 failed / 1 passed; (2) delete the fold-lift line before measuring: 4 failed with Maximum update depth exceeded. Chromium check (real components, console index.css compiled through @tailwindcss/postcss, which emits the fold rule): zh-CN, en, ja, de with four layouts fold to a 49 px row, selected label kept, every tab named and titled; en with Timeline picked keeps Timeline; zh-CN with two layouts keeps both labels; popover 320 px in every run. Screenshots in the project folder issue-26637/.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at ecb5f58: 34 commands, each run with exit captured before any pipe, all 34 exit 0; --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Includes pnpm --dir ui exec vitest run scripts/ (178 files passed, 2 skipped), check-sdui-manifest, check-changeset-no-major, check-closing-keyword-parity with this PR body as GITHUB_EVENT_PATH. check:partof-closing-keyword on the body: green. check:closing-target-claim needs the PR number: CI's pr-body-guards. PR check-runs at report time: 19 on ecb5f58, 17 in_progress, 2 skipped, none failed; mergeable_state blocked (draft, checks pending).",
"dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — relay stroke fw-20261027T130927Z-f1e4dd (run 40509588019): pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/26696/assignees [zhuangjianguo], read back identical 8851 bytes; then this os-dev-report comment via post-stamped. git push is not a REST write. Reviewer request on the PR not made: the platform asks for it via GitHub MCP and the order forbids MCP writes; the seat can add it.",
"open_questions": [
{
"question": "The fold reads the switcher's DOM shape (role=tab, aria-selected, words in a child span) instead of a prop, because the order keeps the fold inside the popover and ListView.tsx is held by #26613. Make it explicit later?",
"options": [
"A keep as is: the contract is written on the layout prop's doc comment; one host draws the row",
"B follow-up card: pass an icons-only flag through the layout render prop and let ViewSwitcherDropdown hide its own labels (touches ListView.tsx and ViewSwitcher.tsx)"
],
"recommendation": "A, because only ViewSwitcherDropdown fills the row today and B adds a prop with no second consumer; revisit if another host draws the row"
}
],
"out_of_scope_findings": []
}
Generated by Claude Code