mirror of
https://github.com/stablyai/orca.git
synced 2026-10-15 08:03:08 +00:00
Share worktree status indicator UI
This commit is contained in:
@@ -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>
|
||||
|
||||
+5
-5
@@ -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')
|
||||
+1
-1
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user