feat(tests): review panels, blind visibility UX, red_review/blue_review badges

This commit is contained in:
kitos
2026-07-06 12:02:14 +02:00
parent 82033b5037
commit d5e3df00f9
11 changed files with 449 additions and 11 deletions
@@ -26,7 +26,9 @@ import LiveTimer from "./LiveTimer";
const PROGRESS_STEPS: { key: TestState; label: string }[] = [
{ key: "draft", label: "Draft" },
{ key: "red_executing", label: "Red Exec" },
{ key: "red_review", label: "Red Review" },
{ key: "blue_evaluating", label: "Blue Eval" },
{ key: "blue_review", label: "Blue Review" },
{ key: "in_review", label: "Review" },
{ key: "validated", label: "Validated" },
];
@@ -34,11 +36,13 @@ const PROGRESS_STEPS: { key: TestState; label: string }[] = [
const STATE_INDEX: Record<TestState, number> = {
draft: 0,
red_executing: 1,
blue_evaluating: 2,
in_review: 3,
validated: 4,
red_review: 2,
blue_evaluating: 3,
blue_review: 4,
in_review: 5,
validated: 6,
rejected: -1,
disputed: 3, // same step as in_review (still in validation phase)
disputed: 5, // same step as in_review (still in validation phase)
};
// ── Badge colors ───────────────────────────────────────────────────
@@ -46,13 +50,23 @@ const STATE_INDEX: Record<TestState, number> = {
const STATE_BADGE: Record<TestState, string> = {
draft: "bg-gray-800/50 text-gray-400 border-gray-600/30",
red_executing: "bg-orange-900/50 text-orange-400 border-orange-500/30",
red_review: "bg-amber-900/50 text-amber-400 border-amber-500/30",
blue_evaluating: "bg-indigo-900/50 text-indigo-400 border-indigo-500/30",
blue_review: "bg-purple-900/50 text-purple-400 border-purple-500/30",
in_review: "bg-blue-900/50 text-blue-400 border-blue-500/30",
validated: "bg-green-900/50 text-green-400 border-green-500/30",
rejected: "bg-red-900/50 text-red-400 border-red-500/30",
disputed: "bg-amber-900/50 text-amber-400 border-amber-500/30",
};
/** "Queued Blue Team" is a display-only label for blue_evaluating + unassigned. */
function getStateLabel(test: Test): string {
if (test.state === "blue_evaluating" && !test.blue_work_started_at) {
return "Queued Blue Team";
}
return test.state.replace(/_/g, " ");
}
// ── Props ──────────────────────────────────────────────────────────
interface TestDetailHeaderProps {
@@ -64,6 +78,7 @@ interface TestDetailHeaderProps {
onSubmitBlue: () => void;
onStartBlueWork: () => void;
onOpenValidateModal: (side: "red" | "blue") => void;
onOpenReviewModal: (side: "red" | "blue") => void;
onReopen: () => void;
onPauseTimer: () => void;
onResumeTimer: () => void;
@@ -84,6 +99,7 @@ export default function TestDetailHeader({
onSubmitBlue,
onStartBlueWork,
onOpenValidateModal,
onOpenReviewModal,
onReopen,
onPauseTimer,
onResumeTimer,
@@ -190,6 +206,40 @@ export default function TestDetailHeader({
);
}
// Red Lead assigned to review this submission -> Review Red Submission
if (
test.state === "red_review" &&
(role === "admin" || (role === "red_lead" && test.red_reviewer_assignee === user?.id))
) {
buttons.push(
<button
key="review-red"
onClick={() => onOpenReviewModal("red")}
className="flex items-center gap-1.5 rounded-lg bg-amber-600 px-4 py-2 text-sm font-medium text-white hover:bg-amber-500 transition-colors"
>
<Shield className="h-4 w-4" />
Review Red Submission
</button>,
);
}
// Blue Lead assigned to review this submission -> Review Blue Submission
if (
test.state === "blue_review" &&
(role === "admin" || (role === "blue_lead" && test.blue_reviewer_assignee === user?.id))
) {
buttons.push(
<button
key="review-blue"
onClick={() => onOpenReviewModal("blue")}
className="flex items-center gap-1.5 rounded-lg bg-purple-600 px-4 py-2 text-sm font-medium text-white hover:bg-purple-500 transition-colors"
>
<ShieldCheck className="h-4 w-4" />
Review Blue Submission
</button>,
);
}
// Blue Team in blue_evaluating:
// - if not picked up yet: show "Start Evaluation" button
// - if already picked up: show "Submit for Review" button
@@ -472,7 +522,7 @@ export default function TestDetailHeader({
STATE_BADGE[test.state]
}`}
>
{test.state.replace(/_/g, " ")}
{getStateLabel(test)}
</span>
</div>
<p className="mt-1 text-sm text-gray-400">