feat(tests): review panels, blind visibility UX, red_review/blue_review badges
This commit is contained in:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user