Skip to content

Make composer background-task rows clickable - #2402

Open
technicalpickles wants to merge 1 commit into
get-bb:mainfrom
technicalpickles:fix/composer-status-bar-click
Open

Make composer background-task rows clickable#2402
technicalpickles wants to merge 1 commit into
get-bb:mainfrom
technicalpickles:fix/composer-status-bar-click

Conversation

@technicalpickles

@technicalpickles technicalpickles commented Aug 25, 2026

Copy link
Copy Markdown

What was wrong

The composer's "Running background agent/command" status card rows had no click handler, unlike the main timeline's expandable delegation rows, so there was no way to jump to a background task's context from the card.

What changed

  • ThreadBackgroundCommandsCard.tsx: every row (the single non-expandable summary row and each row in the expanded list) is now a real button. On click, it scrolls to and flashes the row in the main timeline if it's already rendered there, or opens a bottom drawer with the row's own data otherwise.
  • The drawer path is the common one: a background task's row only stays in the main timeline while its spawning turn is still pending. Once that turn completes and gets summarized, the row survives only in the activeBackgroundCommands/activeWorkflows projection this card reads from, so there's nothing to scroll to.
  • The drawer tracks the row by id and re-derives it from commands on every render (falling back to the last known data once the row drops out of that list), so it reflects live task progress instead of freezing to whatever the row looked like at click time.
  • Extracted the scroll/flash DOM helpers shared with useScrollToSearchedMessage.ts into a new timelineRowNavigation.ts so both features use the same selector and flash-class logic instead of duplicating it.
  • Deviation from the issue: it proposed adding a timelineRowId back-reference field to TimelineWorkflowWorkRow, on the assumption the row carried no id back to its main-timeline counterpart. That assumption doesn't hold: row.id is already built via the same buildWorkflowWorkRow helper used for the row that eventually appears in the main timeline, so it's already the right id to look up. No schema change was needed.

How you verified

  • New tests in ThreadBackgroundCommandsCard.test.tsx cover both click paths (scroll+flash when rendered, drawer fallback when not), targeting the clicked row's own id when multiple rows are expanded, the header toggle staying navigation-free, and the drawer staying in sync with live row updates (including when the row disappears from commands entirely) instead of freezing to a stale snapshot.
  • pnpm exec turbo run test --filter=@bb/app and pnpm exec turbo run typecheck --filter=@bb/app.
  • Manually reproduced the bug against main first: spawned a real background task on a claude-code thread and confirmed the card row did nothing on click, and that no [data-timeline-row-id] element existed for it while it was running.
  • Verified the drawer path live against this branch's dev server: opened the drawer on a running task, confirmed it showed the correct live description, and confirmed it didn't go blank or error once the underlying task completed.
  • Could not verify the scroll-to-rendered-row path live. While investigating why, I found that for the claude-code provider, a backgrounded shell command's completion never projects into a workKind: "workflow" row in the main timeline at all (running or completed) -- it falls into a generic "Unhandled Claude Code event" operation row instead. That's #2224 (background_tasks_changed hits assertNever), a pre-existing gap this PR doesn't touch; I added the UI-side evidence there. The scroll path itself is still covered at the unit level, using the same data-timeline-row-id selector the app uses in production.

Fixes #2315

AGENT GENERATED

Rows in ThreadBackgroundCommandsCard were plain divs with no
onClick, unlike the main timeline's expandable delegation rows.
Clicking a row now scrolls to and flashes the corresponding row
in the main timeline if it's already rendered there (reusing the
search-jump convention from useScrollToSearchedMessage), or opens
a detail drawer with the row's own data otherwise -- the common
case, since a background task's row only stays in the main
timeline while its spawning turn is still pending; once that turn
completes and gets summarized, the row survives only in the
activeBackgroundCommands/activeWorkflows projection this card
reads from.

Extracted the shared scroll/flash DOM helpers into
timelineRowNavigation.ts so both the search-jump hook and this
card use the same selector and flash-class logic instead of
duplicating it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDNPjAxzyMPgPZx4ATgUsQ
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.

Composer's running-agents status bar isn't clickable, unlike the main timeline

1 participant