feat(ST-1111.7): add job status pill with spinner on solo task cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-29 19:05:38 +02:00
parent b9c65eb145
commit dace4271a3
2 changed files with 45 additions and 4 deletions

View file

@ -0,0 +1,21 @@
import type { ClaudeJobStatusApi } from '@/lib/job-status'
export const JOB_STATUS_LABELS: Record<ClaudeJobStatusApi, string> = {
queued: 'Wacht…',
claimed: 'Geclaimd…',
running: 'Bezig…',
done: 'Klaar',
failed: 'Mislukt',
cancelled: 'Geannuleerd',
}
export const JOB_STATUS_COLORS: Record<ClaudeJobStatusApi, string> = {
queued: 'bg-status-todo/15 text-status-todo border-status-todo/30',
claimed: 'bg-status-in-progress/15 text-status-in-progress border-status-in-progress/30',
running: 'bg-status-in-progress/15 text-status-in-progress border-status-in-progress/30',
done: 'bg-status-done/15 text-status-done border-status-done/30',
failed: 'bg-status-blocked/15 text-status-blocked border-status-blocked/30',
cancelled: 'bg-muted text-muted-foreground border-border',
}
export const JOB_STATUS_ACTIVE = new Set<ClaudeJobStatusApi>(['queued', 'claimed', 'running'])

View file

@ -3,8 +3,11 @@
import type React from 'react'
import { useDraggable } from '@dnd-kit/core'
import { CSS } from '@dnd-kit/utilities'
import { Loader2 } from 'lucide-react'
import { cn } from '@/lib/utils'
import { CodeBadge } from '@/components/shared/code-badge'
import { JOB_STATUS_LABELS, JOB_STATUS_COLORS, JOB_STATUS_ACTIVE } from '@/components/shared/job-status'
import { useSoloStore } from '@/stores/solo-store'
import type { SoloTask } from './solo-board'
const PRIORITY_BORDER: Record<number, string> = {
@ -21,6 +24,7 @@ interface SoloTaskCardProps {
}
export function SoloTaskCard({ task, isDemo, onClick }: SoloTaskCardProps) {
const job = useSoloStore(s => s.claudeJobsByTaskId[task.id])
const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({
id: task.id,
disabled: isDemo,
@ -51,10 +55,26 @@ export function SoloTaskCard({ task, isDemo, onClick }: SoloTaskCardProps) {
<p className="text-sm text-foreground leading-snug flex-1">{task.title}</p>
{task.task_code && <CodeBadge code={task.task_code} className="shrink-0 mt-0.5" />}
</div>
<p className="text-xs text-muted-foreground mt-0.5 truncate">
{task.story_code && <span className="font-mono mr-1">{task.story_code}</span>}
{task.story_title}
</p>
<div className="flex items-center justify-between gap-2 mt-0.5">
<p className="text-xs text-muted-foreground truncate">
{task.story_code && <span className="font-mono mr-1">{task.story_code}</span>}
{task.story_title}
</p>
{job && (
<span
className={cn(
'text-[10px] px-1.5 py-0 rounded border flex items-center gap-1 shrink-0',
JOB_STATUS_COLORS[job.status],
)}
onClick={(e) => { e.stopPropagation(); onClick() }}
role="button"
aria-label={`Agent-status: ${JOB_STATUS_LABELS[job.status]}`}
>
{JOB_STATUS_ACTIVE.has(job.status) && <Loader2 className="animate-spin" size={8} />}
{JOB_STATUS_LABELS[job.status]}
</span>
)}
</div>
</div>
)
}