Share worktree status indicator UI

This commit is contained in:
brennanb2025
2026-05-17 22:43:26 -07:00
parent 7e9cec1c32
commit bb5683d9d4
5 changed files with 12 additions and 23 deletions
@@ -5,13 +5,11 @@ import { Badge } from '@/components/ui/badge'
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { activateAndRevealWorktree } from '@/lib/worktree-activation'
import { getWorktreeStatusLabel } from '@/lib/worktree-status'
import { cn } from '@/lib/utils'
import type { Repo, Worktree } from '../../../../shared/types'
import StatusIndicator from './StatusIndicator'
import WorktreeCard from './WorktreeCard'
import { WorktreeActivityStatusIndicator } from './WorktreeActivityStatusIndicator'
import WorktreeContextMenu from './WorktreeContextMenu'
import { useWorktreeActivityStatus } from './use-worktree-activity-status'
import { writeWorkspaceDragData } from './workspace-status'
type WorkspaceKanbanCardProps = {
@@ -108,7 +106,6 @@ function WorkspaceKanbanCompactCard({
}: Omit<WorkspaceKanbanCardProps, 'compact'>): React.JSX.Element {
const deleteState = useAppStore((s) => s.deleteStateByWorktreeId[worktree.id])
const isDeleting = deleteState?.isDeleting ?? false
const status = useWorktreeActivityStatus(worktree.id)
const contextWorktrees = useMemo(
() =>
isSelected && selectedWorktrees && selectedWorktrees.length > 0
@@ -187,8 +184,7 @@ function WorkspaceKanbanCompactCard({
aria-label={`Open ${worktree.displayName}`}
aria-busy={isDeleting}
>
<StatusIndicator status={status} aria-hidden="true" className="mr-1" />
<span className="sr-only">{getWorktreeStatusLabel(status)}</span>
<WorktreeActivityStatusIndicator worktreeId={worktree.id} className="mr-1" />
<span className="min-w-0 flex-1 truncate">{worktree.displayName}</span>
{repo ? (
<Tooltip>
@@ -2,7 +2,7 @@ import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { WorktreeStatus } from '@/lib/worktree-status'
import { LineageChildStatusIndicator } from './LineageChildStatusIndicator'
import { WorktreeActivityStatusIndicator } from './WorktreeActivityStatusIndicator'
const mocks = vi.hoisted(() => ({
status: 'inactive' as WorktreeStatus
@@ -15,16 +15,16 @@ vi.mock('./use-worktree-activity-status', () => ({
function renderMarkup(status: WorktreeStatus): string {
mocks.status = status
return renderToStaticMarkup(
React.createElement(LineageChildStatusIndicator, { worktreeId: 'wt-child' })
React.createElement(WorktreeActivityStatusIndicator, { worktreeId: 'wt-child' })
)
}
describe('LineageChildStatusIndicator', () => {
describe('WorktreeActivityStatusIndicator', () => {
beforeEach(() => {
mocks.status = 'inactive'
})
it('renders the shared inactive status for slept child previews', () => {
it('renders the shared inactive status for slept worktrees', () => {
const markup = renderMarkup('inactive')
expect(markup).toContain('Inactive')
@@ -32,7 +32,7 @@ describe('LineageChildStatusIndicator', () => {
expect(markup).not.toContain('bg-emerald-500')
})
it('renders the shared active status when the child workspace is live', () => {
it('renders the shared active status when the worktree is live', () => {
const markup = renderMarkup('active')
expect(markup).toContain('Active')
@@ -3,7 +3,7 @@ import { getWorktreeStatusLabel } from '@/lib/worktree-status'
import StatusIndicator from './StatusIndicator'
import { useWorktreeActivityStatus } from './use-worktree-activity-status'
export function LineageChildStatusIndicator({
export function WorktreeActivityStatusIndicator({
worktreeId,
className
}: {
@@ -15,14 +15,13 @@ import {
ServerOff,
Workflow
} from 'lucide-react'
import StatusIndicator from './StatusIndicator'
import CacheTimer from './CacheTimer'
import WorktreeContextMenu from './WorktreeContextMenu'
import { SshDisconnectedDialog } from './SshDisconnectedDialog'
import WorktreeCardAgents from './WorktreeCardAgents'
import { WorktreeActivityStatusIndicator } from './WorktreeActivityStatusIndicator'
import { cn } from '@/lib/utils'
import { activateAndRevealWorktree } from '@/lib/worktree-activation'
import { getWorktreeStatusLabel } from '@/lib/worktree-status'
import { getRepoKindLabel, isFolderRepo } from '../../../../shared/repo-kind'
import type { HostedReviewInfo } from '../../../../shared/hosted-review'
import type { Worktree, Repo, IssueInfo, LinearIssue } from '../../../../shared/types'
@@ -33,7 +32,6 @@ import {
hasWorktreeCardDetails
} from './WorktreeCardMeta'
import { writeWorkspaceDragData } from './workspace-status'
import { useWorktreeActivityStatus } from './use-worktree-activity-status'
import { getWorktreeCardPrDisplay } from './worktree-card-pr-display'
type WorktreeCardProps = {
@@ -212,8 +210,6 @@ const WorktreeCard = React.memo(function WorktreeCard({
: null
const isDeleting = deleteState?.isDeleting ?? false
const status = useWorktreeActivityStatus(worktree.id)
const showPR = cardProps.includes('pr')
const showIssue = cardProps.includes('issue')
const showComment = cardProps.includes('comment')
@@ -431,10 +427,7 @@ const WorktreeCard = React.memo(function WorktreeCard({
{(cardProps.includes('status') || cardProps.includes('unread')) && (
<div className="flex flex-col items-center justify-start pt-[2px] gap-2 shrink-0">
{cardProps.includes('status') && (
<>
<StatusIndicator status={status} aria-hidden="true" />
<span className="sr-only">{getWorktreeStatusLabel(status)}</span>
</>
<WorktreeActivityStatusIndicator worktreeId={worktree.id} />
)}
{cardProps.includes('unread') && (
@@ -14,8 +14,8 @@ import {
} from '@/store/selectors'
import WorktreeCard from './WorktreeCard'
import WorktreeCardAgents from './WorktreeCardAgents'
import { LineageChildStatusIndicator } from './LineageChildStatusIndicator'
import { SshDisconnectedDialog } from './SshDisconnectedDialog'
import { WorktreeActivityStatusIndicator } from './WorktreeActivityStatusIndicator'
import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import {
@@ -1136,7 +1136,7 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp
onDoubleClick={(event) => event.stopPropagation()}
>
<span className="mt-[2px] flex w-4 shrink-0 justify-center pt-[2px]">
<LineageChildStatusIndicator worktreeId={child.worktree.id} />
<WorktreeActivityStatusIndicator worktreeId={child.worktree.id} />
</span>
<div className="min-w-0 flex-1">
<div className="truncate text-[12px] leading-tight text-foreground">