Files
roboco/panel/src/components/tasks/task-detail/tab-overview.tsx
T
a5d8c6bd5b feat(video): CEO can preview a video authoring task's frames before approving (#608)
A source=video authoring task reaches awaiting_ceo_approval with no MP4
yet — rendering only happens after it completes — so the CEO had nothing
to review. Two CEO-gated routes now serve the request_render preview
frames: GET /video/preview-frames/{task_id} lists them per orientation
(parsed from the self-describing .previews/{task8}/{orientation}/ filenames
rather than the render_preview marker, which only holds the last call's
single orientation), and .../{orientation}/{filename} streams a frame's
PNG behind the existing path-confinement guard. The task-detail Overview
gains a Video preview card — a 9:16/1:1 toggle + prev/next/scrubber frame
stepper with composition id, duration, and a dirty badge — shown for a
video task with preview frames or awaiting CEO approval.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-20 10:51:43 +02:00

124 lines
4.3 KiB
TypeScript

"use client";
import { Task, TaskStatus } from "@/types";
import { TaskDescription } from "./task-description";
import { AcceptanceCriteria } from "./acceptance-criteria";
import { SubtasksList } from "./subtasks-list";
import { WorkSessionCard } from "./work-session-card";
import { VideoPreviewCard } from "./video-preview-card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Markdown } from "@/components/ui/markdown";
import { HelpTip } from "@/components/ui/help-tip";
import Link from "next/link";
interface TabOverviewProps {
task: Task;
}
export function TabOverview({ task }: TabOverviewProps) {
return (
<div className="space-y-6">
{/* Parent Task Link */}
{task.parent_task_id && (
<Card className="bg-muted/30">
<CardContent className="py-3">
<div className="flex items-center gap-2 text-sm">
<span className="text-muted-foreground">Subtask of:</span>
<HelpTip label={task.parent_task_id}>
<Link
prefetch={false}
href={`/tasks/${task.parent_task_id}`}
className="text-primary hover:underline font-medium"
>
Parent Task #{task.parent_task_id.slice(0, 8)}
</Link>
</HelpTip>
</div>
</CardContent>
</Card>
)}
{/* Description */}
<TaskDescription task={task} />
{/* Acceptance Criteria */}
<AcceptanceCriteria task={task} />
{/* Subtasks */}
<SubtasksList task={task} />
{/* Work Session / Git Info */}
<WorkSessionCard taskId={task.id} />
{/* Video preview (source=video authoring tasks with a captured
render_preview, or already awaiting the CEO's approval — the state
with nothing else to show) */}
{task.source === "video" &&
(!!task.orchestration_markers?.render_preview ||
task.status === TaskStatus.AWAITING_CEO_APPROVAL) && (
<VideoPreviewCard task={task} />
)}
{/* Quick Context (for resumption) */}
{task.quick_context && (
<Card>
<CardHeader>
<HelpTip label="Short notes for resuming work after an interruption — mirrored on the Notes tab">
<CardTitle className="text-lg w-fit">Quick Context</CardTitle>
</HelpTip>
</CardHeader>
<CardContent>
<Markdown className="text-sm">{task.quick_context}</Markdown>
</CardContent>
</Card>
)}
{/* Verification Status */}
<Card>
<CardHeader>
<HelpTip label="Two independent checks: the developer's self-verification, then QA's separate review">
<CardTitle className="text-lg w-fit">Verification Status</CardTitle>
</HelpTip>
</CardHeader>
<CardContent>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">
Self Verified:
</span>
<HelpTip label="The developer confirmed they tested their own work before requesting QA review">
<Badge variant={task.self_verified ? "default" : "secondary"}>
{task.self_verified ? "Yes" : "No"}
</Badge>
</HelpTip>
</div>
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">
QA Verified:
</span>
<HelpTip label="Whether QA reviewed this task: Passed, Failed (back to needs_revision), or Pending (not reviewed yet)">
<Badge
variant={
task.qa_verified === true
? "default"
: task.qa_verified === false
? "destructive"
: "secondary"
}
>
{task.qa_verified === true
? "Passed"
: task.qa_verified === false
? "Failed"
: "Pending"}
</Badge>
</HelpTip>
</div>
</div>
</CardContent>
</Card>
</div>
);
}