feat(panel): surface the PR-review gate on the kanban boards

The awaiting_pr_review status had no board home, so a task sitting in the
in-path PR-review gate was invisible on every kanban. Add a "PR Review"
column to the PM board (between In Docs and PM Review, matching the
lifecycle) and a dedicated "PR Review" tab — Awaiting Review -> Passed ->
Changes Requested — mirroring the QA board.
This commit is contained in:
Renn F
2026-06-20 20:08:34 +02:00
parent a71bd723f8
commit af5adf8c03
4 changed files with 44 additions and 3 deletions
+10 -3
View File
@@ -2,12 +2,12 @@
import { Suspense } from "react"; import { Suspense } from "react";
import { useSearchParams, useRouter } from "next/navigation"; import { useSearchParams, useRouter } from "next/navigation";
import { DevKanban, QaKanban, PmKanban } from "@/components/kanban"; import { DevKanban, QaKanban, PrReviewKanban, PmKanban } from "@/components/kanban";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { Code, TestTube, ClipboardList } from "lucide-react"; import { Code, TestTube, GitPullRequest, ClipboardList } from "lucide-react";
type KanbanView = "dev" | "qa" | "pm"; type KanbanView = "dev" | "qa" | "pr-review" | "pm";
function KanbanPageContent() { function KanbanPageContent() {
const router = useRouter(); const router = useRouter();
@@ -36,6 +36,10 @@ function KanbanPageContent() {
<TestTube className="h-4 w-4" /> <TestTube className="h-4 w-4" />
QA QA
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="pr-review" className="gap-2">
<GitPullRequest className="h-4 w-4" />
PR Review
</TabsTrigger>
<TabsTrigger value="pm" className="gap-2"> <TabsTrigger value="pm" className="gap-2">
<ClipboardList className="h-4 w-4" /> <ClipboardList className="h-4 w-4" />
PM PM
@@ -48,6 +52,9 @@ function KanbanPageContent() {
<TabsContent value="qa" className="mt-6"> <TabsContent value="qa" className="mt-6">
<QaKanban /> <QaKanban />
</TabsContent> </TabsContent>
<TabsContent value="pr-review" className="mt-6">
<PrReviewKanban />
</TabsContent>
<TabsContent value="pm" className="mt-6"> <TabsContent value="pm" className="mt-6">
<PmKanban /> <PmKanban />
</TabsContent> </TabsContent>
+1
View File
@@ -6,6 +6,7 @@ export { KanbanCard } from "./core/kanban-card";
// Views // Views
export { DevKanban } from "./views/dev-kanban"; export { DevKanban } from "./views/dev-kanban";
export { QaKanban } from "./views/qa-kanban"; export { QaKanban } from "./views/qa-kanban";
export { PrReviewKanban } from "./views/pr-review-kanban";
export { PmKanban } from "./views/pm-kanban"; export { PmKanban } from "./views/pm-kanban";
// Shared // Shared
@@ -20,6 +20,7 @@ const PM_COLUMNS = [
{ id: "qa", status: TaskStatus.AWAITING_QA, title: "In QA", color: "bg-yellow-50 dark:bg-yellow-950" }, { id: "qa", status: TaskStatus.AWAITING_QA, title: "In QA", color: "bg-yellow-50 dark:bg-yellow-950" },
{ id: "needs-revision", status: TaskStatus.NEEDS_REVISION, title: "Needs Revision", color: "bg-rose-50 dark:bg-rose-950" }, { id: "needs-revision", status: TaskStatus.NEEDS_REVISION, title: "Needs Revision", color: "bg-rose-50 dark:bg-rose-950" },
{ id: "docs", status: TaskStatus.AWAITING_DOCUMENTATION, title: "In Docs", color: "bg-purple-50 dark:bg-purple-950" }, { id: "docs", status: TaskStatus.AWAITING_DOCUMENTATION, title: "In Docs", color: "bg-purple-50 dark:bg-purple-950" },
{ id: "pr-review", status: TaskStatus.AWAITING_PR_REVIEW, title: "PR Review", color: "bg-teal-50 dark:bg-teal-950" },
{ id: "pm-review", status: TaskStatus.AWAITING_PM_REVIEW, title: "PM Review", color: "bg-orange-50 dark:bg-orange-950" }, { id: "pm-review", status: TaskStatus.AWAITING_PM_REVIEW, title: "PM Review", color: "bg-orange-50 dark:bg-orange-950" },
{ id: "ceo-approval", status: TaskStatus.AWAITING_CEO_APPROVAL, title: "CEO Approval", color: "bg-indigo-50 dark:bg-indigo-950" }, { id: "ceo-approval", status: TaskStatus.AWAITING_CEO_APPROVAL, title: "CEO Approval", color: "bg-indigo-50 dark:bg-indigo-950" },
{ id: "done", status: TaskStatus.COMPLETED, title: "Done", color: "bg-green-50 dark:bg-green-950" }, { id: "done", status: TaskStatus.COMPLETED, title: "Done", color: "bg-green-50 dark:bg-green-950" },
@@ -0,0 +1,32 @@
"use client";
import { useState } from "react";
import { TaskStatus, Team } from "@/types";
import { KanbanBoard } from "../core/kanban-board";
// The in-path PR-review gate: a reviewer checks each assembled cell->root /
// root->master PR before the PM merges. A card sits in "Awaiting Review" until
// a reviewer pr_passes it on to PM Review or pr_fails it back for changes.
const PR_REVIEW_COLUMNS = [
{ id: "awaiting", status: TaskStatus.AWAITING_PR_REVIEW, title: "Awaiting Review", color: "bg-teal-100 dark:bg-teal-900" },
{ id: "passed", status: TaskStatus.AWAITING_PM_REVIEW, title: "Passed", color: "bg-green-50 dark:bg-green-950" },
{ id: "changes", status: TaskStatus.NEEDS_REVISION, title: "Changes Requested", color: "bg-red-50 dark:bg-red-950" },
];
interface PrReviewKanbanProps {
initialTeam?: Team;
}
export function PrReviewKanban({ initialTeam }: PrReviewKanbanProps) {
const [team, setTeam] = useState<Team | undefined>(initialTeam);
return (
<KanbanBoard
title="PR Review Kanban"
description="In-path PR-review gate for assembled PRs"
columns={PR_REVIEW_COLUMNS}
teamFilter={team}
onTeamChange={(t) => setTeam(t === "all" ? undefined : t)}
/>
);
}