Skip to content

fix(app): restore collapsing a checkout on the home session list - #1711

Open
chphch wants to merge 1 commit into
slopus:mainfrom
chphch:fix/restore-project-collapse
Open

fix(app): restore collapsing a checkout on the home session list#1711
chphch wants to merge 1 commit into
slopus:mainfrom
chphch:fix/restore-project-collapse

Conversation

@chphch

@chphch chphch commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

The home session list could be folded per project until c63c80ff rebuilt it around projects and worktrees: that commit replaced the project header the chevron lived on, and the collapse went with it. Nothing in the commit says it was meant to go — and the collapsedProjects local setting is still in the schema with nothing reading it any more, so whatever people had already folded is sitting there intact. This puts the toggle back, on the header the rebuild left us.

Because that header is now per checkout, a tap folds exactly the card it sits on. A project with two worktrees renders three sections, and folding all three from one chevron would hide sessions the user never pointed at — so each collapses on its own, and you can fold the worktrees you are not working in while the main checkout stays open. The primary checkout keys on the project id, which is the key the old code used, so a project someone had already collapsed comes back collapsed.

Two smaller decisions. The + button stays its own pressable beside the toggle, so starting a session in a project never folds it. And a collapsed header shows how many sessions it is hiding, since a folded card otherwise tells you nothing about what is inside.

Worth noting that #1706, filed two days before the rebuild and still open, was leaning on this: "Collapsing cards helps (and the collapsed state is nicely persisted)". That issue asks for something further — a switch that drops the grouping entirely — and this PR does not attempt it. It only restores what that issue was already building on.

Proof

Driven against the running app (standalone happy-server + Expo web + Playwright), on a project with a main checkout and two worktrees so the per-checkout behaviour is actually visible. Frames and the full assertion log are in the comment below; in short: folding the alpha worktree left the main checkout and beta expanded, folding the main checkout as well left beta still expanded, and a real page reload (performance.getEntriesByType('navigation')[0].type === "reload") brought that three-way state back. The persisted setting held exactly two keys — the bare project id and the project id plus the alpha path — and none mentioning beta.

pnpm typecheck is clean and vitest passes 922 tests, three of them new for the key derivation.

@chphch

chphch commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Proof — each checkout folds on its own

per-checkout collapse

One project, repo, with a main checkout and two worktrees (alpha, beta) — three WorkspaceSections under a single ProjectGroup container, holding 2 / 1 / 1 sessions. Five frames, in order:

# Action main / alpha / beta rows
1 nothing folded 2 / 1 / 1
2 fold alpha only 2 / 0 / 1 — alpha's header reads 1, the others untouched
3 also fold the main checkout 0 / 0 / 1 — two independent folds inside one card
4 reload the page 0 / 0 / 1 — same three-way state
5 unfold both 2 / 1 / 1

Captured against a standalone happy-server (PGlite) + Expo web, four sessions spawned through the daemon's control server, driven headlessly with Playwright. 39 assertions, 0 failures.

What was read, and what could have faked a pass

Row counts are workspaceCard DOM children cross-checked against the card's innerText. This react-native-web build emits no aria-expanded, so folded-ness was read from three signals that agreed at every frame: section child count, the chevron codepoint (U+F232 down / U+F23B forward, taken from the bundled @expo/vector-icons glyphmaps rather than assumed), and the visible session-row text.

Frame 4 is byte-identical to frame 3, which is what persistence looks like — so it was checked separately rather than assumed: a nonce stamped on window was gone afterwards and performance.getEntriesByType('navigation')[0].type === "reload", i.e. a real document navigation with a discarded JS realm. A fresh context with empty storage renders everything expanded, so the restored state is doing real work.

After frame 3 the persisted collapsedProjects held exactly two keys:

happy:["<machine>","…/cwd/repo"]
happy:["<machine>","…/cwd/repo"]\0…/cwd/repo/.dev/worktree/alpha

the bare project id for the main checkout, and that same id joined by a NUL to the alpha path — nothing mentioning beta. A per-project toggle would have written one key and folded the whole card.

A separate run on single-checkout projects covers the rest: folding one project leaves the other alone, and pressing + inside a card navigates to the composer without folding it (12 assertions, 0 failures).

Coverage is Expo web. projectWorkspaceCollapseKey and the per-section state are platform-independent, but native rendering is not exercised here.

The session list could be folded per project until the home list was
rebuilt around projects and worktrees, which replaced the project header
that carried the chevron. The `collapsedProjects` local setting outlived
it and is still in the schema, so the state people already had is intact
— nothing reads it any more.

This puts the toggle back on the header the rebuild left us. Because that
header is now per checkout, a tap folds exactly the card it sits on: a
project with three worktrees can hide the two it is not working in and
keep the third open. The primary checkout keys on the project id, the key
the old code used, so an existing collapsed project stays collapsed.

The `+` button stays its own pressable next to the toggle, so starting a
session in a project never folds it. A collapsed header shows how many
sessions it is hiding.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
@chphch
chphch force-pushed the fix/restore-project-collapse branch from 1cdb4a2 to fed8e97 Compare August 25, 2026 08:00
@chphch

chphch commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@bra1nDump — this restores something c63c80ff removed without saying why, and the removal has a third-party objection on record.

What went away

Before that commit the home list could be folded per project. c63c80ff rebuilt the list around projects and worktrees, and the header the chevron lived on went with it — the collapse was not replaced by anything, it just stopped existing. The commit body is empty, there is no linked PR or issue, and I could not find a discussion of it anywhere, so I am reading it as collateral of the rebuild rather than a decision. If it was deliberate, say so and I will close this.

Two things point the other way. #1706 (still open, not mine) asks for exactly this affordance, filed two days before the removal. And collapsedProjects is still in the local-settings schema with nothing reading it any more — whatever people had already folded is sitting there intact, so this PR brings their state back rather than starting from a clean slate.

Proof

per-checkout collapse

One project, repo, with a main checkout and two worktrees. Each of the three folds on its own — the toggle sits on the header the rebuild left us, which is now per checkout, so folding one card leaves the project's other checkouts open. Collapsed cards show the session count in place of the rows.

The key is projectWorkspaceCollapseKey(project.id, workspace.id), and the primary checkout keeps project.id unchanged so anything folded before the rebuild stays folded.

Rebased onto current main: mergeable, CI green. Happy to gate it behind a setting, or to fold the toggle into whatever shape you would rather the new header take.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant