feat(ST-1111.10d): show worker presence indicator and gate 'Voer uit' on connected workers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-29 19:14:00 +02:00
parent 5c226fb042
commit 95b5dd8430
4 changed files with 62 additions and 6 deletions

View file

@ -92,6 +92,7 @@ export function SoloBoard({
const { tasks, initTasks, optimisticMove, rollback, markPending, clearPending } = useSoloStore()
const realtimeStatus = useSoloStore((s) => s.realtimeStatus)
const showConnectingIndicator = useSoloStore((s) => s.showConnectingIndicator)
const connectedWorkers = useSoloStore((s) => s.connectedWorkers)
const [activeDragId, setActiveDragId] = useState<string | null>(null)
const [selectedTask, setSelectedTask] = useState<SoloTask | null>(null)
const [sheetOpen, setSheetOpen] = useState(false)
@ -192,6 +193,13 @@ export function SoloBoard({
status={realtimeStatus}
showConnectingIndicator={showConnectingIndicator}
/>
<div className="flex items-center gap-1 text-xs text-muted-foreground ml-1">
<span className={cn(
'size-2 rounded-full',
connectedWorkers > 0 ? 'bg-status-done' : 'bg-muted-foreground/40'
)} />
{connectedWorkers > 0 ? 'Agent verbonden' : 'Geen agent'}
</div>
</div>
{sprintGoal && (
<p className="text-sm text-muted-foreground mt-0.5 line-clamp-2">{sprintGoal}</p>

View file

@ -8,6 +8,7 @@ import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Textarea } from '@/components/ui/textarea'
import { DemoTooltip } from '@/components/shared/demo-tooltip'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import { useSoloStore } from '@/stores/solo-store'
import { enqueueClaudeJobAction, cancelClaudeJobAction } from '@/actions/claude-jobs'
import { cn } from '@/lib/utils'
@ -46,6 +47,7 @@ type SaveState = 'idle' | 'saving' | 'saved'
function TaskDetailContent({ task, productId, isDemo, onClose }: TaskDetailContentProps) {
const { updatePlan } = useSoloStore()
const job = useSoloStore(s => s.claudeJobsByTaskId[task.id])
const connectedWorkers = useSoloStore(s => s.connectedWorkers)
const [localPlan, setLocalPlan] = useState(task.implementation_plan ?? '')
const [saveState, setSaveState] = useState<SaveState>('idle')
const [, startTransition] = useTransition()
@ -166,9 +168,27 @@ function TaskDetailContent({ task, productId, isDemo, onClose }: TaskDetailConte
</Link>
{!isDemo && !job && (
<Button size="sm" className="h-7 text-xs" onClick={handleEnqueue} disabled={jobPending}>
Voer uit
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger
render={
<Button
size="sm"
className="h-7 text-xs"
onClick={handleEnqueue}
disabled={jobPending || connectedWorkers === 0}
>
Voer uit
</Button>
}
/>
{connectedWorkers === 0 && (
<TooltipContent side="top" className="max-w-xs text-xs">
Geen Claude Code-sessie verbonden. Start claude lokaal en zeg &apos;wacht op jobs&apos;.
</TooltipContent>
)}
</Tooltip>
</TooltipProvider>
)}
{job?.status === 'queued' && (