From 885f803adb8b60fca6400a67d5b5cc972fb647ab Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:34:12 -0700 Subject: [PATCH] refactor(dashboard): head the card with the session name, move the worktree beside the project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversation name now sits next to the agent icon as the card's heading rather than prefixing the user-message line, and the worktree drops to the footer beside the project icon. The message line reads "You" again — the name moved up, so keeping it there said the same thing twice. Cards without a resolvable session name keep the worktree as the heading, and the footer omits it rather than repeating it. --- .../dashboard-popout/AgentKanbanCard.test.tsx | 25 +++++++++++++---- .../dashboard-popout/AgentKanbanCard.tsx | 28 +++++++++---------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx b/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx index 1e15b588190..16739e15d99 100644 --- a/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx +++ b/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx @@ -127,19 +127,32 @@ describe('AgentKanbanCard', () => { expect(idleClassName).not.toContain('amber') }) - it('labels the user message with the conversation name, falling back to "You"', () => { - renderCard({ + it('heads the card with the conversation name and drops the worktree to the footer', () => { + const { container } = renderCard({ card: card({ lastUserMessage: 'ship it', conversationName: 'Sparse-checkout parser' }), now: 2_000 }) - expect(screen.getByText('Sparse-checkout parser')).toBeInTheDocument() - expect(screen.queryByText('You')).not.toBeInTheDocument() - cleanup() - renderCard({ card: card({ lastUserMessage: 'ship it' }), now: 2_000 }) + const [header, footer] = [ + container.querySelector('button')!.firstElementChild!, + container.querySelector('button')!.lastElementChild! + ] + expect(header).toHaveTextContent('Sparse-checkout parser') + expect(header).not.toHaveTextContent('dashboard-review') + expect(footer).toHaveTextContent('dashboard-review') + // The message line is attributed to the user again — the name moved up. expect(screen.getByText('You')).toBeInTheDocument() }) + it('heads the card with the worktree when no name resolves, without repeating it', () => { + const { container } = renderCard({ card: card({ lastUserMessage: 'ship it' }), now: 2_000 }) + + expect(screen.getAllByText('dashboard-review')).toHaveLength(1) + expect(container.querySelector('button')!.firstElementChild).toHaveTextContent( + 'dashboard-review' + ) + }) + it('shows the repo as an icon labelled with its name instead of inline text', () => { renderCard({ card: card(), diff --git a/src/renderer/src/components/dashboard-popout/AgentKanbanCard.tsx b/src/renderer/src/components/dashboard-popout/AgentKanbanCard.tsx index 54f72df28d7..97142a0b42e 100644 --- a/src/renderer/src/components/dashboard-popout/AgentKanbanCard.tsx +++ b/src/renderer/src/components/dashboard-popout/AgentKanbanCard.tsx @@ -105,6 +105,11 @@ export const AgentKanbanCard = memo( // neutral so the tint keeps meaning something. const needsYou = card.bucket === 'attention' const isDone = card.dotState === 'done' + // Why: the session's own name heads the card. Without one the worktree is + // the best heading left — and then the footer drops it rather than say it + // twice. + const heading = card.conversationName ?? card.worktreeName + const worktreeInFooter = card.conversationName !== undefined return (