fix: show Resume button for features stuck in pipeline steps

Enable the Resume button to appear for features with pipeline status
(e.g., 'pipeline_step_xyz') in addition to 'in_progress' status.

Previously, features that crashed during pipeline execution would show
a 'testing' status badge but no Resume button, making it impossible to
resume them from the UI.

Changes:
- Update card-actions.tsx condition to include pipeline_ status check
- Resume button now shows for both in_progress and pipeline_step_* statuses
- Maintains all existing behavior for other feature states

This fixes the UX issue where users could see a feature was stuck in a
pipeline step but had no way to resume it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Stephan Rieche
2026-01-02 13:22:11 +01:00
parent 2d309f6833
commit 2a87d55519

View File

@@ -109,88 +109,90 @@ export function CardActions({
)} )}
</> </>
)} )}
{!isCurrentAutoTask && feature.status === 'in_progress' && ( {!isCurrentAutoTask &&
<> (feature.status === 'in_progress' ||
{/* Approve Plan button - shows when plan is generated and waiting for approval */} (typeof feature.status === 'string' && feature.status.startsWith('pipeline_'))) && (
{feature.planSpec?.status === 'generated' && onApprovePlan && ( <>
<Button {/* Approve Plan button - shows when plan is generated and waiting for approval */}
variant="default" {feature.planSpec?.status === 'generated' && onApprovePlan && (
size="sm" <Button
className="flex-1 h-7 text-[11px] bg-purple-600 hover:bg-purple-700 text-white animate-pulse" variant="default"
onClick={(e) => { size="sm"
e.stopPropagation(); className="flex-1 h-7 text-[11px] bg-purple-600 hover:bg-purple-700 text-white animate-pulse"
onApprovePlan(); onClick={(e) => {
}} e.stopPropagation();
onPointerDown={(e) => e.stopPropagation()} onApprovePlan();
data-testid={`approve-plan-${feature.id}`} }}
> onPointerDown={(e) => e.stopPropagation()}
<FileText className="w-3 h-3 mr-1" /> data-testid={`approve-plan-${feature.id}`}
Approve Plan >
</Button> <FileText className="w-3 h-3 mr-1" />
)} Approve Plan
{feature.skipTests && onManualVerify ? ( </Button>
<Button )}
variant="default" {feature.skipTests && onManualVerify ? (
size="sm" <Button
className="flex-1 h-7 text-[11px]" variant="default"
onClick={(e) => { size="sm"
e.stopPropagation(); className="flex-1 h-7 text-[11px]"
onManualVerify(); onClick={(e) => {
}} e.stopPropagation();
onPointerDown={(e) => e.stopPropagation()} onManualVerify();
data-testid={`manual-verify-${feature.id}`} }}
> onPointerDown={(e) => e.stopPropagation()}
<CheckCircle2 className="w-3 h-3 mr-1" /> data-testid={`manual-verify-${feature.id}`}
Verify >
</Button> <CheckCircle2 className="w-3 h-3 mr-1" />
) : hasContext && onResume ? ( Verify
<Button </Button>
variant="default" ) : hasContext && onResume ? (
size="sm" <Button
className="flex-1 h-7 text-[11px] bg-[var(--status-success)] hover:bg-[var(--status-success)]/90" variant="default"
onClick={(e) => { size="sm"
e.stopPropagation(); className="flex-1 h-7 text-[11px] bg-[var(--status-success)] hover:bg-[var(--status-success)]/90"
onResume(); onClick={(e) => {
}} e.stopPropagation();
onPointerDown={(e) => e.stopPropagation()} onResume();
data-testid={`resume-feature-${feature.id}`} }}
> onPointerDown={(e) => e.stopPropagation()}
<RotateCcw className="w-3 h-3 mr-1" /> data-testid={`resume-feature-${feature.id}`}
Resume >
</Button> <RotateCcw className="w-3 h-3 mr-1" />
) : onVerify ? ( Resume
<Button </Button>
variant="default" ) : onVerify ? (
size="sm" <Button
className="flex-1 h-7 text-[11px] bg-[var(--status-success)] hover:bg-[var(--status-success)]/90" variant="default"
onClick={(e) => { size="sm"
e.stopPropagation(); className="flex-1 h-7 text-[11px] bg-[var(--status-success)] hover:bg-[var(--status-success)]/90"
onVerify(); onClick={(e) => {
}} e.stopPropagation();
onPointerDown={(e) => e.stopPropagation()} onVerify();
data-testid={`verify-feature-${feature.id}`} }}
> onPointerDown={(e) => e.stopPropagation()}
<PlayCircle className="w-3 h-3 mr-1" /> data-testid={`verify-feature-${feature.id}`}
Resume >
</Button> <PlayCircle className="w-3 h-3 mr-1" />
) : null} Resume
{onViewOutput && !feature.skipTests && ( </Button>
<Button ) : null}
variant="secondary" {onViewOutput && !feature.skipTests && (
size="sm" <Button
className="h-7 text-[11px] px-2" variant="secondary"
onClick={(e) => { size="sm"
e.stopPropagation(); className="h-7 text-[11px] px-2"
onViewOutput(); onClick={(e) => {
}} e.stopPropagation();
onPointerDown={(e) => e.stopPropagation()} onViewOutput();
data-testid={`view-output-inprogress-${feature.id}`} }}
> onPointerDown={(e) => e.stopPropagation()}
<FileText className="w-3 h-3" /> data-testid={`view-output-inprogress-${feature.id}`}
</Button> >
)} <FileText className="w-3 h-3" />
</> </Button>
)} )}
</>
)}
{!isCurrentAutoTask && feature.status === 'verified' && ( {!isCurrentAutoTask && feature.status === 'verified' && (
<> <>
{/* Logs button */} {/* Logs button */}