Repository navigation
fix(components): keep the opened-by tree on active sidebar rows - #442
Conversation
The leading slot held one node, and status won it: a working, unread, or waiting child dropped its ├/└ and an active opener dropped its disclosure. That traded away exactly the rows a user is tracking — a group of opened Sessions read as a group right up to the moment any of it started running, then read as a flat list with a stray indent. Status moves to the row's END slot instead, where it replaces the resting metric cluster (line diff, Mergeable, worktree glyph, PR icon, mobile time) for as long as it lasts. The leading slot now draws the tree unconditionally, so nesting is a stable fact about the list rather than a function of activity, and the right edge stays a single 14px mark with more room for the title. The metrics it stands in for are still in the desktop hover info card. Applies to every desktop sidebar row surface through the shared `SidebarRowEndSlot`. The mobile chat rows keep their own leading-node rule for now — a checkbox, an out-of-button chevron, and the edge-back swipe zone share that slot there. Model: claude-opus-5[1m]
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54c2c69c3e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const restContent = hasSessionRowStatus({ | ||
| isWaitingPermission, | ||
| isWorking, | ||
| hasUnreadMessages, | ||
| }) ? ( |
There was a problem hiding this comment.
Preserve the private-sharing indicator during activity
When a private task is also unread, working, or waiting for permission, this branch discards the entire restIcon; both task-list.tsx and sidebar-updated-task-list.tsx place SessionSharingIndicator inside that value. Consequently, these common states—especially a never-opened row, which is unread—remove the list's lock and its “who can open this conversation” tooltip, obscuring the session's access scope along with the intentionally suppressed metrics. Keep the privacy indicator outside the replaceable metric cluster so it remains visible beside the activity status.
Useful? React with 👍 / 👎.
Related issue
Problem / pressure
The sidebar's leading slot held exactly one node, and status won it. A
working, unread, or waiting-permission child dropped its
├/└connectors, and an active opener dropped its disclosure chevron. So the
opened-by tree disappeared on precisely the rows a user is tracking: a
group of opened Sessions read as a group right up to the moment any of it
started running, and then read as a flat list with a stray indent.
Reported from the desktop sidebar, where several running rows sat between
nested idle ones and the nesting was unreadable.
Summary
Status moves from the row's leading slot to its END slot
(
SidebarRowEndSlotinsidebar-row-shared.tsx), and the leading slotnow draws the opened-by tree unconditionally.
While a status shows, it REPLACES that slot's whole resting cluster —
line diff,
Mergeable, worktree glyph, PR icon, and the mobile/chatrelative time — so the right edge is a single 14px mark and the title
gets the width back. Those metrics are still one hover away in the
desktop info card. A row that is idle and read is unchanged.
Applies to every desktop sidebar row surface through the one shared
component: Workspace groups (
session-list.tsx), local-project sections(
loro-app-sidebar.tsx), the Updated / Pinned list(
sidebar-updated-session-list.tsx), and the two legacy task-listrenderers that share the same primitives.
The mobile chat rows keep their own leading-node rule for now: a
selection checkbox, an out-of-button chevron, and the edge-back swipe
zone all share that slot there, so it is a separate change.
mobile/AGENTS.mdstill documents the old rule, and the scopedAGENTS.mdnow says not to assume the two match.Before / after
◌ Audit archive…and● Check mobile…render with NO trunk or elbow — the two nested rows in the middle of the group look top-level, while their idle siblings keep├/└. The working row still shows4m +38 -4.├/└; the working row shows a spinner at the right edge and the unread row a dot, both with the metric cluster hidden. The working opener keeps its chevron and shows its spinner at the right.Verified in Storybook:
Components/SessionList→Opened Sessions (MCP),· Light, and· Active opener(light and dark), which already cover aworking child, an unread child, an orphan, and a child-tab opener.
Test plan
pnpm --filter @lody/components test— 436 files / 3198 tests pass.pnpm typecheck(workspace) andpnpm check:quick(lint, i18n,code-collab imports, platform boundaries, public boundary) pass.
pnpm format.one, rather than deleting them:
session-list-opened-by.test.ts: connectors survive on working /unread children; the disclosure survives on a working, unread, or
waiting opener; status renders in the end slot; and a new case pins
that the diff numbers yield to a status.
sidebar-updated-opened-by.test.tsx: same guarantee for the Updatedbucket.
loro-app-sidebar-worktree.test.ts: the PR icon needs a READ row now,plus a new unread row asserting the icon yields to the status mark.
spinner-rotates-in-place.test.tsx/session-list-pr-badge.test.ts:the spinner's square-box invariants now render through the end slot.
Not covered: no e2e run; the mobile chat lists are untouched.
Context handoff
Instructions for reviewing agents
sidebar-row-shared.tsx—SessionRowLeadingSlotno longer takes the three status flags andSidebarRowEndSlotnow owns them; confirm all five row renderers pass them to the end slot and none still passes them to the leading slot.sessionHasUnreadMessageswith nolastReadAt), that can be many rows at once. This was the user's explicit call over the narrower "hide only the diff numbers" option.Authoring context
lib/session-opened-by-tree.ts), to the two opened-by fields, to keyboard navigation, or to the mobile chat lists.ConversationRowkeeps status on its leading node, because that slot also hosts the selection checkbox and its chevron must lift above the edge-back swipe zone — a separate change with its own screenshots. No e2e run.